]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/mkpath.c
kes Suppress chown and chmod error messages if the FD is not running
[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          Jmsg2(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          Jmsg1(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(ATTR *attr, char *path, uid_t owner, gid_t group, mode_t mode)
62 {
63    if (chown(path, owner, group) != 0 && attr->uid == 0
64 #ifdef AFS
65         && errno != EPERM
66 #endif
67    ) {
68       berrno be;
69       Jmsg2(attr->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 && attr->uid == 0) {
73       berrno be;
74       Jmsg2(attr->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(ATTR *attr, 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    JCR *jcr = attr->jcr;
104
105    if (stat(path, &statp) == 0) {     /* Does dir exist? */
106       if (!S_ISDIR(statp.st_mode)) {
107          Jmsg1(jcr, M_ERROR, 0, _("%s exists but is not a directory.\n"), path);
108          return false;
109       }
110       /* Full path exists */
111       if (keep_dir_modes) {
112          return true;
113       }
114       set_own_mod(attr, path, owner, group, mode);
115       return true;
116    }
117    omask = umask(0);
118    umask(omask);
119    len = strlen(apath);
120    path = (char *)alloca(len+1);
121    bstrncpy(path, apath, len+1);
122    strip_trailing_slashes(path);
123    /*
124     * Now for one of the complexities. If we are not running as root,
125     *  then if the parent_mode does not have wx user perms, or we are
126     *  setting the userid or group, and the parent_mode has setuid, setgid,
127     *  or sticky bits, we must create the dir with open permissions, then
128     *  go back and patch all the dirs up with the correct perms.
129     * Solution, set everything to 0777, then go back and reset them at the
130     *  end.
131     */
132    tmode = 0777;
133
134 #if defined(HAVE_WIN32)
135    /* Validate drive letter */
136    if (path[1] == ':') {
137       char drive[4] = "X:\\";
138
139       drive[0] = path[0];
140
141       UINT drive_type = GetDriveType(drive);
142
143       if (drive_type == DRIVE_UNKNOWN || drive_type == DRIVE_NO_ROOT_DIR) {
144          Jmsg1(jcr, M_ERROR, 0, _("%c: is not a valid drive.\n"), path[0]);
145          goto bail_out;
146       }
147
148       if (path[2] == '\0') {          /* attempt to create a drive */
149          ok = true;
150          goto bail_out;               /* OK, it is already there */
151       }
152
153       p = &path[3];
154    } else {
155       p = path;
156    }
157 #else
158    p = path;
159 #endif
160
161    /* Skip leading slash(es) */
162    while (IsPathSeparator(*p)) {
163       p++;
164    }
165    while ((p = first_path_separator(p))) {
166       char save_p;
167       save_p = *p;
168       *p = 0;
169       if (!makedir(jcr, path, tmode, &created)) {
170          goto bail_out;
171       }
172       if (ndir < max_dirs) {
173          new_dir[ndir++] = created;
174       }
175       *p = save_p;
176       while (IsPathSeparator(*p)) {
177          p++;
178       }
179    }
180    /* Create final component */
181    if (!makedir(jcr, path, tmode, &created)) {
182       goto bail_out;
183    }
184    if (ndir < max_dirs) {
185       new_dir[ndir++] = created;
186    }
187    if (ndir >= max_dirs) {
188       Jmsg0(jcr, M_WARNING, 0, _("Too many subdirectories. Some permissions not reset.\n"));
189    }
190
191    /* Now set the proper owner and modes */
192 #if defined(HAVE_WIN32)
193    if (path[1] == ':') {
194       p = &path[3];
195    } else {
196       p = path;
197    }
198 #else
199    p = path;
200 #endif
201    /* Skip leading slash(es) */
202    while (IsPathSeparator(*p)) {
203       p++;
204    }
205    while ((p = first_path_separator(p))) {
206       char save_p;
207       save_p = *p;
208       *p = 0;
209       if (i < ndir && new_dir[i++] && !keep_dir_modes) {
210          set_own_mod(attr, path, owner, group, parent_mode);
211       }
212       *p = save_p;
213       while (IsPathSeparator(*p)) {
214          p++;
215       }
216    }
217
218    /* Set for final component */
219    if (i < ndir && new_dir[i++]) {
220       set_own_mod(attr, path, owner, group, mode);
221    }
222
223    ok = true;
224 bail_out:
225    umask(omask);
226    return ok;
227 }