Add zlib
[git/pclouds.git] / box / libbb / make_directory.c
blobb8470f4b0ab72dd417d7555aacabcc14908f146e
1 /* vi: set sw=4 ts=4: */
2 /*
3 * parse_mode implementation for busybox
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
10 /* Mar 5, 2003 Manuel Novoa III
12 * This is the main work function for the 'mkdir' applet. As such, it
13 * strives to be SUSv3 compliant in it's behaviour when recursively
14 * making missing parent dirs, and in it's mode setting of the final
15 * directory 'path'.
17 * To recursively build all missing intermediate directories, make
18 * sure that (flags & FILEUTILS_RECUR) is non-zero. Newly created
19 * intermediate directories will have at least u+wx perms.
21 * To set specific permissions on 'path', pass the appropriate 'mode'
22 * val. Otherwise, pass -1 to get default permissions.
25 #include "libbb.h"
27 /* This function is used from NOFORK applets. It must not allocate anything */
29 int bb_make_directory (char *path, long mode, int flags)
31 mode_t mask;
32 const char *fail_msg;
33 char *s = path,*s2;
34 char c;
35 struct stat st;
37 mask = umask(0);
38 if (mode == -1) {
39 umask(mask);
40 mode = (S_IXUSR | S_IXGRP | S_IXOTH |
41 S_IWUSR | S_IWGRP | S_IWOTH |
42 S_IRUSR | S_IRGRP | S_IROTH) & ~mask;
43 } else {
44 umask(mask & ~0300);
47 do {
48 c = 0;
50 if (flags & FILEUTILS_RECUR) { /* Get the parent. */
51 #ifdef __MINGW32__
52 /* skip drive letter and initial slashes */
53 if (s == path && *s && s[1] == ':') {
54 s += 2;
55 while (*s == '/')
56 s++;
58 #endif
59 /* Bypass leading non-'/'s and then subsequent '/'s. */
60 while (*s) {
61 if (*s == '/') {
62 s2 = s;
63 c = *s2; /* Save the current char */
64 *s2 = 0; /* and replace it with nul. */
65 do {
66 ++s;
67 } while (*s == '/');
68 break;
70 ++s;
74 if (mkdir(path, 0777) < 0) {
75 /* If we failed for any other reason than the directory
76 * already exists, output a diagnostic and return -1.*/
77 if (errno != EEXIST
78 || !(flags & FILEUTILS_RECUR)
79 || (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))) {
80 fail_msg = "create";
81 umask(mask);
82 break;
84 /* Since the directory exists, don't attempt to change
85 * permissions if it was the full target. Note that
86 * this is not an error conditon. */
87 if (!c) {
88 umask(mask);
89 return 0;
93 if (!c) {
94 /* Done. If necessary, updated perms on the newly
95 * created directory. Failure to update here _is_
96 * an error.*/
97 umask(mask);
98 if ((mode != -1) && (chmod(path, mode) < 0)){
99 fail_msg = "set permissions of";
100 break;
102 return 0;
105 /* Remove any inserted nul from the path (recursive mode). */
106 *s2 = c;
108 } while (1);
110 bb_perror_msg ("cannot %s directory '%s'", fail_msg, path);
111 return -1;