changeset 12262:29121a37225b

unlink, remove: detect FreeBSD bug 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>
author Eric Blake <ebb9@byu.net>
date Mon, 09 Nov 2009 10:44:08 -0700
parents e96aac709428
children c689d1419da9
files ChangeLog doc/posix-functions/remove.texi doc/posix-functions/unlink.texi m4/unlink.m4 tests/test-remove.c tests/test-unlink.h
diffstat 6 files changed, 43 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- 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
--- a/doc/posix-functions/remove.texi
+++ b/doc/posix-functions/remove.texi
@@ -11,7 +11,7 @@
 @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:
--- a/doc/posix-functions/unlink.texi
+++ b/doc/posix-functions/unlink.texi
@@ -9,8 +9,8 @@
 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:
--- a/m4/unlink.m4
+++ b/m4/unlink.m4
@@ -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_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])
--- a/tests/test-remove.c
+++ b/tests/test-remove.c
@@ -113,6 +113,19 @@
     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;
 }
--- a/tests/test-unlink.h
+++ b/tests/test-unlink.h
@@ -68,14 +68,17 @@
       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);