bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: mkdir -p and EROFS


From: Paul Eggert
Subject: Re: mkdir -p and EROFS
Date: Wed, 12 Oct 2005 14:24:09 -0700
User-agent: Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux)

address@hidden (Eric Blake) writes:

> The algorithm change between 5.3.0 and 5.90 in lib/mkdir-p.c to
> try mkdir() first instead of stat(), and key off of EEXIST, breaks
> when mkdir() fails with EROFS on an intermediate directory when
> the writable directory has been mounted inside a read-only tree.

Thanks for reporting this.  It is indeed a bug in
coreutils/lib/mkdir-p.c.  It can be triggered by other errors too.
This is hard to write a test case for, but I'd like to fix things.
Does the following patch work for you?

Jim, if this works for Eric, is it OK to install this patch at this late
date?

2005-10-12  Paul Eggert  <address@hidden>

        * mkdir-p.c (make_dir_parents): Don't fail if an intervening mkdir
        fails due to EROFS, or due to EEXIST or other reasons for that matter.
        Problem reported by Eric Blake.
        (ENOSYS): Remove; no longer needed.

--- mkdir-p.c.~1.11.~   2005-09-21 22:42:26.000000000 -0700
+++ mkdir-p.c   2005-10-12 14:21:22.000000000 -0700
@@ -45,10 +45,6 @@
 #include "quote.h"
 #include "stat-macros.h"
 
-#ifndef ENOSYS
-# define ENOSYS EEXIST
-#endif
-
 #define WX_USR (S_IWUSR | S_IXUSR)
 
 /* Ensure that the directory ARG exists.
@@ -175,6 +171,9 @@ make_dir_parents (char const *arg,
 
       while (true)
        {
+         bool dir_known_to_exist;
+         int mkdir_errno;
+
          /* slash points to the leftmost unprocessed component of dir.  */
          basename_dir = slash;
 
@@ -188,7 +187,10 @@ make_dir_parents (char const *arg,
            basename_dir = dir;
 
          *slash = '\0';
-         if (mkdir (basename_dir, tmp_mode) == 0)
+         dir_known_to_exist = (mkdir (basename_dir, tmp_mode) == 0);
+         mkdir_errno = errno;
+
+         if (dir_known_to_exist)
            {
              if (verbose_fmt_string)
                error (0, 0, verbose_fmt_string, quote (dir));
@@ -215,29 +217,30 @@ make_dir_parents (char const *arg,
                  leading_dirs = new;
                }
            }
-         else if (errno == EEXIST || errno == ENOSYS)
-           {
-             /* A file is already there.  Perhaps it is a directory.
-                If not, it will be diagnosed later.
-
-                The ENOSYS is for Solaris 8 NFS clients, which can
-                fail with errno == ENOSYS if mkdir is invoked on an
-                NFS mount point.  */
-           }
-         else
-           {
-             error (0, errno, _("cannot create directory %s"), quote (dir));
-             retval = false;
-             break;
-           }
 
          /* If we were able to save the initial working directory,
             then we can use chdir to change into each directory before
             creating an entry in that directory.  This avoids making
             mkdir process O(n^2) file name components.  */
-         if (do_chdir && chdir (basename_dir) < 0)
+         if (do_chdir)
+           {
+             if (chdir (basename_dir) == 0)
+               dir_known_to_exist = true;
+             else if (dir_known_to_exist)
+               {
+                 error (0, errno, _("cannot chdir to directory %s"),
+                        quote (dir));
+                 retval = false;
+                 break;
+               }
+           }
+         else if (!dir_known_to_exist)
+           dir_known_to_exist = (stat (basename_dir, &stats) == 0
+                                 && S_ISDIR (stats.st_mode));
+
+         if (!dir_known_to_exist)
            {
-             error (0, errno, _("cannot chdir to directory %s"),
+             error (0, mkdir_errno, _("cannot create directory %s"),
                     quote (dir));
              retval = false;
              break;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]