More removal of "#if 0" content.
[oweals/busybox.git] / libbb / make_directory.c
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  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  *
21  */
22
23 /* Mar 5, 2003    Manuel Novoa III
24  *
25  * This is the main work function for the 'mkdir' applet.  As such, it
26  * strives to be SUSv3 compliant in it's behaviour when recursively
27  * making missing parent dirs, and in it's mode setting of the final
28  * directory 'path'.
29  *
30  * To recursively build all missing intermediate directories, make
31  * sure that (flags & FILEUTILS_RECUR) is non-zero.  Newly created
32  * intermediate directories will have at least u+wx perms.
33  *
34  * To set specific permissions on 'path', pass the appropriate 'mode'
35  * val.  Otherwise, pass -1 to get default permissions.
36  */
37
38 #include <errno.h>
39 #include <unistd.h>
40 #include <sys/stat.h>
41 #include "libbb.h"
42
43 int bb_make_directory (char *path, long mode, int flags)
44 {
45         mode_t mask;
46         const char *fail_msg;
47         char *s = path;
48         char c;
49         struct stat st;
50
51         mask = umask(0);
52         if (mode == -1) {
53                 umask(mask);
54                 mode = (S_IXUSR | S_IXGRP | S_IXOTH |
55                                 S_IWUSR | S_IWGRP | S_IWOTH |
56                                 S_IRUSR | S_IRGRP | S_IROTH) & ~mask;
57         } else {
58                 umask(mask & ~0300);
59         }
60
61         do {
62                 c = 0;
63
64                 if (flags & FILEUTILS_RECUR) {  /* Get the parent. */
65                         /* Bypass leading non-'/'s and then subsequent '/'s. */
66                         while (*s) {
67                                 if (*s == '/') {
68                                         do {
69                                                 ++s;
70                                         } while (*s == '/');
71                                         c = *s;         /* Save the current char */
72                                         *s = 0;         /* and replace it with nul. */
73                                         break;
74                                 }
75                                 ++s;
76                         }
77                 }
78
79                 if (mkdir(path, 0777) < 0) {
80                         /* If we failed for any other reason than the directory
81                          * already exists, output a diagnostic and return -1.*/
82                         if (errno != EEXIST
83                                 || !(flags & FILEUTILS_RECUR)
84                                 || (stat(path, &st) < 0 || !S_ISDIR(st.st_mode))) {
85                                 fail_msg = "create";
86                                 umask(mask);
87                                 break;
88                         }
89                         /* Since the directory exists, don't attempt to change
90                          * permissions if it was the full target.  Note that
91                          * this is not an error conditon. */
92                         if (!c) {
93                                 umask(mask);
94                                 return 0;
95                         }
96                 }
97
98                 if (!c) {
99                         /* Done.  If necessary, updated perms on the newly
100                          * created directory.  Failure to update here _is_
101                          * an error.*/
102                         umask(mask);
103                         if ((mode != -1) && (chmod(path, mode) < 0)){
104                                 fail_msg = "set permissions of";
105                                 break;
106                         }
107                         return 0;
108                 }
109
110                 /* Remove any inserted nul from the path (recursive mode). */
111                 *s = c;
112
113         } while (1);
114
115         bb_perror_msg ("Cannot %s directory `%s'", fail_msg, path);
116         return -1;
117 }