7 /* create directory hierarchy
9 /* #include <make_dirs.h>
11 /* int make_dirs(path, perms)
15 /* make_dirs() creates the directory specified in \fIpath\fR, and
16 /* creates any missing intermediate directories as well. Directories
17 /* are created with the permissions specified in \fIperms\fR, as
18 /* modified by the process umask.
20 /* Fatal: out of memory. make_dirs() returns 0 in case of success.
21 /* In case of problems. make_dirs() returns -1 and \fIerrno\fR
22 /* reflects the nature of the problem.
28 /* The Secure Mailer license must be distributed with this software.
31 /* IBM T.J. Watson Research
33 /* Yorktown Heights, NY 10598, USA
43 /* Utility library. */
47 #include "stringops.h"
48 #include "make_dirs.h"
50 /* make_dirs - create directory hierarchy */
52 int make_dirs(const char *path
, int perms
)
59 mode_t saved_mode
= 0;
62 * Initialize. Make a copy of the path that we can safely clobber.
64 cp
= (unsigned char *) (saved_path
= mystrdup(path
));
67 * I didn't like the 4.4BSD "mkdir -p" implementation, but coming up with
68 * my own took a day, spread out over several days.
70 #define SKIP_WHILE(cond, ptr) { while(*ptr && (cond)) ptr++; }
72 SKIP_WHILE(*cp
== '/', cp
);
75 SKIP_WHILE(*cp
!= '/', cp
);
76 if ((saved_ch
= *cp
) != 0)
78 if ((ret
= stat(saved_path
, &st
)) >= 0) {
79 if (!S_ISDIR(st
.st_mode
)) {
84 saved_mode
= st
.st_mode
;
90 * mkdir(foo) fails with EEXIST if foo is a symlink.
95 * Create a new directory. Unfortunately, mkdir(2) has no
96 * equivalent of open(2)'s O_CREAT|O_EXCL safety net, so we must
97 * require that the parent directory is not world writable.
98 * Detecting a lost race condition after the fact is not
99 * sufficient, as an attacker could repeat the attack and add one
100 * directory level at a time.
102 if (saved_mode
& S_IWOTH
) {
103 msg_warn("refusing to mkdir %s: parent directory is writable by everyone",
110 if ((ret
= mkdir(saved_path
, perms
)) < 0) {
113 /* Race condition? */
114 if ((ret
= stat(saved_path
, &st
)) < 0)
116 if (!S_ISDIR(st
.st_mode
)) {
125 SKIP_WHILE(*cp
== '/', cp
);
140 * Test program. Usage: make_dirs path...
143 #include <msg_vstream.h>
145 int main(int argc
, char **argv
)
147 msg_vstream_init(argv
[0], VSTREAM_ERR
);
149 msg_fatal("usage: %s path...", argv
[0]);
150 while (--argc
> 0 && *++argv
!= 0)
151 if (make_dirs(*argv
, 0755))
152 msg_fatal("%s: %m", *argv
);