bug-coreutils
[Top][All Lists]
Advanced

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

Re: [bug #14848] [5.92 regression] "mkdir -p nonexistent/." fails


From: Jim Meyering
Subject: Re: [bug #14848] [5.92 regression] "mkdir -p nonexistent/." fails
Date: Mon, 24 Oct 2005 12:31:54 +0200

Thanks for the quick report!
I've just fixed it with the patch below.
I will add a test, too, of course.

Matthias Andree <address@hidden> wrote:
> URL:
>   <http://savannah.gnu.org/bugs/?func=detailitem&item_id=14848>
...
> Details:
>
> As of coreutils 5.92, there is a regression over previous versions:
>
> $ rm -rf /tmp/test$$
> # this fails:
> $ mkdir -p /tmp/test$$/new/.
> mkdir: cannot create directory `/tmp/test12097/new/.': File exists
> # it works however if the directory exists
> $ mkdir -p /tmp/test$$/new/.    # now works as new exists
>
> The first mkdir -p command shown used to work with older coreutils, and there
> is no reason why it should fail today.

2005-10-24  Jim Meyering  <address@hidden>

        * mkdir-p.c (make_dir_parents): Make the preceding fix a little
        more robust, e.g., when the final component is created as a non-
        directory by another process just before `mkdir -p's final mkdir.

        A command like `mkdir -p nonexistent/.' would create the
        directory but exit nonzero with a diagnostic.  This could also be
        triggered with a non-`.' component, e.g., in a race with another
        process running the same `mkdir -p nonexistent/sub' command.

        * mkdir-p.c (make_dir_parents): Handle the case of an
        existing final component.
        Reported by Matthias Andree here:
        http://savannah.gnu.org/bugs/?func=detailitem&item_id=14848

Index: lib/mkdir-p.c
===================================================================
RCS file: /fetish/cu/lib/mkdir-p.c,v
retrieving revision 1.12
retrieving revision 1.14
diff -u -p -r1.12 -r1.14
--- lib/mkdir-p.c       13 Oct 2005 19:05:13 -0000      1.12
+++ lib/mkdir-p.c       24 Oct 2005 10:22:10 -0000      1.14
@@ -264,17 +264,42 @@ make_dir_parents (char const *arg,
         Create the final component of the file name.  */
       if (retval)
        {
-         if (mkdir (basename_dir, mode) != 0)
-           {
-             error (0, errno, _("cannot create directory %s"), quote (dir));
-             retval = false;
-           }
-         else
+         bool just_created = (mkdir (basename_dir, mode) == 0);
+         if (just_created)
            {
              if (verbose_fmt_string)
                error (0, 0, verbose_fmt_string, quote (dir));
              fixup_permissions_dir = basename_dir;
            }
+         else
+           {
+             if (errno != EEXIST)
+               {
+                 error (0, errno, _("cannot create directory %s"), quote 
(dir));
+                 retval = false;
+               }
+             else
+               {
+                 /* basename_dir exists.
+                    This is highly unlikely, but not impossible in a race.
+                    You can exercise this code by running a very slow
+                    mkdir -p a/nonexistent/c process and e.g., running
+                    touch a/nonexistent/c after a/nonexistent is created
+                    but before mkdir attempts to create `c'.
+
+                    If it's a directory, we're done.
+                    Otherwise, we must fail.  */
+                 struct stat sbuf;
+                 /* The stat may fail for a dangling link.  */
+                 if (stat (basename_dir, &sbuf) != 0
+                     || ! S_ISDIR (sbuf.st_mode))
+                   {
+                     error (0, 0, _("%s exists but is not a directory"),
+                            quote (basename_dir));
+                     retval = false;
+                   }
+               }
+           }
        }
     }
 




reply via email to

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