bug-coreutils
[Top][All Lists]
Advanced

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

Re: new snapshot available: coreutils-7.6.63-addb6


From: Eric Blake
Subject: Re: new snapshot available: coreutils-7.6.63-addb6
Date: Sun, 04 Oct 2009 09:09:17 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.23) Gecko/20090812 Thunderbird/2.0.0.23 Mnenhy/0.7.6.666

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

According to Eric Blake on 10/4/2009 8:29 AM:
>> If you feel like addressing that right away, that would
>> be great.  Otherwise, I think it's safe to say that no one
>> will complain if it is deferred until 8.1.
> 
> At this point, it's enough of a corner case that I'm okay deferring any
> mkdir(1) (or even mkdir(2) cleanups in gnulib) until after coreutils 8.0.

For the record, I tried the quick hack below to change things in just
coreutils for 'mkdir -p' (without even touching plain 'mkdir' for Linux),
all without modifying gnulib.  But it still fails on Solaris, because
gnulib's make_dir_parents fails on savewd_chdir if the trailing slash is
not present on a symlink to a directory.  So since fixing this requires
gnulib tweaks, and is more invasive than I originally suspected, I'd feel
more comfortable waiting for the Austin group ruling on mkdir -p before
changing any behavior.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkrIupwACgkQ84KuGfSFAYAdMgCgj7tYc5uetn1VADy+ENvlRnro
1YUAnjrNYenWD/EZ6dqlPGCiNY/qJi9V
=yJGI
-----END PGP SIGNATURE-----
diff --git a/NEWS b/NEWS
index aff0744..fe287f6 100644
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,9 @@ GNU coreutils NEWS                                    -*- 
outline -*-
   id no longer prints SELinux " context=..." when the POSIXLY_CORRECT
   environment variable is set.

+  mkdir now reliably creates a directory through a dangling symlink
+  given with a trailing slash.
+
   readlink -f now ignores a trailing slash when deciding if the
   last component (possibly via a dangling symlink) can be created,
   since mkdir will succeed in that case.
diff --git a/src/mkdir.c b/src/mkdir.c
index 756cc40..ffdc0b1 100644
--- a/src/mkdir.c
+++ b/src/mkdir.c
@@ -29,6 +29,7 @@
 #include "prog-fprintf.h"
 #include "quote.h"
 #include "savewd.h"
+#include "canonicalize.h"

 /* The official name of this program (e.g., no `g' prefix).  */
 #define PROGRAM_NAME "mkdir"
@@ -105,6 +106,36 @@ announce_mkdir (char const *dir, void *options)
     prog_fprintf (stdout, o->created_directory_format, quote (dir));
 }

+/* Create an ancestor directory DIR with the given MODE.  If DIR is a
+   symlink, guarantee the POSIX semantics as if we had called
+   mkdir(DIR/).  */
+static int
+mkdir_follow (char const *dir, mode_t mode)
+{
+  int r = mkdir (dir, mode);
+  int saved_errno = errno;
+  if (r && saved_errno == EEXIST)
+    {
+      /* If "dir" is a dangling symlink, create a directory at the
+         location pointed to by the link so that "dir/" will
+         resolve.  */
+      struct stat st;
+      if (stat (dir, &st) == -1 && errno == ENOENT)
+        {
+          char *target = canonicalize_filename_mode (dir, CAN_ALL_BUT_LAST);
+          if (target)
+            {
+              int saved_errno;
+              r = mkdir (target, mode);
+              saved_errno = errno;
+              free (target);
+            }
+        }
+    }
+  errno = saved_errno;
+  return r;
+}
+
 /* Make ancestor directory DIR, whose last component is COMPONENT,
    with options OPTIONS.  Assume the working directory is COMPONENT's
    parent.  Return 0 if successful and the resulting directory is
@@ -114,7 +145,7 @@ static int
 make_ancestor (char const *dir, char const *component, void *options)
 {
   struct mkdir_options const *o = options;
-  int r = mkdir (component, o->ancestor_mode);
+  int r = mkdir_follow (component, o->ancestor_mode);
   if (r == 0)
     {
       r = ! (o->ancestor_mode & S_IRUSR);
diff --git a/tests/mkdir/p-thru-slink b/tests/mkdir/p-thru-slink
index 30df4fe..a1e792a 100755
--- a/tests/mkdir/p-thru-slink
+++ b/tests/mkdir/p-thru-slink
@@ -24,9 +24,14 @@ fi
 . $srcdir/test-lib.sh

 ln -s . slink || framework_failure
+ln -s dir slink2 || framework_failure

 fail=0
 mkdir -p slink/x || fail=1
 test -d x || fail=1

+# This test failed on GNU/Linux through coreutils 7.6.
+mkdir -p slink2/x || fail=1
+test -d dir/x || fail=1
+
 Exit $fail
diff --git a/tests/mkdir/t-slash b/tests/mkdir/t-slash
index 3214bf4..128fecd 100755
--- a/tests/mkdir/t-slash
+++ b/tests/mkdir/t-slash
@@ -33,4 +33,9 @@ test -d dir || fail=1
 mkdir d2/ || fail=1
 test -d d2 || fail=1

+# This test failed on GNU/Linux through coreutils 7.6.
+ln -s d3 link || framework_failure
+mkdir link/ || fail=1
+test -d d3 || fail=1
+
 Exit $fail

reply via email to

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