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