archie/prospero/lib/pfs/mkdirs.c
2024-05-27 16:13:40 +02:00

122 lines
3.4 KiB
C

/*
* Copyright (c) 1989, 1990, 1991 by the University of Washington
*
* For copying and distribution information, please see the file
* <uw-copyright.h>.
*/
#include <uw-copyright.h>
#include <sys/param.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <pmachine.h>
#include <pfs.h>
#include <perrno.h>
/*
* mkdirs - Make a directory and all superior directories
*
* MKDIRS takes a pathame for a directory, checks to see
* whether it exists, and if not creates it. Any parent
* directories which do not exist will be created as
* well.
*
* ARGS: path - path of the directoriy to be created
*
* RETURNS: 0 on success
* the contents of errno on error
*/
/*
* I've mutilated this file because most calls I found where having to
* go through the effort of making a string for the directory name
* from a file
*
* The old version also had a bug (though I found it through looking at
* the code, not from experience, and a number of non-standards etc
* Specifically:
* if errno was non-zero on entry, and the directory exists, then
* the code would find stat==0, it was a directory, tmp is zero,
* and it would return the errno (or even fail to recreate the directory)
* it should return immediately if the directory exists
*
* rindex is not POSIX
*
* it uses MAXPATHLEN, also non-POSIX
*
* the headers in here, conflicted with those in pfs.h
*/
#define RETURN(r1) { retval=r1 ; goto cleanup; }
/* Argument should be TRUE if one should not strip off the trailing suffix,
* false if one does need to strip off the trailing suffix.
*/
int
p__mkdirs(const char path[], int wantdir)
{
char *prefix = NULL;
char *suffix; /* Pointer into prefix */
struct stat st;
int mode = 0777;
int retval = 0;
if (stat(path, &st) == 0) { /* exists, either dir. or file */
if (!wantdir)
return 0; /* File exists, so directory must */
if (wantdir && !S_ISDIR(st.st_mode))
return (EEXIST); /* already exists and is not dir. */
return 0; /* Directory exists */
}
if (!wantdir) { /* Want file, build parent directory */
prefix = stcopy(path);
if (!(suffix = strrchr(prefix, '/'))) {
RETURN(PSUCCESS); /* No directory to build - thats ok*/
} else {
*suffix = '\0';
RETURN(p__mkdirs(prefix, 1)) ; /* Recurse on directory*/
}
} else { /*wantdir*/
/* If want directory, but specified trailing slash*/
if (path[strlen(path)-1] == '/') {
prefix = stcopy(path);
prefix[strlen(prefix)-1] = '\0';
RETURN(p__mkdirs(prefix, 1)); /*recurse without /*/
}
if (!mkdir(path, mode)) {
chmod(path, mode);
RETURN(0);
}
switch (errno) {
case ENOENT: /* Failed because no parent, recurse for it */
prefix = stcopy(path);
if (suffix = strrchr(prefix, '/'))
*suffix = '\0';
else
*prefix = '\0';
assert(*prefix != '\0'); /* Is no parent, strange */
if (retval = p__mkdirs(prefix, TRUE))
RETURN(retval); /* Recurse on parent */
RETURN(p__mkdirs(path,TRUE)); /* Recurse on self */
case EEXIST: /* Someone else created it for us */
RETURN(PSUCCESS);
default: /* mkdir failed for some other reason */
p_err_string = qsprintf_stcopyr(p_err_string,
"Couldnt create %s: %s", path, unixerrstr());
RETURN(errno);
}
} /*wantdir*/
cleanup:
stfree(prefix);
return(retval);
}
/* back compatibility*/
int
mkdirs(const char *path)
{
return p__mkdirs(path, 1);
}