1 /* makepath.c -- Ensure that a directory path exists.
3 Copyright (C) 1990, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 /* Written by David MacKenzie <djm@gnu.ai.mit.edu> and Jim Meyering. */
22 * Modified by Kern Sibbald for use in Bacula, December 2000
32 #if !defined(S_ISDIR) && defined(S_IFDIR)
33 # define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
37 # define S_IRWXUGO (S_IRWXU | S_IRWXG | S_IRWXO)
42 # define S_ISUID 04000
45 # define S_ISGID 02000
48 # define S_ISVTX 01000
61 # define S_IRWXU (S_IRUSR | S_IWUSR | S_IXUSR)
64 #define WX_USR (S_IWUSR | S_IXUSR)
66 #define quote(path) path
68 extern void strip_trailing_slashes();
71 cleanup(struct saved_cwd *cwd)
74 int _fail = restore_cwd(cwd, NULL, NULL);
83 /* Attempt to create directory DIR (aka DIRPATH) with the specified MODE.
84 If CREATED_DIR_P is non-NULL, set *CREATED_DIR_P to non-zero if this
85 function creates DIR and to zero otherwise. Give a diagnostic and
86 return non-zero if DIR cannot be created or cannot be determined to
87 exist already. Use DIRPATH in any diagnostic, not DIR.
88 Note that if DIR already exists, this function will return zero
89 (indicating success) and will set *CREATED_DIR_P to zero. */
92 make_dir(void *jcr, const char *dir, const char *dirpath, mode_t mode, int *created_dir_p)
97 Dmsg2(300, "make_dir mode=%o dir=%s\n", mode, dir);
98 created_dir = (mkdir(dir, mode) == 0);
103 /* The mkdir and stat calls below may appear to be reversed.
104 They are not. It is important to call mkdir first and then to
105 call stat (to distinguish the three cases) only if mkdir fails.
106 The alternative to this approach is to `stat' each directory,
107 then to call mkdir if it doesn't exist. But if some other process
108 were to create the directory between the stat & mkdir, the mkdir
109 would fail with EEXIST. */
111 if (stat(dir, &stats)) {
112 Jmsg(jcr, M_ERROR, 0, "Cannot create directory %s: %s\n",
113 dirpath, strerror(errno));
115 } else if (!S_ISDIR(stats.st_mode)) {
116 Jmsg(jcr, M_ERROR, 0, "%s exists but is not a directory\n", quote(dirpath));
119 /* DIR (aka DIRPATH) already exists and is a directory. */
124 *created_dir_p = created_dir;
130 /* Ensure that the directory ARGPATH exists.
131 Remove any trailing slashes from ARGPATH before calling this function.
133 Create any leading directories that don't already exist, with
134 permissions PARENT_MODE.
136 If the last element of ARGPATH does not exist, create it as
137 a new directory with permissions MODE.
139 If OWNER and GROUP are non-negative, use them to set the UID and GID of
140 any created directories.
142 If VERBOSE_FMT_STRING is nonzero, use it as a printf format
143 string for printing a message after successfully making a directory,
144 with the name of the directory that was just made as an argument.
146 If PRESERVE_EXISTING is non-zero and ARGPATH is an existing directory,
147 then do not attempt to set its permissions and ownership.
149 Return 0 if ARGPATH exists as a directory with the proper
150 ownership and permissions when done, otherwise 1. */
160 int preserve_existing,
161 char *verbose_fmt_string)
166 if (stat(argpath, &stats)) {
168 int tmp_mode; /* Initial perms for leading dirs. */
169 int re_protect; /* Should leading dirs be unwritable? */
172 struct ptr_list *next;
174 struct ptr_list *p, *leading_dirs = NULL;
175 struct saved_cwd cwd;
179 /* Temporarily relax umask in case it's overly restrictive. */
180 mode_t oldmask = umask (0);
182 /* Make a copy of ARGPATH that we can scribble NULs on. */
183 dirpath = (char *)alloca(strlen(argpath) + 1);
184 strcpy (dirpath, argpath);
185 strip_trailing_slashes(dirpath);
187 /* If leading directories shouldn't be writable or executable,
188 or should have set[ug]id or sticky bits set and we are setting
189 their owners, we need to fix their permissions after making them. */
190 if (((parent_mode & WX_USR) != WX_USR)
191 || ((owner != (uid_t) -1 || group != (gid_t) -1)
192 && (parent_mode & (S_ISUID | S_ISGID | S_ISVTX)) != 0))
198 tmp_mode = parent_mode;
202 /* If we can record the current working directory, we may be able
203 to do the chdir optimization. */
204 cwd.do_chdir = !save_cwd(&cwd);
206 /* If we've saved the cwd and DIRPATH is an absolute pathname,
207 we must chdir to `/' in order to enable the chdir optimization.
208 So if chdir ("/") fails, turn off the optimization. */
209 if (cwd.do_chdir && *dirpath == '/' && chdir ("/") < 0) {
215 /* Skip over leading slashes. */
216 while (*slash == '/')
220 int newly_created_dir;
223 /* slash points to the leftmost unprocessed component of dirpath. */
224 basename_dir = slash;
226 slash = strchr (slash, '/');
231 /* If we're *not* doing chdir before each mkdir, then we have to refer
232 to the target using the full (multi-component) directory name. */
234 basename_dir = dirpath;
238 fail = make_dir(jcr, basename_dir, dirpath, tmp_mode, &newly_created_dir);
245 if (newly_created_dir) {
246 Dmsg0(300, "newly_created_dir\n");
247 if (verbose_fmt_string) {
248 Jmsg(jcr, M_ERROR, 0, verbose_fmt_string, quote(dirpath));
251 if ((owner != (uid_t) -1 || group != (gid_t) -1)
252 && chown (basename_dir, owner, group)
253 #if defined(AFS) && defined (EPERM)
257 Jmsg(jcr, M_ERROR, 0, "Cannot change owner and/or group of %s: %s\n",
258 quote (dirpath), strerror(errno));
263 Dmsg0(300, "Chown done.\n");
266 struct ptr_list *pnew = (struct ptr_list *)
267 alloca (sizeof (struct ptr_list));
268 pnew->dirname_end = slash;
269 pnew->next = leading_dirs;
271 Dmsg0(300, "re_protect\n");
275 /* If we were able to save the initial working directory,
276 then we can use chdir to change into each directory before
277 creating an entry in that directory. This avoids making
278 stat and mkdir process O(n^2) file name components. */
279 if (cwd.do_chdir && chdir(basename_dir) < 0) {
280 Jmsg(jcr, M_ERROR, 0, "Cannot chdir to directory, %s: %s\n",
281 quote (dirpath), strerror(errno));
289 /* Avoid unnecessary calls to `stat' when given
290 pathnames containing multiple adjacent slashes. */
291 while (*slash == '/')
293 } /* end while (1) */
296 basename_dir = dirpath;
299 /* We're done making leading directories.
300 Create the final component of the path. */
302 Dmsg1(300, "Create final component. mode=%o\n", mode);
303 if (make_dir(jcr, basename_dir, dirpath, mode, NULL)) {
309 /* Done creating directories. Restore original umask. */
312 if (verbose_fmt_string != NULL) {
313 Jmsg(jcr, M_ERROR, 0, verbose_fmt_string, dirpath);
316 if (owner != (uid_t) -1 || group != (gid_t) -1) {
317 if (chown(basename_dir, owner, group)
323 Jmsg(jcr, M_ERROR, 0, "Cannot change owner and/or group of %s: %s\n",
324 quote (dirpath), strerror(errno));
329 /* The above chown may have turned off some permission bits in MODE.
330 Another reason we may have to use chmod here is that mkdir(2) is
331 required to honor only the file permission bits. In particular,
332 it need not honor the `special' bits, so if MODE includes any
333 special bits, set them here. */
334 if (mode & ~S_IRWXUGO) {
335 Dmsg1(300, "Final chmod mode=%o\n", mode);
337 if ((mode & ~S_IRWXUGO) && chmod(basename_dir, mode)) {
338 Jmsg(jcr, M_ERROR, 0, "Cannot change permissions of %s: %s\n",
339 quote(dirpath), strerror(errno));
346 /* If the mode for leading directories didn't include owner "wx"
347 privileges, we have to reset their protections to the correct
349 for (p = leading_dirs; p != NULL; p = p->next) {
350 *(p->dirname_end) = '\0';
351 Dmsg2(300, "Reset parent mode=%o dir=%s\n", parent_mode, dirpath);
352 if (chmod(dirpath, parent_mode)) {
353 Jmsg(jcr, M_ERROR, 0, "Cannot change permissions of %s: %s\n",
354 quote (dirpath), strerror(errno));
359 /* We get here if the entire path already exists. */
361 const char *dirpath = argpath;
363 if (!S_ISDIR(stats.st_mode)) {
364 Jmsg(jcr, M_ERROR, 0, "%s exists but is not a directory\n", quote(dirpath));
368 if (!preserve_existing) {
369 Dmsg0(300, "Do not preserve existing.\n");
370 /* chown must precede chmod because on some systems,
371 chown clears the set[ug]id bits for non-superusers,
372 resulting in incorrect permissions.
373 On System V, users can give away files with chown and then not
374 be able to chmod them. So don't give files away. */
376 if ((owner != (uid_t) -1 || group != (gid_t) -1)
377 && chown(dirpath, owner, group)
383 Jmsg(jcr, M_ERROR, 0, "Cannot change owner and/or group of %s: %s\n",
384 quote(dirpath), strerror(errno));
387 if (chmod(dirpath, mode)) {
388 Jmsg(jcr, M_ERROR, 0, "Cannot change permissions of %s: %s\n",
389 quote(dirpath), strerror(errno));
392 Dmsg2(300, "pathexists chmod mode=%o dir=%s\n", mode, dirpath);