X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Funlinkat.c;h=008192e6d3fa8f72971d21b070b1c36e571be5fc;hb=c47e73f47733362996652ecbb683347920a183b6;hp=bf5d5b89634d90c28cbcc15c948c746f453c9a72;hpb=22d7496bac7d391faff10755b17889ecd2f604d4;p=gnulib.git diff --git a/lib/unlinkat.c b/lib/unlinkat.c index bf5d5b896..008192e6d 100644 --- a/lib/unlinkat.c +++ b/lib/unlinkat.c @@ -1,6 +1,6 @@ /* Work around unlinkat bugs on Solaris 9. - Copyright (C) 2009 Free Software Foundation, Inc. + Copyright (C) 2009-2010 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,7 +28,9 @@ #include "openat.h" -#undef unlinkat +#if HAVE_UNLINKAT + +# undef unlinkat /* unlinkat without AT_REMOVEDIR does not honor trailing / on Solaris 9. Solve it in a similar manner to unlink. */ @@ -46,32 +48,58 @@ rpl_unlinkat (int fd, char const *name, int flag) if (len && ISSLASH (name[len - 1])) { /* See the lengthy comment in unlink.c why we disobey the POSIX - rule of letting unlink("link-to-dir/") attempt to unlink a - directory. */ + rule of letting unlink("link-to-dir/") attempt to unlink a + directory. */ struct stat st; result = lstatat (fd, name, &st); if (result == 0) - { - /* Trailing NUL will overwrite the trailing slash. */ - char *short_name = malloc (len); - if (!short_name) - { - errno = EPERM; - return -1; - } - memcpy (short_name, name, len); - while (len && ISSLASH (short_name[len - 1])) - short_name[--len] = '\0'; - if (len && (lstatat (fd, short_name, &st) || S_ISLNK (st.st_mode))) - { - free (short_name); - errno = EPERM; - return -1; - } - free (short_name); - } + { + /* Trailing NUL will overwrite the trailing slash. */ + char *short_name = malloc (len); + if (!short_name) + { + errno = EPERM; + return -1; + } + memcpy (short_name, name, len); + while (len && ISSLASH (short_name[len - 1])) + short_name[--len] = '\0'; + if (len && (lstatat (fd, short_name, &st) || S_ISLNK (st.st_mode))) + { + free (short_name); + errno = EPERM; + return -1; + } + free (short_name); + } } if (!result) result = unlinkat (fd, name, flag); return result; } + +#else /* !HAVE_UNLINKAT */ + +/* Replacement for Solaris' function by the same name. + + First, try to simulate it via (unlink|rmdir) ("/proc/self/fd/FD/FILE"). + Failing that, simulate it via save_cwd/fchdir/(unlink|rmdir)/restore_cwd. + If either the save_cwd or the restore_cwd fails (relatively unlikely), + then give a diagnostic and exit nonzero. + Otherwise, this function works just like Solaris' unlinkat. */ + +# define AT_FUNC_NAME unlinkat +# define AT_FUNC_F1 rmdir +# define AT_FUNC_F2 unlink +# define AT_FUNC_USE_F1_COND AT_REMOVEDIR +# define AT_FUNC_POST_FILE_PARAM_DECLS , int flag +# define AT_FUNC_POST_FILE_ARGS /* empty */ +# include "at-func.c" +# undef AT_FUNC_NAME +# undef AT_FUNC_F1 +# undef AT_FUNC_F2 +# undef AT_FUNC_USE_F1_COND +# undef AT_FUNC_POST_FILE_PARAM_DECLS +# undef AT_FUNC_POST_FILE_ARGS + +#endif /* !HAVE_UNLINKAT */