From 12107b837dd1b31678c9e14923ac989bad91a92d Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sat, 20 Mar 2010 15:26:42 +0100 Subject: [PATCH] Work around unlink() bug on MacOS X 10.5.6. --- ChangeLog | 10 +++++ doc/posix-functions/unlink.texi | 3 ++ lib/unlink.c | 12 +++++- m4/unlink.m4 | 71 ++++++++++++++++++++++++++++++--- 4 files changed, 90 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4270e21efa..cbb11e5a55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2010-03-20 Bruno Haible + + Work around unlink() bug on MacOS X 10.5.6. + * lib/unlink.c (rpl_unlink): If UNLINK_PARENT_BUG is defined, fail when + attempting to unlink a parent directory. + * m4/unlink.m4 (gl_FUNC_UNLINK): Require AC_CANONICAL_HOST. Test for + MacOS X 10.5 bug. If the bug is present, define UNLINK_PARENT_BUG and + activate for the replacement function. + * doc/posix-functions/unlink.texi: Mention the MacOS X 10.5 bug. + 2010-03-20 Bruno Haible Fix link errors on Solaris 8. diff --git a/doc/posix-functions/unlink.texi b/doc/posix-functions/unlink.texi index 42b9e817e5..50d45acc6b 100644 --- a/doc/posix-functions/unlink.texi +++ b/doc/posix-functions/unlink.texi @@ -11,6 +11,9 @@ Portability problems fixed by Gnulib: @item Some systems mistakenly succeed on @code{unlink("link-to-file/")}: GNU/Hurd, FreeBSD 7.2, Solaris 9. +@item +On MacOS X 10.5.6, in a writable HFS mount, @code{unlink("..")} succeeds +without doing anything. @end itemize Portability problems not fixed by Gnulib: diff --git a/lib/unlink.c b/lib/unlink.c index 3e42e28692..8d53b11db6 100644 --- a/lib/unlink.c +++ b/lib/unlink.c @@ -80,6 +80,16 @@ rpl_unlink (char const *name) } } if (!result) - result = unlink (name); + { +#if UNLINK_PARENT_BUG + if (len >= 2 && name[len - 1] == '.' && name[len - 2] == '.' + && (len == 2 || ISSLASH (name[len - 3]))) + { + errno = EISDIR; /* could also use EPERM */ + return -1; + } +#endif + result = unlink (name); + } return result; } diff --git a/m4/unlink.m4 b/m4/unlink.m4 index c01d848285..01f2aabf4d 100644 --- a/m4/unlink.m4 +++ b/m4/unlink.m4 @@ -1,4 +1,4 @@ -# unlink.m4 serial 3 +# unlink.m4 serial 4 dnl Copyright (C) 2009, 2010 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,9 +8,10 @@ AC_DEFUN([gl_FUNC_UNLINK], [ AC_REQUIRE([gl_AC_DOS]) AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl Detect Solaris 9 and FreeBSD 7.2 bug. AC_CACHE_CHECK([whether unlink honors trailing slashes], - [gl_cv_func_unlink_works], + [gl_cv_func_unlink_honors_slashes], [touch conftest.file # Assume that if we have lstat, we can also check symlinks. if test $ac_cv_func_lstat = yes; then @@ -25,10 +26,70 @@ AC_DEFUN([gl_FUNC_UNLINK], 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"]) + [gl_cv_func_unlink_honors_slashes=yes], + [gl_cv_func_unlink_honors_slashes=no], + [gl_cv_func_unlink_honors_slashes="guessing no"]) rm -f conftest.file conftest.lnk]) - if test x"$gl_cv_func_unlink_works" != xyes; then + dnl Detect MacOS X 10.5.6 bug: On read-write HFS mounts, unlink("..") or + dnl unlink("../..") succeeds without doing anything. + AC_CACHE_CHECK([whether unlink of a parent directory fails is it should], + [gl_cv_func_unlink_parent_fails], + [case "$host_os" in + darwin*) + if { + # Use the mktemp program if available. If not available, hide the error + # message. + tmp=`(umask 077 && mktemp -d /tmp/gtXXXXXX) 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" + } || + { + # Use a simple mkdir command. It is guaranteed to fail if the directory + # already exists. $RANDOM is bash specific and expands to empty in shells + # other than bash, ksh and zsh. Its use does not increase security; + # rather, it minimizes the probability of failure in a very cluttered /tmp + # directory. + tmp=/tmp/gt$$-$RANDOM + (umask 077 && mkdir "$tmp") + }; then + mkdir "$tmp/subdir" + export tmp + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #include + #include + int main () + { + if (chdir (getenv ("tmp")) != 0) + return 1; + return unlink ("..") == 0; + } + ]])], + [gl_cv_func_unlink_parent_fails=yes], + [gl_cv_func_unlink_parent_fails=no], + [gl_cv_func_unlink_parent_fails="guessing no"]) + rm -rf "$tmp" + unset tmp + else + gl_cv_func_unlink_parent_fails="guessing no" + fi + ;; + *) + gl_cv_func_unlink_parent_fails="guessing yes" + ;; + esac + ]) + case "$gl_cv_func_unlink_parent_fails" in + *no) + AC_DEFINE([UNLINK_PARENT_BUG], [1], + [Define to 1 if unlink() on a parent directory may succeed]) + ;; + esac + if test "$gl_cv_func_unlink_honors_slashes" != yes \ + || { case "$gl_cv_func_unlink_parent_fails" in + *yes) false;; + *no) true;; + esac + }; then REPLACE_UNLINK=1 AC_LIBOBJ([unlink]) fi -- 2.30.2