unlink, remove: detect FreeBSD bug
authorEric Blake <ebb9@byu.net>
Mon, 9 Nov 2009 17:44:08 +0000 (10:44 -0700)
committerIan Beckwith <ianb@erislabs.net>
Sun, 15 Nov 2009 02:50:23 +0000 (02:50 +0000)
unlink("link-to-file/") mistakenly removed "file".

* m4/unlink.m4 (gl_FUNC_UNLINK): Also detect FreeBSD bug with
slash on symlink.
* doc/posix-functions/unlink.texi (unlink): Document the bug.
* doc/posix-functions/remove.texi (remove): Likewise.
* tests/test-unlink.h (test_unlink): Enhance test.
* tests/test-remove.c (main): Likewise.

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

ChangeLog
doc/posix-functions/remove.texi
doc/posix-functions/unlink.texi
m4/unlink.m4
tests/test-remove.c
tests/test-unlink.h

index 599a2ab..8d3dcea 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2009-11-10  Eric Blake  <ebb9@byu.net>
+
+       unlink, remove: detect FreeBSD bug
+       * m4/unlink.m4 (gl_FUNC_UNLINK): Also detect FreeBSD bug with
+       slash on symlink.
+       * doc/posix-functions/unlink.texi (unlink): Document the bug.
+       * doc/posix-functions/remove.texi (remove): Likewise.
+       * tests/test-unlink.h (test_unlink): Enhance test.
+       * tests/test-remove.c (main): Likewise.
+
 2009-11-09  Eric Blake  <ebb9@byu.net>
 
        rename: detect FreeBSD bug
index b3e3d1b..83a8955 100644 (file)
@@ -11,7 +11,7 @@ Portability problems fixed by Gnulib:
 @item
 This function fails to reject trailing slashes on non-directories on
 some platforms:
-Solaris 9.
+FreeBSD 7.2, Solaris 9.
 @item
 This function mistakenly removes a directory with
 @code{remove("dir/./")} on some platforms:
index 1df1e30..42b9e81 100644 (file)
@@ -9,8 +9,8 @@ Gnulib module: unlink
 Portability problems fixed by Gnulib:
 @itemize
 @item
-Some systems mistakenly succeed on @code{unlink("file/")}:
-GNU/Hurd, Solaris 9.
+Some systems mistakenly succeed on @code{unlink("link-to-file/")}:
+GNU/Hurd, FreeBSD 7.2, Solaris 9.
 @end itemize
 
 Portability problems not fixed by Gnulib:
index 626c3ad..bed2466 100644 (file)
@@ -1,4 +1,4 @@
-# unlink.m4 serial 1
+# unlink.m4 serial 2
 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,
@@ -8,18 +8,26 @@ AC_DEFUN([gl_FUNC_UNLINK],
 [
   AC_REQUIRE([gl_AC_DOS])
   AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
-  dnl Detect Solaris 9 bug.
+  dnl Detect Solaris 9 and FreeBSD 7.2 bug.
   AC_CACHE_CHECK([whether unlink honors trailing slashes],
     [gl_cv_func_unlink_works],
     [touch conftest.file
+     # Assume that if we have lstat, we can also check symlinks.
+     if test $ac_cv_func_lstat = yes; then
+       ln -s conftest.file conftest.lnk
+     fi
      AC_RUN_IFELSE(
        [AC_LANG_PROGRAM(
          [[#include <stdio.h>
            #include <errno.h>
-]], [[return !unlink ("conftest.file/") || errno != ENOTDIR;]])],
+]], [[if (!unlink ("conftest.file/") || errno != ENOTDIR) return 1;
+#if HAVE_LSTAT
+      if (!unlink ("conftest.lnk/") || errno != ENOTDIR) return 2;
+#endif
+      ]])],
       [gl_cv_func_unlink_works=yes], [gl_cv_func_unlink_works=no],
       [gl_cv_func_unlink_works="guessing no"])
-     rm -f conftest.file])
+     rm -f conftest.file conftest.lnk])
   if test x"$gl_cv_func_unlink_works" != xyes; then
     REPLACE_UNLINK=1
     AC_LIBOBJ([unlink])
index af5d01b..16bfe2f 100644 (file)
@@ -113,6 +113,19 @@ main (void)
     ASSERT (S_ISLNK (st.st_mode));
   }
   ASSERT (remove (BASE "link") == 0);
+  /* Trailing slash on symlink to non-directory is an error.  */
+  ASSERT (symlink (BASE "loop", BASE "loop") == 0);
+  errno = 0;
+  ASSERT (remove (BASE "loop/") == -1);
+  ASSERT (errno == ELOOP || errno == ENOTDIR);
+  ASSERT (remove (BASE "loop") == 0);
+  ASSERT (close (creat (BASE "file", 0600)) == 0);
+  ASSERT (symlink (BASE "file", BASE "link") == 0);
+  errno = 0;
+  ASSERT (remove (BASE "link/") == -1);
+  ASSERT (errno == ENOTDIR);
+  ASSERT (remove (BASE "link") == 0);
+  ASSERT (remove (BASE "file") == 0);
 
   return 0;
 }
index 6b6384e..e65057d 100644 (file)
@@ -68,14 +68,17 @@ test_unlink_func (int (*func) (char const *name), bool print)
       ASSERT (func (BASE "dir/file") == 0);
       ASSERT (rmdir (BASE "dir") == 0);
       if (print)
-       fputs ("skipping test: symlinks not supported on this file system\n",
-              stderr);
+        fputs ("skipping test: symlinks not supported on this file system\n",
+               stderr);
       return 77;
     }
   if (cannot_unlink_dir ())
     ASSERT (func (BASE "link/") == -1);
   ASSERT (func (BASE "link") == 0);
   ASSERT (symlink (BASE "dir/file", BASE "link") == 0);
+  errno = 0;
+  ASSERT (func (BASE "link/") == -1);
+  ASSERT (errno == ENOTDIR);
   /* Order here proves unlink of a symlink does not follow through to
      the file.  */
   ASSERT (func (BASE "link") == 0);