]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/mkpath.c
kes Integrate patch to README.vc8 from
[bacula/bacula] / bacula / src / findlib / mkpath.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2007-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28
29 /*
30  *  Kern Sibbald, September MMVII
31  * 
32  *  This is tricky code, especially when writing from scratch. Fortunately,
33  *    a non-copyrighted version of mkdir was available to consult.
34  *
35  *  Version $Id$
36  */
37 #include "bacula.h"
38 #include "jcr.h"
39
40 static bool makedir(JCR *jcr, char *path, mode_t mode, int *created)
41 {
42    struct stat statp;
43
44    if (mkdir(path, mode) != 0) {
45       berrno be;
46       *created = false;
47       if (stat(path, &statp) != 0) {
48          Jmsg(jcr, M_ERROR, 0, _("Cannot create directory %s: ERR=%s\n"),
49               path, be.bstrerror());
50          return false;
51       } else if (!S_ISDIR(statp.st_mode)) {
52          Jmsg(jcr, M_ERROR, 0, _("%s exists but is not a directory.\n"), path);
53          return false;
54       }
55       return true;                 /* directory exists */
56    }
57    *created = true;
58    return true;
59 }
60
61 static void set_own_mod(JCR *jcr, char *path, uid_t owner, gid_t group, mode_t mode)
62 {
63    if (chown(path, owner, group) != 0
64 #ifdef AFS
65         && errno != EPERM
66 #endif
67    ) {
68       berrno be;
69       Jmsg(jcr, M_WARNING, 0, _("Cannot change owner and/or group of %s: ERR=%s\n"),
70            path, be.bstrerror());
71    }
72    if (chmod(path, mode) != 0) {
73       berrno be;
74       Jmsg(jcr, M_WARNING, 0, _("Cannot change permissions of %s: ERR=%s\n"),
75            path, be.bstrerror());
76    }
77 }
78
79 /*
80  * mode is the mode bits to use in creating a new directory
81  *
82  * parent_mode are the parent's modes if we need to create parent 
83  *    directories.
84  *
85  * owner and group are to set on any created dirs
86  *
87  * keep_dir_modes if set means don't change mode bits if dir exists
88  */
89 bool makepath(JCR *jcr, const char *apath, mode_t mode, mode_t parent_mode,
90             uid_t owner, gid_t group, int keep_dir_modes)
91 {
92    struct stat statp;
93    mode_t omask, tmode;
94    char *path = (char *)apath;
95    char *p;
96    int len;
97    bool ok = false;
98    int created;
99    char new_dir[5000];
100    int ndir = 0;
101    int i = 0;
102    int max_dirs = (int)sizeof(new_dir);
103
104    if (stat(path, &statp) == 0) {     /* Does dir exist? */
105       if (!S_ISDIR(statp.st_mode)) {
106          Jmsg(jcr, M_ERROR, 0, _("%s exists but is not a directory.\n"), path);
107          return false;
108       }
109       /* Full path exists */
110       if (keep_dir_modes) {
111          return true;
112       }
113       set_own_mod(jcr, path, owner, group, mode);
114       return true;
115    }
116    omask = umask(0);
117    umask(omask);
118    len = strlen(apath);
119    path = (char *)alloca(len+1);
120    bstrncpy(path, apath, len+1);
121    strip_trailing_slashes(path);
122    /*
123     * Now for one of the complexities. If we are not running as root,
124     *  then if the parent_mode does not have wx user perms, or we are
125     *  setting the userid or group, and the parent_mode has setuid, setgid,
126     *  or sticky bits, we must create the dir with open permissions, then
127     *  go back and patch all the dirs up with the correct perms.
128     * Solution, set everything to 0777, then go back and reset them at the
129     *  end.
130     */
131    tmode = 0777;
132
133 #if defined(HAVE_WIN32)
134    /* Validate drive letter */
135    if (path[1] == ':') {
136       char drive[4] = "X:\\";
137
138       drive[0] = path[0];
139
140       UINT drive_type = GetDriveType(drive);
141
142       if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) {
143          Jmsg(jcr, M_ERROR, 0, _("%c: is not a valid drive.\n"), path[0]);
144          goto bail_out;
145       }
146
147       if (path[2] == '\0') {          /* attempt to create a drive */
148          ok = true;
149          goto bail_out;               /* OK, it is already there */
150       }
151
152       p = &path[3];
153    } else {
154       p = path;
155    }
156 #else
157    p = path;
158 #endif
159
160    /* Skip leading slash(es) */
161    while (IsPathSeparator(*p)) {
162       p++;
163    }
164    while ((p = first_path_separator(p))) {
165       char save_p;
166       save_p = *p;
167       *p = 0;
168       if (!makedir(jcr, path, tmode, &created)) {
169          goto bail_out;
170       }
171       if (ndir < max_dirs) {
172          new_dir[ndir++] = created;
173       }
174       *p = save_p;
175       while (IsPathSeparator(*p)) {
176          p++;
177       }
178    }
179    /* Create final component */
180    if (!makedir(jcr, path, tmode, &created)) {
181       goto bail_out;
182    }
183    if (ndir < max_dirs) {
184       new_dir[ndir++] = created;
185    }
186    if (ndir >= max_dirs) {
187       Jmsg(jcr, M_WARNING, 0, _("Too many subdirectories. Some permissions not reset.\n"));
188    }
189
190    /* Now set the proper owner and modes */
191 #if defined(HAVE_WIN32)
192    if (path[1] == ':') {
193       p = &path[3];
194    } else {
195       p = path;
196    }
197 #else
198    p = path;
199 #endif
200    /* Skip leading slash(es) */
201    while (IsPathSeparator(*p)) {
202       p++;
203    }
204    while ((p = first_path_separator(p))) {
205       char save_p;
206       save_p = *p;
207       *p = 0;
208       if (i < ndir && new_dir[i++] && !keep_dir_modes) {
209          set_own_mod(jcr, path, owner, group, parent_mode);
210       }
211       *p = save_p;
212       while (IsPathSeparator(*p)) {
213          p++;
214       }
215    }
216
217    /* Set for final component */
218    if (i < ndir && new_dir[i++]) {
219       set_own_mod(jcr, path, owner, group, mode);
220    }
221
222    ok = true;
223 bail_out:
224    umask(omask);
225    return ok;
226 }