diff options
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/make_directory.c | 63 |
1 files changed, 47 insertions, 16 deletions
diff --git a/libbb/make_directory.c b/libbb/make_directory.c index a4ad59975..4486eb1ed 100644 --- a/libbb/make_directory.c +++ b/libbb/make_directory.c | |||
@@ -28,53 +28,76 @@ | |||
28 | 28 | ||
29 | int FAST_FUNC bb_make_directory(char *path, long mode, int flags) | 29 | int FAST_FUNC bb_make_directory(char *path, long mode, int flags) |
30 | { | 30 | { |
31 | mode_t mask; | 31 | mode_t cur_mask; |
32 | mode_t org_mask; | ||
32 | const char *fail_msg; | 33 | const char *fail_msg; |
33 | char *s = path; | 34 | char *s; |
34 | char c; | 35 | char c; |
35 | struct stat st; | 36 | struct stat st; |
36 | 37 | ||
37 | mask = umask(0); | 38 | /* Happens on bb_make_directory(dirname("no_slashes"),...) */ |
38 | umask(mask & ~0300); /* Ensure intermediate dirs are wx */ | 39 | if (LONE_CHAR(path, '.')) |
40 | return 0; | ||
39 | 41 | ||
42 | org_mask = cur_mask = (mode_t)-1L; | ||
43 | s = path; | ||
40 | while (1) { | 44 | while (1) { |
41 | c = '\0'; | 45 | c = '\0'; |
42 | 46 | ||
43 | if (flags & FILEUTILS_RECUR) { /* Get the parent. */ | 47 | if (flags & FILEUTILS_RECUR) { /* Get the parent */ |
44 | /* Bypass leading non-'/'s and then subsequent '/'s. */ | 48 | /* Bypass leading non-'/'s and then subsequent '/'s */ |
45 | while (*s) { | 49 | while (*s) { |
46 | if (*s == '/') { | 50 | if (*s == '/') { |
47 | do { | 51 | do { |
48 | ++s; | 52 | ++s; |
49 | } while (*s == '/'); | 53 | } while (*s == '/'); |
50 | c = *s; /* Save the current char */ | 54 | c = *s; /* Save the current char */ |
51 | *s = '\0'; /* and replace it with nul. */ | 55 | *s = '\0'; /* and replace it with nul */ |
52 | break; | 56 | break; |
53 | } | 57 | } |
54 | ++s; | 58 | ++s; |
55 | } | 59 | } |
56 | } | 60 | } |
57 | 61 | ||
58 | if (!c) /* Last component uses orig umask */ | 62 | if (c != '\0') { |
59 | umask(mask); | 63 | /* Intermediate dirs: must have wx for user */ |
64 | if (cur_mask == (mode_t)-1L) { /* wasn't done yet? */ | ||
65 | mode_t new_mask; | ||
66 | org_mask = umask(0); | ||
67 | cur_mask = 0; | ||
68 | /* Clear u=wx in umask - this ensures | ||
69 | * they won't be cleared on mkdir */ | ||
70 | new_mask = (org_mask & ~(mode_t)0300); | ||
71 | //bb_error_msg("org_mask:%o cur_mask:%o", org_mask, new_mask); | ||
72 | if (new_mask != cur_mask) { | ||
73 | cur_mask = new_mask; | ||
74 | umask(new_mask); | ||
75 | } | ||
76 | } | ||
77 | } else { | ||
78 | /* Last component: uses original umask */ | ||
79 | //bb_error_msg("1 org_mask:%o", org_mask); | ||
80 | if (org_mask != cur_mask) { | ||
81 | cur_mask = org_mask; | ||
82 | umask(org_mask); | ||
83 | } | ||
84 | } | ||
60 | 85 | ||
61 | if (mkdir(path, 0777) < 0) { | 86 | if (mkdir(path, 0777) < 0) { |
62 | /* If we failed for any other reason than the directory | 87 | /* If we failed for any other reason than the directory |
63 | * already exists, output a diagnostic and return -1. */ | 88 | * already exists, output a diagnostic and return -1 */ |
64 | if (errno != EEXIST | 89 | if (errno != EEXIST |
65 | || !(flags & FILEUTILS_RECUR) | 90 | || !(flags & FILEUTILS_RECUR) |
66 | || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode)) | 91 | || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode)) |
67 | ) { | 92 | ) { |
68 | fail_msg = "create"; | 93 | fail_msg = "create"; |
69 | umask(mask); | ||
70 | break; | 94 | break; |
71 | } | 95 | } |
72 | /* Since the directory exists, don't attempt to change | 96 | /* Since the directory exists, don't attempt to change |
73 | * permissions if it was the full target. Note that | 97 | * permissions if it was the full target. Note that |
74 | * this is not an error condition. */ | 98 | * this is not an error condition. */ |
75 | if (!c) { | 99 | if (!c) { |
76 | umask(mask); | 100 | goto ret0; |
77 | return 0; | ||
78 | } | 101 | } |
79 | } | 102 | } |
80 | 103 | ||
@@ -86,13 +109,21 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) | |||
86 | fail_msg = "set permissions of"; | 109 | fail_msg = "set permissions of"; |
87 | break; | 110 | break; |
88 | } | 111 | } |
89 | return 0; | 112 | goto ret0; |
90 | } | 113 | } |
91 | 114 | ||
92 | /* Remove any inserted nul from the path (recursive mode). */ | 115 | /* Remove any inserted nul from the path (recursive mode) */ |
93 | *s = c; | 116 | *s = c; |
94 | } /* while (1) */ | 117 | } /* while (1) */ |
95 | 118 | ||
96 | bb_perror_msg("can't %s directory '%s'", fail_msg, path); | 119 | bb_perror_msg("can't %s directory '%s'", fail_msg, path); |
97 | return -1; | 120 | flags = -1; |
121 | goto ret; | ||
122 | ret0: | ||
123 | flags = 0; | ||
124 | ret: | ||
125 | //bb_error_msg("2 org_mask:%o", org_mask); | ||
126 | if (org_mask != cur_mask) | ||
127 | umask(org_mask); | ||
128 | return flags; | ||
98 | } | 129 | } |