From 24c30abb7272d5085391388fff826226b525954d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Mon, 9 Nov 2009 14:23:11 -0700 Subject: [PATCH] link: detect FreeBSD bug 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 (cherry picked from commit 492960c3a5eaaae32cd9d69d6fd5d7fdf96cbb78) --- ChangeLog | 7 +++++++ doc/posix-functions/link.texi | 2 +- m4/link.m4 | 14 +++++++++++--- tests/test-link.h | 28 +++++++++++++++++++++++----- tests/test-linkat.c | 17 +++++++++-------- 5 files changed, 51 insertions(+), 17 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8d3dcea35..8863561b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2009-11-10 Eric Blake + 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. diff --git a/doc/posix-functions/link.texi b/doc/posix-functions/link.texi index c06f0a6ce..6279fe83a 100644 --- a/doc/posix-functions/link.texi +++ b/doc/posix-functions/link.texi @@ -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: diff --git a/m4/link.m4 b/m4/link.m4 index a212ee266..d5fcef9dc 100644 --- a/m4/link.m4 +++ b/m4/link.m4 @@ -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 -]], [[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]) diff --git a/tests/test-link.h b/tests/test-link.h index 363097d4c..0d5826203 100644 --- a/tests/test-link.h +++ b/tests/test-link.h @@ -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; } diff --git a/tests/test-linkat.c b/tests/test-linkat.c index b06b3189f..11233fe13 100644 --- a/tests/test-linkat.c +++ b/tests/test-linkat.c @@ -36,11 +36,11 @@ 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); -- 2.11.0