Sync from coreutils.
[gnulib.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, 2006
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 #ifdef 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 #include <unistd.h>
34
35 #include <stdlib.h>
36 #include <errno.h>
37 #include <string.h>
38
39 #include "gettext.h"
40 #define _(msgid) gettext (msgid)
41
42 #include "chdir-safer.h"
43 #include "dirname.h"
44 #include "error.h"
45 #include "lchmod.h"
46 #include "lchown.h"
47 #include "quote.h"
48 #include "save-cwd.h"
49 #include "stat-macros.h"
50
51 /* Ensure that the directory ARG exists.
52
53    Create any leading directories that don't already exist, with
54    permissions PARENT_MODE.
55    If the last element of ARG does not exist, create it as
56    a new directory with permissions MODE.
57    If OWNER and GROUP are non-negative, use them to set the UID and GID of
58    any created directories.
59    If VERBOSE_FMT_STRING is nonzero, use it as a printf format
60    string for printing a message after successfully making a directory,
61    with the name of the directory that was just made as an argument.
62    If PRESERVE_EXISTING is true and ARG is an existing directory,
63    then do not attempt to set its permissions and ownership.
64
65    Set *CWD_ERRNO to a (nonzero) error number if this
66    function has changed the current working directory and is unable to
67    restore it to its initial state.  Do not change
68    *CWD_ERRNO otherwise.
69
70    Return true iff ARG exists as a directory with the proper ownership
71    and permissions when done.  Note that this function returns true
72    even when it fails to return to the initial working directory.  */
73
74 bool
75 make_dir_parents (char const *arg,
76                   mode_t mode,
77                   mode_t parent_mode,
78                   uid_t owner,
79                   gid_t group,
80                   bool preserve_existing,
81                   char const *verbose_fmt_string,
82                   int *cwd_errno)
83 {
84   struct stat stats;
85   bool retval = true;
86   bool do_chdir = false;        /* Whether to chdir before each mkdir.  */
87   struct saved_cwd cwd;
88   bool cwd_problem = false;
89   char const *fixup_permissions_dir = NULL;
90   char const *full_dir = arg;
91
92   struct ptr_list
93   {
94     char *dirname_end;
95     struct ptr_list *next;
96   };
97   struct ptr_list *leading_dirs = NULL;
98
99   if (stat (arg, &stats) == 0)
100     {
101       if (! S_ISDIR (stats.st_mode))
102         {
103           error (0, 0, _("%s exists but is not a directory"), quote (arg));
104           return false;
105         }
106
107       if (!preserve_existing)
108         fixup_permissions_dir = arg;
109     }
110   else if (errno != ENOENT || !*arg)
111     {
112       error (0, errno, "%s", quote (arg));
113       return false;
114     }
115   else
116     {
117       char *slash;
118       mode_t tmp_mode;          /* Initial perms for leading dirs.  */
119       bool re_protect;          /* Should leading dirs be unwritable? */
120       char *basename_dir;
121       char *dir;
122
123       /* Temporarily relax umask in case it's overly restrictive.  */
124       mode_t oldmask = umask (0);
125
126       /* Make a copy of ARG that we can scribble NULs on.  */
127       dir = alloca (strlen (arg) + 1);
128       strcpy (dir, arg);
129       strip_trailing_slashes (dir);
130       full_dir = dir;
131
132       /* If leading directories shouldn't be readable, writable or executable,
133          or should have set[ug]id or sticky bits set and we are setting
134          their owners, we need to fix their permissions after making them.  */
135       if (((parent_mode & S_IRWXU) != S_IRWXU)
136           || ((owner != (uid_t) -1 || group != (gid_t) -1)
137               && (parent_mode & (S_ISUID | S_ISGID | S_ISVTX)) != 0))
138         {
139           tmp_mode = S_IRWXU;
140           re_protect = true;
141         }
142       else
143         {
144           tmp_mode = parent_mode;
145           re_protect = false;
146         }
147
148       /* If we can record the current working directory, we may be able
149          to do the chdir optimization.  */
150       do_chdir = (save_cwd (&cwd) == 0);
151
152       /* If we've saved the cwd and DIR is an absolute file name,
153          we must chdir to `/' in order to enable the chdir optimization.
154          So if chdir ("/") fails, turn off the optimization.  */
155       if (do_chdir && dir[0] == '/')
156         {
157           /* POSIX says "//" might be special, so chdir to "//" if the
158              file name starts with exactly two slashes.  */
159           char const *root = "//" + (dir[1] != '/' || dir[2] == '/');
160           if (chdir (root) != 0)
161             {
162               free_cwd (&cwd);
163               do_chdir = false;
164             }
165         }
166
167       slash = dir;
168
169       /* Skip over leading slashes.  */
170       while (*slash == '/')
171         slash++;
172
173       while (true)
174         {
175           bool dir_known_to_exist;
176           int mkdir_errno;
177
178           /* slash points to the leftmost unprocessed component of dir.  */
179           basename_dir = slash;
180
181           slash = strchr (slash, '/');
182           if (slash == NULL)
183             break;
184
185           /* If we're *not* doing chdir before each mkdir, then we have to refer
186              to the target using the full (multi-component) directory name.  */
187           if (!do_chdir)
188             basename_dir = dir;
189
190           *slash = '\0';
191           dir_known_to_exist = (mkdir (basename_dir, tmp_mode) == 0);
192           mkdir_errno = errno;
193
194           if (dir_known_to_exist)
195             {
196               if (verbose_fmt_string)
197                 error (0, 0, verbose_fmt_string, quote (dir));
198
199               if ((owner != (uid_t) -1 || group != (gid_t) -1)
200                   && lchown (basename_dir, owner, group)
201 #if defined AFS && defined EPERM
202                   && errno != EPERM
203 #endif
204                   )
205                 {
206                   error (0, errno, _("cannot change owner and/or group of %s"),
207                          quote (dir));
208                   retval = false;
209                   break;
210                 }
211
212               if (re_protect)
213                 {
214                   struct ptr_list *new = alloca (sizeof *new);
215                   new->dirname_end = slash;
216                   new->next = leading_dirs;
217                   leading_dirs = new;
218                 }
219             }
220
221           /* If we were able to save the initial working directory,
222              then we can use chdir to change into each directory before
223              creating an entry in that directory.  This avoids making
224              mkdir process O(n^2) file name components.  */
225           if (do_chdir)
226             {
227               /* If we know that basename_dir is a directory (because we've
228                  just created it), then ensure that when we change to it,
229                  that final component is not a symlink.  Otherwise, we must
230                  accept the possibility that basename_dir is a preexisting
231                  symlink-to-directory and chdir through the symlink.  */
232               if ((dir_known_to_exist
233                    ? chdir_no_follow (basename_dir)
234                    : chdir (basename_dir)) == 0)
235                 dir_known_to_exist = true;
236               else if (dir_known_to_exist)
237                 {
238                   error (0, errno, _("cannot chdir to directory %s"),
239                          quote (dir));
240                   retval = false;
241                   break;
242                 }
243             }
244           else if (!dir_known_to_exist)
245             dir_known_to_exist = (stat (basename_dir, &stats) == 0
246                                   && S_ISDIR (stats.st_mode));
247
248           if (!dir_known_to_exist)
249             {
250               error (0, mkdir_errno, _("cannot create directory %s"),
251                      quote (dir));
252               retval = false;
253               break;
254             }
255
256           *slash++ = '/';
257
258           /* Avoid unnecessary calls to mkdir when given
259              file names containing multiple adjacent slashes.  */
260           while (*slash == '/')
261             slash++;
262         }
263
264       if (!do_chdir)
265         basename_dir = dir;
266
267       /* Done creating leading directories.  Restore original umask.  */
268       umask (oldmask);
269
270       /* We're done making leading directories.
271          Create the final component of the file name.  */
272       if (retval)
273         {
274           bool dir_known_to_exist = (mkdir (basename_dir, mode) == 0);
275           int mkdir_errno = errno;
276           struct stat sbuf;
277
278           if ( ! dir_known_to_exist)
279             dir_known_to_exist = (stat (basename_dir, &sbuf) == 0
280                                   && S_ISDIR (sbuf.st_mode));
281
282           if ( ! dir_known_to_exist)
283             {
284               error (0, mkdir_errno,
285                      _("cannot create directory %s"), quote (dir));
286               retval = false;
287             }
288           else
289             {
290               if (verbose_fmt_string)
291                 error (0, 0, verbose_fmt_string, quote (dir));
292               fixup_permissions_dir = basename_dir;
293             }
294         }
295     }
296
297   if (fixup_permissions_dir)
298     {
299       /* chown must precede chmod because on some systems,
300          chown clears the set[ug]id bits for non-superusers,
301          resulting in incorrect permissions.
302          On System V, users can give away files with chown and then not
303          be able to chmod them.  So don't give files away.  */
304
305       if (owner != (uid_t) -1 || group != (gid_t) -1)
306         {
307           if (lchown (fixup_permissions_dir, owner, group) != 0
308 #ifdef AFS
309               && errno != EPERM
310 #endif
311               )
312             {
313               error (0, errno, _("cannot change owner and/or group of %s"),
314                      quote (full_dir));
315               retval = false;
316             }
317         }
318
319       /* The above chown may have turned off some permission bits in MODE.
320          Another reason we may have to use chmod here is that mkdir(2) is
321          required to honor only the file permission bits.  In particular,
322          it need not honor the `special' bits, so if MODE includes any
323          special bits, set them here.  */
324       if ((mode & ~S_IRWXUGO) && lchmod (fixup_permissions_dir, mode) != 0)
325         {
326           error (0, errno, _("cannot change permissions of %s"),
327                  quote (full_dir));
328           retval = false;
329         }
330     }
331
332   if (do_chdir)
333     {
334       if (restore_cwd (&cwd) != 0)
335         {
336           *cwd_errno = errno;
337           cwd_problem = true;
338         }
339       free_cwd (&cwd);
340     }
341
342   /* If the mode for leading directories didn't include owner "wx"
343      privileges, reset their protections to the correct value.  */
344   for (; leading_dirs != NULL; leading_dirs = leading_dirs->next)
345     {
346       leading_dirs->dirname_end[0] = '\0';
347       if ((cwd_problem && *full_dir != '/')
348           || lchmod (full_dir, parent_mode) != 0)
349         {
350           error (0, (cwd_problem ? 0 : errno),
351                  _("cannot change permissions of %s"), quote (full_dir));
352           retval = false;
353         }
354     }
355
356   return retval;
357 }