link: detect FreeBSD bug
authorEric Blake <ebb9@byu.net>
Mon, 9 Nov 2009 21:23:11 +0000 (14:23 -0700)
committerIan Beckwith <ianb@erislabs.net>
Sun, 15 Nov 2009 02:50:32 +0000 (02:50 +0000)
link("link-to-file/","a") mistakenly created "a" as a link to "file".

* m4/link.m4 (gl_FUNC_LINK): Also detect FreeBSD bug with slash on
symlink.
* doc/posix-functions/link.texi (link): Document the bug.
* tests/test-link.h (test_link): Enhance test.
* tests/test-linkat.c (main): Update caller.

Signed-off-by: Eric Blake <ebb9@byu.net>
(cherry picked from commit 492960c3a5eaaae32cd9d69d6fd5d7fdf96cbb78)

ChangeLog
doc/posix-functions/link.texi
m4/link.m4
tests/test-link.h
tests/test-linkat.c

index 8d3dcea..8863561 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2009-11-10  Eric Blake  <ebb9@byu.net>
 
+       link: detect FreeBSD bug
+       * m4/link.m4 (gl_FUNC_LINK): Also detect FreeBSD bug with slash on
+       symlink.
+       * doc/posix-functions/link.texi (link): Document the bug.
+       * tests/test-link.h (test_link): Enhance test.
+       * tests/test-linkat.c (main): Update caller.
+
        unlink, remove: detect FreeBSD bug
        * m4/unlink.m4 (gl_FUNC_UNLINK): Also detect FreeBSD bug with
        slash on symlink.
index c06f0a6..6279fe8 100644 (file)
@@ -14,7 +14,7 @@ mingw.
 @item
 This function fails to reject trailing slashes on non-directories on
 some platforms:
-Solaris, Cygwin 1.5.x.
+FreeBSD 7.2, Solaris, Cygwin 1.5.x.
 @end itemize
 
 Portability problems not fixed by Gnulib:
index a212ee2..d5fcef9 100644 (file)
@@ -1,4 +1,4 @@
-# link.m4 serial 3
+# link.m4 serial 4
 dnl Copyright (C) 2009 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -15,13 +15,21 @@ AC_DEFUN([gl_FUNC_LINK],
     AC_CACHE_CHECK([whether link handles trailing slash correctly],
       [gl_cv_func_link_works],
       [touch conftest.a
+       # Assume that if we have lstat, we can also check symlinks.
+       if test $ac_cv_func_lstat = yes; then
+         ln -s conftest.a conftest.lnk
+       fi
        AC_RUN_IFELSE(
          [AC_LANG_PROGRAM(
            [[#include <unistd.h>
-]], [[return !link ("conftest.a", "conftest.b/");]])],
+]], [[if (!link ("conftest.a", "conftest.b/")) return 1;
+#if HAVE_LSTAT
+      if (!link ("conftest.lnk/", "conftest.b")) return 2;
+#endif
+           ]])],
          [gl_cv_func_link_works=yes], [gl_cv_func_link_works=no],
          [gl_cv_func_link_works="guessing no"])
-       rm -f conftest.a conftest.b])
+       rm -f conftest.a conftest.b conftest.lnk])
     if test "$gl_cv_func_link_works" != yes; then
       REPLACE_LINK=1
       AC_LIBOBJ([link])
index 363097d..0d58262 100644 (file)
@@ -18,8 +18,8 @@
    linkat(AT_FDCWD,a,AT_FDCWD,b,0).  FUNC is the function to test.
    Assumes that BASE and ASSERT are already defined, and that
    appropriate headers are already included.  If PRINT, warn before
-   skipping tests with status 77.  This test does not exercise link on
-   symlinks.  */
+   skipping tests with status 77.  This test does not try to create
+   hard links to symlinks, but does test other aspects of symlink.  */
 
 static int
 test_link (int (*func) (char const *, char const *), bool print)
@@ -145,14 +145,32 @@ test_link (int (*func) (char const *, char const *), bool print)
         ASSERT (errno == EPERM || errno == EACCES || errno == EINVAL);
       }
   }
-
-  /* Clean up.  */
   ASSERT (unlink (BASE "a") == 0);
-  ASSERT (unlink (BASE "b") == 0);
   errno = 0;
   ASSERT (unlink (BASE "c") == -1);
   ASSERT (errno == ENOENT);
   ASSERT (rmdir (BASE "d") == 0);
 
+  /* Test invalid use of symlink.  */
+  if (symlink (BASE "a", BASE "link") != 0)
+    {
+      ASSERT (unlink (BASE "b") == 0);
+      if (print)
+        fputs ("skipping test: symlinks not supported on this file system\n",
+               stderr);
+      return 77;
+    }
+  errno = 0;
+  ASSERT (func (BASE "b", BASE "link/") == -1);
+  ASSERT (errno == ENOTDIR || errno == ENOENT || errno == EEXIST);
+  ASSERT (rename (BASE "b", BASE "a") == 0);
+  errno = 0;
+  ASSERT (func (BASE "link/", BASE "b") == -1);
+  ASSERT (errno == ENOTDIR || errno == EEXIST);
+
+  /* Clean up.  */
+  ASSERT (unlink (BASE "a") == 0);
+  ASSERT (unlink (BASE "link") == 0);
+
   return 0;
 }
index b06b318..11233fe 100644 (file)
   do                                                                         \
     {                                                                        \
       if (!(expr))                                                           \
-       {                                                                    \
-         fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
-         fflush (stderr);                                                   \
-         abort ();                                                          \
-       }                                                                    \
+        {                                                                    \
+          fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__);  \
+          fflush (stderr);                                                   \
+          abort ();                                                          \
+        }                                                                    \
     }                                                                        \
   while (0)
 
@@ -92,7 +92,7 @@ main (void)
   ASSERT (system ("rm -rf " BASE "*") == 0);
 
   /* Test basic link functionality, without mentioning symlinks.  */
-  result = test_link (do_link, false);
+  result = test_link (do_link, true);
   dfd1 = open (".", O_RDONLY);
   ASSERT (0 <= dfd1);
   ASSERT (test_link (do_link, false) == result);
@@ -166,8 +166,9 @@ main (void)
       ASSERT (rmdir (BASE "sub1") == 0);
       ASSERT (rmdir (BASE "sub2") == 0);
       free (cwd);
-      fputs ("skipping test: symlinks not supported on this file system\n",
-             stderr);
+      if (!result)
+        fputs ("skipping test: symlinks not supported on this file system\n",
+               stderr);
       return result;
     }
   dfd = open (".", O_RDONLY);