2007-01-08 Bruno Haible <bruno@clisp.org>
[gnulib.git] / lib / mkdir-p.c
index f097e67..a927d5d 100644 (file)
 
 #include <errno.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-#include "dirchownmod.c"
+#include "dirchownmod.h"
 #include "dirname.h"
 #include "error.h"
 #include "quote.h"
 #include "mkancesdirs.h"
 #include "savewd.h"
-#include "stat-macros.h"
+
+#ifndef HAVE_FCHMOD
+# define HAVE_FCHMOD false
+#endif
 
 /* Ensure that the directory DIR exists.
 
    WD is the working directory, as in savewd.c.
 
    If MAKE_ANCESTOR is not null, create any ancestor directories that
-   don't already exist, by invoking MAKE_ANCESTOR (ANCESTOR, OPTIONS).
+   don't already exist, by invoking MAKE_ANCESTOR (DIR, ANCESTOR, OPTIONS).
    This function should return zero if successful, -1 (setting errno)
    otherwise.  In this case, DIR may be modified by storing '\0' bytes
    into it, to access the ancestor directories, and this modification
@@ -82,7 +86,7 @@
 bool
 make_dir_parents (char *dir,
                  struct savewd *wd,
-                 int (*make_ancestor) (char const *, void *),
+                 int (*make_ancestor) (char const *, char const *, void *),
                  void *options,
                  mode_t mode,
                  void (*announce) (char const *, void *),
@@ -111,7 +115,14 @@ make_dir_parents (char *dir,
 
       if (0 <= prefix_len)
        {
-         if (mkdir (dir + prefix_len, mode) == 0)
+         /* If the ownership will change, create the directory with
+            more restrictive permissions at first, so unauthorized
+            users cannot nip in before the directory is ready.  */
+         mode_t mkdir_mode = mode;
+         if (! (owner == (uid_t) -1 && group == (gid_t) -1))
+           mkdir_mode &= S_IRWXU;
+
+         if (mkdir (dir + prefix_len, mkdir_mode) == 0)
            {
              announce (dir, options);
              preserve_existing =
@@ -122,7 +133,10 @@ make_dir_parents (char *dir,
                 | (mode & S_IRUSR ? SAVEWD_CHDIR_READABLE : 0));
            }
          else
-           mkdir_errno = errno;
+           {
+             mkdir_errno = errno;
+             mkdir_mode = -1;
+           }
 
          if (preserve_existing)
            {
@@ -159,7 +173,6 @@ make_dir_parents (char *dir,
                    }
                  else
                    {
-                     mode_t mkdir_mode = (mkdir_errno == 0 ? mode : -1);
                      char const *subdir = (chdir_ok ? "." : dir + prefix_len);
                      if (dirchownmod (fd, subdir, mkdir_mode, owner, group,
                                       mode, mode_bits)