bcda8d48274966493bae6d4540b3d22c4e2094e3
[platform/upstream/coreutils.git] / lib / mkdir-p.c
1 /* mkdir-p.c -- Ensure that a directory and its parents exist.
2
3    Copyright (C) 1990, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005
4    Free Software Foundation, Inc.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2, or (at your option)
9    any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software Foundation,
18    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
19
20 /* Written by David MacKenzie <djm@gnu.ai.mit.edu> and Jim Meyering.  */
21
22 #if HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include "mkdir-p.h"
27
28 #include <alloca.h>
29
30 #include <stdio.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #if HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <string.h>
40
41 #include "gettext.h"
42 #define _(msgid) gettext (msgid)
43
44 #include "save-cwd.h"
45 #include "dirname.h"
46 #include "error.h"
47 #include "quote.h"
48 #include "stat-macros.h"
49
50 #define WX_USR (S_IWUSR | S_IXUSR)
51
52 #define CLEANUP_CWD                                     \
53   do                                                    \
54     {                                                   \
55       /* We're done operating on basename_dir.          \
56          Restore working directory.  */                 \
57       if (do_chdir)                                     \
58         {                                               \
59           if (restore_cwd (&cwd) != 0)                  \
60             {                                           \
61               int _saved_errno = errno;                 \
62               error (0, errno,                          \
63                 _("failed to return to initial working directory")); \
64               free_cwd (&cwd);                          \
65               errno = _saved_errno;                     \
66               *different_working_dir = true;            \
67               return false;                             \
68             }                                           \
69           free_cwd (&cwd);                              \
70         }                                               \
71     }                                                   \
72   while (0)
73
74 #define CLEANUP                                         \
75   do                                                    \
76     {                                                   \
77       umask (oldmask);                                  \
78       CLEANUP_CWD;                                      \
79     }                                                   \
80   while (0)
81
82 /* Attempt to create directory DIR (aka FULLDIR) with the specified MODE.
83    If CREATED_DIR_P is non-NULL, set *CREATED_DIR_P if this
84    function creates DIR and clear it otherwise.  Give a diagnostic and
85    return false if DIR cannot be created or cannot be determined to
86    exist already.  Use FULLDIR in any diagnostic, not DIR.
87    Note that if DIR already exists, this function returns true
88    (indicating success) and clears *CREATED_DIR_P.  */
89
90 bool
91 make_dir (char const *dir, char const *fulldir, mode_t mode,
92           bool *created_dir_p)
93 {
94   bool ok = true;
95   bool created_dir;
96
97   created_dir = (mkdir (dir, mode) == 0);
98
99   if (!created_dir)
100     {
101       struct stat stats;
102       int saved_errno = errno;
103
104       /* The mkdir and stat calls below may appear to be reversed.
105          They are not.  It is important to call mkdir first and then to
106          call stat (to distinguish the three cases) only if mkdir fails.
107          The alternative to this approach is to `stat' each directory,
108          then to call mkdir if it doesn't exist.  But if some other process
109          were to create the directory between the stat & mkdir, the mkdir
110          would fail with EEXIST.  */
111
112       if (stat (dir, &stats))
113         {
114           error (0, saved_errno, _("cannot create directory %s"),
115                  quote (fulldir));
116           ok = false;
117         }
118       else if (!S_ISDIR (stats.st_mode))
119         {
120           error (0, 0, _("%s exists but is not a directory"), quote (fulldir));
121           ok = false;
122         }
123       else
124         {
125           /* DIR (aka FULLDIR) already exists and is a directory. */
126         }
127     }
128
129   if (created_dir_p)
130     *created_dir_p = created_dir;
131
132   return ok;
133 }
134
135 /* Ensure that the directory ARG exists.
136
137    Create any leading directories that don't already exist, with
138    permissions PARENT_MODE.
139    If the last element of ARG does not exist, create it as
140    a new directory with permissions MODE.
141    If OWNER and GROUP are non-negative, use them to set the UID and GID of
142    any created directories.
143    If VERBOSE_FMT_STRING is nonzero, use it as a printf format
144    string for printing a message after successfully making a directory,
145    with the name of the directory that was just made as an argument.
146    If PRESERVE_EXISTING is true and ARG is an existing directory,
147    then do not attempt to set its permissions and ownership.
148    Upon return, set *DIFFERENT_WORKING_DIR to true if this function
149    has changed the current working directory and is unable to restore
150    it to its initial state.
151
152    Return true iff ARG exists as a directory with the proper
153    ownership and permissions when done.  */
154
155 bool
156 make_dir_parents (char const *arg,
157                   mode_t mode,
158                   mode_t parent_mode,
159                   uid_t owner,
160                   gid_t group,
161                   bool preserve_existing,
162                   char const *verbose_fmt_string,
163                   bool *different_working_dir)
164 {
165   struct stat stats;
166   bool retval = true;
167   *different_working_dir = false;
168
169   if (stat (arg, &stats) != 0)
170     {
171       char *slash;
172       mode_t tmp_mode;          /* Initial perms for leading dirs.  */
173       bool re_protect;          /* Should leading dirs be unwritable? */
174       struct ptr_list
175       {
176         char *dirname_end;
177         struct ptr_list *next;
178       };
179       struct ptr_list *p, *leading_dirs = NULL;
180       bool do_chdir;            /* Whether to chdir before each mkdir.  */
181       struct saved_cwd cwd;
182       char *basename_dir;
183       char *dir;
184
185       /* Temporarily relax umask in case it's overly restrictive.  */
186       mode_t oldmask = umask (0);
187
188       /* Make a copy of ARG that we can scribble NULs on.  */
189       dir = (char *) alloca (strlen (arg) + 1);
190       strcpy (dir, arg);
191       strip_trailing_slashes (dir);
192
193       /* If leading directories shouldn't be writable or executable,
194          or should have set[ug]id or sticky bits set and we are setting
195          their owners, we need to fix their permissions after making them.  */
196       if (((parent_mode & WX_USR) != WX_USR)
197           || ((owner != (uid_t) -1 || group != (gid_t) -1)
198               && (parent_mode & (S_ISUID | S_ISGID | S_ISVTX)) != 0))
199         {
200           tmp_mode = S_IRWXU;
201           re_protect = true;
202         }
203       else
204         {
205           tmp_mode = parent_mode;
206           re_protect = false;
207         }
208
209       /* If we can record the current working directory, we may be able
210          to do the chdir optimization.  */
211       do_chdir = (save_cwd (&cwd) == 0);
212
213       /* If we've saved the cwd and DIR is an absolute file name,
214          we must chdir to `/' in order to enable the chdir optimization.
215          So if chdir ("/") fails, turn off the optimization.  */
216       if (do_chdir && dir[0] == '/')
217         {
218           /* POSIX says "//" might be special, so chdir to "//" if the
219              file name starts with exactly two slashes.  */
220           char const *root = "//" + (dir[1] != '/' || dir[2] == '/');
221           if (chdir (root) != 0)
222             do_chdir = false;
223         }
224
225       slash = dir;
226
227       /* Skip over leading slashes.  */
228       while (*slash == '/')
229         slash++;
230
231       while (1)
232         {
233           bool newly_created_dir;
234
235           /* slash points to the leftmost unprocessed component of dir.  */
236           basename_dir = slash;
237
238           slash = strchr (slash, '/');
239           if (slash == NULL)
240             break;
241
242           /* If we're *not* doing chdir before each mkdir, then we have to refer
243              to the target using the full (multi-component) directory name.  */
244           if (!do_chdir)
245             basename_dir = dir;
246
247           *slash = '\0';
248           if (! make_dir (basename_dir, dir, tmp_mode, &newly_created_dir))
249             {
250               CLEANUP;
251               return false;
252             }
253
254           if (newly_created_dir)
255             {
256               if (verbose_fmt_string)
257                 error (0, 0, verbose_fmt_string, quote (dir));
258
259               if ((owner != (uid_t) -1 || group != (gid_t) -1)
260                   && chown (basename_dir, owner, group)
261 #if defined AFS && defined EPERM
262                   && errno != EPERM
263 #endif
264                   )
265                 {
266                   error (0, errno, _("cannot change owner and/or group of %s"),
267                          quote (dir));
268                   CLEANUP;
269                   return false;
270                 }
271
272               if (re_protect)
273                 {
274                   struct ptr_list *new = (struct ptr_list *)
275                     alloca (sizeof (struct ptr_list));
276                   new->dirname_end = slash;
277                   new->next = leading_dirs;
278                   leading_dirs = new;
279                 }
280             }
281
282           /* If we were able to save the initial working directory,
283              then we can use chdir to change into each directory before
284              creating an entry in that directory.  This avoids making
285              stat and mkdir process O(n^2) file name components.  */
286           if (do_chdir && chdir (basename_dir) < 0)
287             {
288               error (0, errno, _("cannot chdir to directory %s"),
289                      quote (dir));
290               CLEANUP;
291               return false;
292             }
293
294           *slash++ = '/';
295
296           /* Avoid unnecessary calls to `stat' when given
297              file names containing multiple adjacent slashes.  */
298           while (*slash == '/')
299             slash++;
300         }
301
302       if (!do_chdir)
303         basename_dir = dir;
304
305       /* Done creating leading directories.  Restore original umask.  */
306       umask (oldmask);
307
308       /* We're done making leading directories.
309          Create the final component of the file name.  */
310
311       if (! make_dir (basename_dir, dir, mode, NULL))
312         {
313           CLEANUP;
314           return false;
315         }
316
317       if (verbose_fmt_string != NULL)
318         error (0, 0, verbose_fmt_string, quote (dir));
319
320       if (owner != (uid_t) -1 || group != (gid_t) -1)
321         {
322           if (chown (basename_dir, owner, group)
323 #ifdef AFS
324               && errno != EPERM
325 #endif
326               )
327             {
328               error (0, errno, _("cannot change owner and/or group of %s"),
329                      quote (dir));
330               retval = false;
331             }
332         }
333
334       /* The above chown may have turned off some permission bits in MODE.
335          Another reason we may have to use chmod here is that mkdir(2) is
336          required to honor only the file permission bits.  In particular,
337          it need not honor the `special' bits, so if MODE includes any
338          special bits, set them here.  */
339       if ((mode & ~S_IRWXUGO)
340           && chmod (basename_dir, mode))
341         {
342           error (0, errno, _("cannot change permissions of %s"),
343                  quote (dir));
344           retval = false;
345         }
346
347       CLEANUP_CWD;
348
349       /* If the mode for leading directories didn't include owner "wx"
350          privileges, we have to reset their protections to the correct
351          value.  */
352       for (p = leading_dirs; p != NULL; p = p->next)
353         {
354           *(p->dirname_end) = '\0';
355           if (chmod (dir, parent_mode) != 0)
356             {
357               error (0, errno, _("cannot change permissions of %s"),
358                      quote (dir));
359               retval = false;
360             }
361         }
362     }
363   else
364     {
365       /* We get here if the file already exists.  */
366
367       char const *dir = arg;
368
369       if (!S_ISDIR (stats.st_mode))
370         {
371           error (0, 0, _("%s exists but is not a directory"), quote (dir));
372           return false;
373         }
374
375       if (!preserve_existing)
376         {
377           /* chown must precede chmod because on some systems,
378              chown clears the set[ug]id bits for non-superusers,
379              resulting in incorrect permissions.
380              On System V, users can give away files with chown and then not
381              be able to chmod them.  So don't give files away.  */
382
383           if ((owner != (uid_t) -1 || group != (gid_t) -1)
384               && chown (dir, owner, group)
385 #ifdef AFS
386               && errno != EPERM
387 #endif
388               )
389             {
390               error (0, errno, _("cannot change owner and/or group of %s"),
391                      quote (dir));
392               retval = false;
393             }
394           if (chmod (dir, mode) != 0)
395             {
396               error (0, errno, _("cannot change permissions of %s"),
397                                  quote (dir));
398               retval = false;
399             }
400         }
401     }
402
403   return retval;
404 }