Mercurial > hg > octave-nkf > gnulib-hg
changeset 12041:73e9ab6e2c90
remove: new module, for mingw and Solaris 9 bugs
Mingw obeys C89, but not POSIX, by not handling directories.
Solaris remove("file/") mistakenly succeeded.
* modules/remove: New file.
* lib/remove.c: Likewise.
* m4/remove.m4 (gl_FUNC_REMOVE): Likewise.
* m4/stdio_h.m4 (gl_STDIO_H_DEFAULTS): Add witnesses.
* modules/stdio (Makefile.am): Use them.
* lib/stdio.in.h (remove): Declare replacement.
* MODULES.html.sh (systems lacking POSIX:2008): Mention module.
* doc/posix-functions/remove.texi (remove): Likewise.
* modules/remove-tests: New test.
* tests/test-remove.c: Likewise.
Signed-off-by: Eric Blake <ebb9@byu.net>
author | Eric Blake <ebb9@byu.net> |
---|---|
date | Mon, 14 Sep 2009 16:57:55 -0600 |
parents | e8108d5c7ca7 |
children | 42d53e82a460 |
files | ChangeLog MODULES.html.sh doc/posix-functions/remove.texi lib/remove.c lib/stdio.in.h m4/remove.m4 m4/stdio_h.m4 modules/remove modules/remove-tests modules/stdio tests/test-remove.c |
diffstat | 11 files changed, 288 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2009-09-19 Eric Blake <ebb9@byu.net> + remove: new module, for mingw and Solaris 9 bugs + * modules/remove: New file. + * lib/remove.c: Likewise. + * m4/remove.m4 (gl_FUNC_REMOVE): Likewise. + * m4/stdio_h.m4 (gl_STDIO_H_DEFAULTS): Add witnesses. + * modules/stdio (Makefile.am): Use them. + * lib/stdio.in.h (remove): Declare replacement. + * MODULES.html.sh (systems lacking POSIX:2008): Mention module. + * doc/posix-functions/remove.texi (remove): Likewise. + * modules/remove-tests: New test. + * tests/test-remove.c: Likewise. + unlink: new module, for Solaris 9 bug * modules/unlink: New file. * lib/unlink.c: Likewise.
--- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2319,6 +2319,7 @@ func_module realloc-posix func_module recv func_module recvfrom + func_module remove func_module sched func_module select func_module send
--- a/doc/posix-functions/remove.texi +++ b/doc/posix-functions/remove.texi @@ -4,10 +4,21 @@ POSIX specification: @url{http://www.opengroup.org/onlinepubs/9699919799/functions/remove.html} -Gnulib module: --- +Gnulib module: remove Portability problems fixed by Gnulib: @itemize +@item +This function fails to reject trailing slashes on non-directories on +some platforms: +Solaris 9. +@item +This function mistakenly removes a directory with +@code{remove("dir/./")} on some platforms: +Cygwin 1.5.x. +@item +This function does not remove empty directories on some platforms: +mingw. @end itemize Portability problems not fixed by Gnulib:
new file mode 100644 --- /dev/null +++ b/lib/remove.c @@ -0,0 +1,43 @@ +/* Remove a file or directory. + Copyright (C) 2009 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* written by Eric Blake */ + +#include <config.h> + +#include <stdio.h> + +#include <errno.h> +#include <unistd.h> + +#undef remove + +/* Remove NAME from the file system. This works around C89 platforms + that don't handle directories like POSIX requires; it also works + around Solaris 9 bugs with trailing slash. */ +int +rpl_remove (char const *name) +{ + /* It is faster to just try rmdir, and fall back on unlink, than it + is to use lstat to see what we are about to remove. Technically, + it is more likely that we want unlink, not rmdir, but we cannot + guarantee the safety of unlink on directories. Trailing slash + bugs are handled by our rmdir and unlink wrappers. */ + int result = rmdir (name); + if (result && errno == ENOTDIR) + result = unlink (name); + return result; +}
--- a/lib/stdio.in.h +++ b/lib/stdio.in.h @@ -416,6 +416,20 @@ extern int puts (const char *string); #endif +#if @GNULIB_REMOVE@ +# if @REPLACE_REMOVE@ +# undef remove +# define remove rpl_remove +extern int remove (const char *name); +# endif +#elif defined GNULIB_POSIXCHECK +# undef remove +# define remove(n) \ + (GL_LINK_WARNING ("remove cannot handle directories on some platforms - " \ + "use gnulib module remove for more portability"), \ + remove (n)) +#endif + #if @GNULIB_RENAME@ # if @REPLACE_RENAME@ # undef rename
new file mode 100644 --- /dev/null +++ b/m4/remove.m4 @@ -0,0 +1,40 @@ +# remove.m4 serial 1 +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, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_REMOVE], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_REQUIRE([gl_AC_DOS]) + AC_REQUIRE([gl_STDIO_H_DEFAULTS]) + AC_REQUIRE([gl_FUNC_RMDIR]) + AC_REQUIRE([gl_FUNC_UNLINK]) + if test "$gl_cv_func_rmdir_works:$gl_cv_func_unlink_works" != yes:yes; then + dnl If either underlying syscall is broken, then remove likely has + dnl the same bug; blindly use our replacement. + REPLACE_REMOVE=1 + AC_LIBOBJ([remove]) + else + dnl C89 requires remove(), but only POSIX requires it to handle + dnl directories. On mingw, directories fails with EPERM. + AC_CACHE_CHECK([whether remove handles directories], + [gl_cv_func_remove_dir_works], + [mkdir conftest.dir + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include <stdio.h> +]], [[return remove ("conftest.dir");]])], + [gl_cv_func_remove_dir_works=yes], [gl_cv_func_remove_dir_works=no], + [case $host_os in + mingw*) gl_cv_func_remove_dir_works="guessing no";; + *) gl_cv_func_remove_dir_works="guessing yes";; + esac]) + rm -rf conftest.dir]) + case $gl_cv_func_remove_dir_works in + *no*) REPLACE_REMOVE=1 + AC_LIBOBJ([remove]);; + esac + fi +])
--- a/m4/stdio_h.m4 +++ b/m4/stdio_h.m4 @@ -1,4 +1,4 @@ -# stdio_h.m4 serial 18 +# stdio_h.m4 serial 19 dnl Copyright (C) 2007-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, @@ -67,6 +67,7 @@ GNULIB_PUTC=0; AC_SUBST([GNULIB_PUTC]) GNULIB_PUTCHAR=0; AC_SUBST([GNULIB_PUTCHAR]) GNULIB_PUTS=0; AC_SUBST([GNULIB_PUTS]) + GNULIB_REMOVE=0; AC_SUBST([GNULIB_REMOVE]) GNULIB_RENAME=0; AC_SUBST([GNULIB_RENAME]) GNULIB_SNPRINTF=0; AC_SUBST([GNULIB_SNPRINTF]) GNULIB_SPRINTF_POSIX=0; AC_SUBST([GNULIB_SPRINTF_POSIX]) @@ -107,6 +108,7 @@ REPLACE_PERROR=0; AC_SUBST([REPLACE_PERROR]) REPLACE_POPEN=0; AC_SUBST([REPLACE_POPEN]) REPLACE_PRINTF=0; AC_SUBST([REPLACE_PRINTF]) + REPLACE_REMOVE=0; AC_SUBST([REPLACE_REMOVE]) REPLACE_RENAME=0; AC_SUBST([REPLACE_RENAME]) REPLACE_SNPRINTF=0; AC_SUBST([REPLACE_SNPRINTF]) REPLACE_SPRINTF=0; AC_SUBST([REPLACE_SPRINTF])
new file mode 100644 --- /dev/null +++ b/modules/remove @@ -0,0 +1,27 @@ +Description: +remove(): remove a file or directory + +Files: +lib/remove.c +m4/dos.m4 +m4/remove.m4 + +Depends-on: +rmdir +stdio +unlink + +configure.ac: +gl_FUNC_REMOVE +gl_STDIO_MODULE_INDICATOR([remove]) + +Makefile.am: + +Include: +<stdio.h> + +License: +LGPL + +Maintainer: +Eric Blake
new file mode 100644 --- /dev/null +++ b/modules/remove-tests @@ -0,0 +1,12 @@ +Files: +tests/test-remove.c + +Depends-on: +sys_stat + +configure.ac: +AC_CHECK_FUNCS_ONCE([symlink]) + +Makefile.am: +TESTS += test-remove +check_PROGRAMS += test-remove
--- a/modules/stdio +++ b/modules/stdio @@ -52,6 +52,7 @@ -e 's|@''GNULIB_PUTC''@|$(GNULIB_PUTC)|g' \ -e 's|@''GNULIB_PUTCHAR''@|$(GNULIB_PUTCHAR)|g' \ -e 's|@''GNULIB_PUTS''@|$(GNULIB_PUTS)|g' \ + -e 's|@''GNULIB_REMOVE''@|$(GNULIB_REMOVE)|g' \ -e 's|@''GNULIB_RENAME''@|$(GNULIB_RENAME)|g' \ -e 's|@''GNULIB_SNPRINTF''@|$(GNULIB_SNPRINTF)|g' \ -e 's|@''GNULIB_SPRINTF_POSIX''@|$(GNULIB_SPRINTF_POSIX)|g' \ @@ -89,6 +90,7 @@ -e 's|@''REPLACE_PERROR''@|$(REPLACE_PERROR)|g' \ -e 's|@''REPLACE_POPEN''@|$(REPLACE_POPEN)|g' \ -e 's|@''REPLACE_PRINTF''@|$(REPLACE_PRINTF)|g' \ + -e 's|@''REPLACE_REMOVE''@|$(REPLACE_REMOVE)|g' \ -e 's|@''REPLACE_RENAME''@|$(REPLACE_RENAME)|g' \ -e 's|@''REPLACE_SNPRINTF''@|$(REPLACE_SNPRINTF)|g' \ -e 's|@''REPLACE_SPRINTF''@|$(REPLACE_SPRINTF)|g' \
new file mode 100644 --- /dev/null +++ b/tests/test-remove.c @@ -0,0 +1,122 @@ +/* Tests of remove. + Copyright (C) 2009 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +#include <config.h> + +#include <stdio.h> + +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#if !HAVE_SYMLINK +# define symlink(a,b) (-1) +#endif + +#define ASSERT(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \ + fflush (stderr); \ + abort (); \ + } \ + } \ + while (0) + +#define BASE "test-remove.t" + +int +main () +{ + /* Remove any leftovers from a previous partial run. */ + ASSERT (system ("rm -rf " BASE "*") == 0); + + /* Setup. */ + ASSERT (mkdir (BASE "dir", 0700) == 0); + ASSERT (close (creat (BASE "dir/file", 0600)) == 0); + + /* Basic error conditions. */ + errno = 0; + ASSERT (remove ("") == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (remove ("nosuch") == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (remove ("nosuch/") == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (remove (".") == -1); + ASSERT (errno == EINVAL || errno == EBUSY); + /* Resulting errno after ".." or "/" is too varied to test; it is + reasonable to see any of EINVAL, EEXIST, ENOTEMPTY, EACCES. */ + ASSERT (remove ("..") == -1); + ASSERT (remove ("/") == -1); + ASSERT (remove ("///") == -1); + errno = 0; + ASSERT (remove (BASE "dir/file/") == -1); + ASSERT (errno == ENOTDIR); + + /* Non-empty directory. */ + errno = 0; + ASSERT (remove (BASE "dir") == -1); + ASSERT (errno == EEXIST || errno == ENOTEMPTY); + + /* Non-directory. */ + ASSERT (remove (BASE "dir/file") == 0); + + /* Empty directory. */ + errno = 0; + ASSERT (remove (BASE "dir/./") == -1); + ASSERT (errno == EINVAL || errno == EBUSY); + ASSERT (remove (BASE "dir") == 0); + + /* Test symlink behavior. Specifying trailing slash should remove + referent directory, or cause ENOTDIR failure, but not touch + symlink. */ + if (symlink (BASE "dir", BASE "link") != 0) + { + fputs ("skipping test: symlinks not supported on this filesystem\n", + stderr); + return 77; + } + ASSERT (mkdir (BASE "dir", 0700) == 0); + errno = 0; + if (remove (BASE "link/") == 0) + { + struct stat st; + errno = 0; + ASSERT (stat (BASE "link", &st) == -1); + ASSERT (errno == ENOENT); + } + else + ASSERT (remove (BASE "dir") == 0); + { + struct stat st; + ASSERT (lstat (BASE "link", &st) == 0); + ASSERT (S_ISLNK (st.st_mode)); + } + ASSERT (remove (BASE "link") == 0); + + return 0; +}