source: MondoRescue/branches/3.3/mindi-busybox/libbb/make_directory.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 3.4 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * parse_mode implementation for busybox
4 *
5 * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10/* Mar 5, 2003 Manuel Novoa III
11 *
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'.
16 *
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.
20 *
21 * To set specific permissions on 'path', pass the appropriate 'mode'
22 * val. Otherwise, pass -1 to get default permissions.
23 */
24
25#include "libbb.h"
26
27/* This function is used from NOFORK applets. It must not allocate anything */
28
29int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
30{
31 mode_t cur_mask;
32 mode_t org_mask;
33 const char *fail_msg;
34 char *s;
35 char c;
36 struct stat st;
37
38 /* Happens on bb_make_directory(dirname("no_slashes"),...) */
39 if (LONE_CHAR(path, '.'))
40 return 0;
41
42 org_mask = cur_mask = (mode_t)-1L;
43 s = path;
44 while (1) {
45 c = '\0';
46
47 if (flags & FILEUTILS_RECUR) { /* Get the parent */
48 /* Bypass leading non-'/'s and then subsequent '/'s */
49 while (*s) {
50 if (*s == '/') {
51 do {
52 ++s;
53 } while (*s == '/');
54 c = *s; /* Save the current char */
55 *s = '\0'; /* and replace it with nul */
56 break;
57 }
58 ++s;
59 }
60 }
61
62 if (c != '\0') {
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 }
85
86 if (mkdir(path, 0777) < 0) {
87 /* If we failed for any other reason than the directory
88 * already exists, output a diagnostic and return -1 */
89 if ((errno != EEXIST && errno != EISDIR)
90 || !(flags & FILEUTILS_RECUR)
91 || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode))
92 ) {
93 fail_msg = "create";
94 break;
95 }
96 /* Since the directory exists, don't attempt to change
97 * permissions if it was the full target. Note that
98 * this is not an error condition. */
99 if (!c) {
100 goto ret0;
101 }
102 } else {
103 if (flags & FILEUTILS_VERBOSE) {
104 printf("created directory: '%s'\n", path);
105 }
106 }
107
108 if (!c) {
109 /* Done. If necessary, update perms on the newly
110 * created directory. Failure to update here _is_
111 * an error. */
112 if ((mode != -1) && (chmod(path, mode) < 0)) {
113 fail_msg = "set permissions of";
114 if (flags & FILEUTILS_IGNORE_CHMOD_ERR) {
115 flags = 0;
116 goto print_err;
117 }
118 break;
119 }
120 goto ret0;
121 }
122
123 /* Remove any inserted nul from the path (recursive mode) */
124 *s = c;
125 } /* while (1) */
126
127 flags = -1;
128 print_err:
129 bb_perror_msg("can't %s directory '%s'", fail_msg, path);
130 goto ret;
131 ret0:
132 flags = 0;
133 ret:
134 //bb_error_msg("2 org_mask:%o", org_mask);
135 if (org_mask != cur_mask)
136 umask(org_mask);
137 return flags;
138}
Note: See TracBrowser for help on using the repository browser.