/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*    mkdir [[-+][lup] dir...
*
* This is JC's version of the mkdir command.  It detects  problems  with  poor
* handling of the umask (by NFS, among others), and tries to correct them.  It
* also has options to modify the case of names, so we can do DOS- and VMS-like
* case-insensitivity.
*
* This  command  creates  one  or more directories.  They will be owned by the
* caller, who must have write permission in the existing (parent) directories.
*
* The options may start with '-' to suppress a feature, or with '+' to enable
* it.  The options are as follows.  At present, the default for each is "off",
* but this may change in the future.
*
* +l converts the first letter of each name to lower case.
*
* +L converts all letters of each name to lower case.
*
* +p creates parent directories as needed.
*
* +u converts the first letter of each name to upper case.
*
* +U converts all letters of each name to upper case.
*
*/
#include "V.h"
#include "sys_stat.h"

char m_cantmake[] = "%s: Can't %s \"%s\" [Err %d=%s]";
Flag mkpr = 0;	/* Make parent directories */
Flag tolc = 0;	/* Convert letters to lower case */
Flag touc = 0;	/* Convert letters to upper case */

main(ac,av)
	int  ac;
	char*av[];
{	int  a;
	int  c0, c1;
	int  err = 0;
	int  m, n, um;
	char*p;
	struct stat st;

	ac = Vinit(ac,av);	/* Init jc's debug package */

	um = umask(0);		/* Fetch the umask */
	V2 "umask was %03o",um D;
	m = (~um) & 0777;	/* Desired mode */
	umask(um);			/* Restore the umask (this is dumb :-) */
	V4 "mkpr=%d.",mkpr D;

	for (a=1; a<ac; a++) {	/* Run thru the command-line args */
		V4 "mkpr=%d.",mkpr D;
		switch (c0 = av[a][0]) {	/* Look for options */
		  case '-':
		  case '+':
			switch (c1 = av[a][1]) {
			  case 'D':
			  case 'd':		/* Debug option */
				Vopt(av[a]+2);
				break;
			  case 'L':		/* Lower-case everything */
				tolc = (c0 == '+') ? 2 : 0;
				break;
			  case 'l':		/* Lower-case first letters */
				tolc = (c0 == '+');
				break;
			  case 'P':
			  case 'p':		/* Make parent directory if necessary */
				mkpr = 1;
				V2 "Making parent directories." D;
				break;
			  case 'U':		/* Upper-case everything */
				touc = (c0 == '+') ? 2 : 0;
				break;
			  case 'u':		/* Upper-case first letters */
				touc = (c0 == '+');
				break;
			  default:
				V1 "Unknown option \"%s\" ignored.",av[a] D;
			}
			continue;
		}
		V4 "mkpr=%d.",mkpr D;
		while ((n = strlen(av[a])) && (n > 0) && (av[a][n-1] == '/')) {
			av[a][--n] = 0;		/* Strip off final '/' */
		}
		if (tolc) lcname(av[a]);
		if (touc) ucname(av[a]);
		if (mkdir(av[a],0777) < 0) {	/* Try to create the directory */
			P2 m_cantmake,pname,"Mkdir",av[a],Erreason D;
			switch (errno) {
			  case ENOENT:		/* Parent directory doesn't exist */
				V4 "mkpr=%d.",mkpr D;
				if (mkpr) {
					V3 "Make parent of \"%s\"",av[a] D;
					if (mkparent(av[a]) < 0) {
						 V1 "Failed to create parent directory of \"%s\" [Err %d=%s=%s]",
						 	av[a],Erreason D;
						 Fail;
					}
					V2 "Making \"%s\"",av[a] D;
					if (mkdir(av[a],0777) < 0) {
						 Fail;
					}
				}
				break;
			  default:
			  fail:
				P1 m_cantmake,pname,"create",av[a],Erreason D;
				++err;
				continue;
			}
		}
		if (stat(av[a],&st) < 0) {		/* Check its status */
			P1 m_cantmake,pname,"stat",av[a],Erreason D;
			err = errno;
			continue;
		}
		if (st.st_mode & 0x777 == m)	/* Does it have correct permissions? */
			continue;
		V2 "Wrong mode  %03o for \"%s\"",st.st_mode & ~S_IFDIR,av[a] D;
		if (chmod(av[a],m) < 0) {		/* Attempt to correct them */
			P1 m_cantmake,pname,"chmod",av[a],Erreason D;
			err = errno;
		}
		V5 "Chmod(\"%s\",%03o)\n", av[a],m D;
		V3 "Set mode to %03o for \"%s\"",m,av[a] D;
	}
	exit(err);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Given a pathname, make the parent directory.
*/
mkparent(name)
	char*name;
{	int  r = 0;
	char c, *p,*q;

	Fpush("mkparent");
	V4 "Making parent of \"%s\"",name D;
	for (p=q=name; c = *p; p++)
		if (c == '/')
			q = p;
	if (q == name || *q != '/') {
		V4 "Can't back up past \"%s\"",name D;
		Done;
	}
	*q = 0;
	mkparent(name);
	V2 "Making \"%s\"",name D;
	if (mkdir(name,0777) < 0) {
		switch (errno) {
		  default:
			P1 m_cantmake,pname,"mkdir",name,Erreason D;
			break;
		  case EEXIST:
			break;
		}
	}
	*q = '/';
fail:
done:
	Return(r);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Convert the pathname to lower case.
*/
lcname(path)
	char *path;
{	char *p;
	Flag  fldfl=1;
	int   c;
	Fname("lcname");
	for (p = path; p >= path && (c = *p); ++p) {
		if (c == '/') {
			fldfl = 1;
		} else {
			if (ISupper(c) && (fldfl || tolc>1)) {
				*p = tolower(c);
			}
			fldfl = 0;
		}
	}
	Return(0);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Convert the pathname to upper case.
*/
ucname(path)
	char *path;
{	char *p;
	Flag  fldfl=1;
	int   c;
	Fname("ucname");
	for (p = path; p >= path && (c = *p); ++p) {
		if (c == '/') {
			fldfl = 1;
		} else {
			if (islower(c) && (fldfl || touc>1)) {
				*p = toupper(c);
			}
			fldfl = 0;
		}
	}
	Return(0);
}
