#include <sys_defs.h>
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "msg.h"
#include "mymalloc.h"
#include "stringops.h"
#include "make_dirs.h"
#include "warn_stat.h"
int make_dirs(const char *path, int perms)
{
const char *myname = "make_dirs";
char *saved_path;
unsigned char *cp;
int saved_ch;
struct stat st;
int ret;
mode_t saved_mode = 0;
gid_t egid = -1;
cp = (unsigned char *) (saved_path = mystrdup(path));
#define SKIP_WHILE(cond, ptr) { while(*ptr && (cond)) ptr++; }
SKIP_WHILE(*cp == '/', cp);
for (;;) {
SKIP_WHILE(*cp != '/', cp);
if ((saved_ch = *cp) != 0)
*cp = 0;
if ((ret = stat(saved_path, &st)) >= 0) {
if (!S_ISDIR(st.st_mode)) {
errno = ENOTDIR;
ret = -1;
break;
}
saved_mode = st.st_mode;
} else {
if (errno != ENOENT)
break;
#if 0
if (saved_mode & S_IWOTH) {
msg_warn("refusing to mkdir %s: parent directory is writable by everyone",
saved_path);
errno = EPERM;
ret = -1;
break;
}
#endif
if ((ret = mkdir(saved_path, perms)) < 0) {
if (errno != EEXIST)
break;
if ((ret = stat(saved_path, &st)) < 0)
break;
if (!S_ISDIR(st.st_mode)) {
errno = ENOTDIR;
ret = -1;
break;
}
}
if ((ret = stat(saved_path, &st)) < 0) {
msg_warn("%s: stat %s: %m", myname, saved_path);
break;
}
if (egid == -1)
egid = getegid();
if (st.st_gid != egid && (ret = chown(saved_path, -1, egid)) < 0) {
msg_warn("%s: chgrp %s: %m", myname, saved_path);
break;
}
}
if (saved_ch != 0)
*cp = saved_ch;
SKIP_WHILE(*cp == '/', cp);
if (*cp == 0)
break;
}
myfree(saved_path);
return (ret);
}
#ifdef TEST
#include <stdlib.h>
#include <msg_vstream.h>
int main(int argc, char **argv)
{
msg_vstream_init(argv[0], VSTREAM_ERR);
if (argc < 2)
msg_fatal("usage: %s path...", argv[0]);
while (--argc > 0 && *++argv != 0)
if (make_dirs(*argv, 0755))
msg_fatal("%s: %m", *argv);
exit(0);
}
#endif