Hi Jim, Eric, Here is a proposed patch to split fchownat() off from the module 'openat'.
The immediate motivation is that on MSVC, there is no <pwd.h> and no <grp.h>, therefore code that fiddles with owners and groups leads to many more compilation problems than code that just deals with files and directories. And the module 'getcwd' depends on 'openat'. The long-standing motivation is that a program that just needs to open a file should not contain (or need to compile) code for changing ownership, access modes, or for creating or removing files or directories. For this reason, I'll submit more patches like this, until the module 'openat' really only provides openat(). This patch is tested on a number of platforms (Linux, MacOS X, FreeBSD, OpenBSD, NetBSD, Cygwin, etc.) 2011-10-31 Bruno Haible <br...@clisp.org> New module 'fchownat', split off from module 'openat'. * lib/openat.h (chownat, lchownat): Enable only if GNULIB_FCHOWNAT is defined. * m4/fchownat.m4: New file, extracted from m4/openat.m4. * m4/openat.m4 (gl_FUNC_OPENAT): Don't set GNULIB_FCHOWNAT. Don't invoke gl_FUNC_FCHOWNAT. (gl_FUNC_FCHOWNAT_DEREF_BUG, gl_FUNC_FCHOWNAT_EMPTY_FILENAME_BUG, gl_FUNC_FCHOWNAT): Moved to m4/fchownat.m4. * modules/fchownat: New file, extracted from modules/openat. * modules/openat (Files): Remove lib/fchownat.c. (Depends-on): Remove lchown. (configure.ac): Remove AC_LIBOBJ of fchownat. * modules/fchownat-tests: New file, extracted from modules/openat-tests. * modules/openat-tests (Files): Remove tests/test-fchownat.c, tests/test-chown.h, tests/test-lchown.h, tests/nap.h. (Depends-on): Remove mgetgroups, usleep, stat-time. (configure.ac): Remove test for getegid. (Makefile.am): Remove rules for test-fchownat. * doc/posix-functions/fchownat.texi: Mention module 'fchownat' instead of module 'openat'. * NEWS: Mention the change. ================================ m4/fchownat.m4 ================================ # fchownat.m4 serial 1 dnl Copyright (C) 2004-2011 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. # Written by Jim Meyering. # If we have the fchownat function, and it has the bug (in glibc-2.4) # that it dereferences symlinks even with AT_SYMLINK_NOFOLLOW, then # use the replacement function. # Also if the fchownat function, like chown, has the trailing slash bug, # use the replacement function. # Also use the replacement function if fchownat is simply not available. AC_DEFUN([gl_FUNC_FCHOWNAT], [ AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) GNULIB_FCHOWNAT=1 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_REQUIRE([gl_FUNC_CHOWN]) AC_CHECK_FUNC([fchownat], [gl_FUNC_FCHOWNAT_DEREF_BUG( [REPLACE_FCHOWNAT=1 AC_DEFINE([FCHOWNAT_NOFOLLOW_BUG], [1], [Define to 1 if your platform has fchownat, but it cannot perform lchown tasks.]) ]) gl_FUNC_FCHOWNAT_EMPTY_FILENAME_BUG( [REPLACE_FCHOWNAT=1 AC_DEFINE([FCHOWNAT_EMPTY_FILENAME_BUG], [1], [Define to 1 if your platform has fchownat, but it does not reject an empty file name.]) ]) if test $REPLACE_CHOWN = 1; then REPLACE_FCHOWNAT=1 fi], [HAVE_FCHOWNAT=0]) ]) # gl_FUNC_FCHOWNAT_DEREF_BUG([ACTION-IF-BUGGY[, ACTION-IF-NOT_BUGGY]]) AC_DEFUN([gl_FUNC_FCHOWNAT_DEREF_BUG], [ dnl Persuade glibc's <unistd.h> to declare fchownat(). AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_CACHE_CHECK([whether fchownat works with AT_SYMLINK_NOFOLLOW], gl_cv_func_fchownat_nofollow_works, [ gl_dangle=conftest.dangle # Remove any remnants of a previous test. rm -f $gl_dangle # Arrange for deletion of the temporary file this test creates. ac_clean_files="$ac_clean_files $gl_dangle" ln -s conftest.no-such $gl_dangle AC_RUN_IFELSE( [AC_LANG_SOURCE( [[ #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> int main () { return (fchownat (AT_FDCWD, "$gl_dangle", -1, getgid (), AT_SYMLINK_NOFOLLOW) != 0 && errno == ENOENT); } ]])], [gl_cv_func_fchownat_nofollow_works=yes], [gl_cv_func_fchownat_nofollow_works=no], [gl_cv_func_fchownat_nofollow_works=no], ) ]) AS_IF([test $gl_cv_func_fchownat_nofollow_works = no], [$1], [$2]) ]) # gl_FUNC_FCHOWNAT_EMPTY_FILENAME_BUG([ACTION-IF-BUGGY[, ACTION-IF-NOT_BUGGY]]) AC_DEFUN([gl_FUNC_FCHOWNAT_EMPTY_FILENAME_BUG], [ dnl Persuade glibc's <unistd.h> to declare fchownat(). AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_CACHE_CHECK([whether fchownat works with an empty file name], [gl_cv_func_fchownat_empty_filename_works], [AC_RUN_IFELSE( [AC_LANG_PROGRAM( [[#include <unistd.h> #include <fcntl.h> ]], [[int fd; int ret; if (mkdir ("conftestdir", 0700) < 0) return 2; fd = open ("conftestdir", O_RDONLY); if (fd < 0) return 3; ret = fchownat (fd, "", -1, -1, 0); close (fd); rmdir ("conftestdir"); return ret == 0; ]])], [gl_cv_func_fchownat_empty_filename_works=yes], [gl_cv_func_fchownat_empty_filename_works=no], [gl_cv_func_fchownat_empty_filename_works="guessing no"]) ]) AS_IF([test "$gl_cv_func_fchownat_empty_filename_works" != yes], [$1], [$2]) ]) =============================== modules/fchownat =============================== Description: Change the owner of a file at a directory. Files: lib/fchownat.c lib/at-func.c lib/openat.h lib/openat-priv.h m4/fchownat.m4 Depends-on: dirent dosname errno extensions fchdir fcntl-h lchown [test $HAVE_FCHOWNAT = 0 || test $REPLACE_FCHOWNAT = 1] openat save-cwd stdbool sys_stat unistd configure.ac: gl_FUNC_FCHOWNAT if test $HAVE_FCHOWNAT = 0 || test $REPLACE_FCHOWNAT = 1; then AC_LIBOBJ([fchownat]) fi AC_REQUIRE([AC_C_INLINE]) dnl because 'inline' is used in lib/openat.h gl_MODULE_INDICATOR([fchownat]) dnl for lib/openat.h Makefile.am: Include: <unistd.h> License: GPL Maintainer: Jim Meyering, Eric Blake ============================ modules/fchownat-tests ============================ Files: tests/nap.h tests/test-chown.h tests/test-lchown.h tests/test-fchownat.c tests/signature.h tests/macros.h Depends-on: ignore-value mgetgroups openat progname usleep stat-time symlink configure.ac: AC_CHECK_FUNCS_ONCE([getegid]) Makefile.am: TESTS += test-fchownat check_PROGRAMS += test-fchownat test_fchownat_LDADD = $(LDADD) @LIBINTL@ ================================================================================ --- NEWS.orig Tue Nov 1 00:21:12 2011 +++ NEWS Mon Oct 31 23:03:00 2011 @@ -12,6 +12,10 @@ Date Modules Changes +2011-11-01 openat This module no longer provides the fchownat() + function. If you need this function, you now need + to request the 'fchownat' module. + 2011-10-03 poll The link requirements of this module are changed from empty to $(LIB_POLL). --- doc/posix-functions/fchownat.texi.orig Tue Nov 1 00:21:12 2011 +++ doc/posix-functions/fchownat.texi Mon Oct 31 23:02:12 2011 @@ -4,7 +4,7 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fchownat.html} -Gnulib module: openat +Gnulib module: fchownat Portability problems fixed by Gnulib: @itemize --- lib/openat.h.orig Tue Nov 1 00:21:12 2011 +++ lib/openat.h Mon Oct 31 23:17:11 2011 @@ -47,6 +47,9 @@ /* Using these function names makes application code slightly more readable than it would be with fchownat (..., 0) or fchownat (..., AT_SYMLINK_NOFOLLOW). */ + +#if GNULIB_FCHOWNAT + static inline int chownat (int fd, char const *file, uid_t owner, gid_t group) { @@ -59,6 +62,8 @@ return fchownat (fd, file, owner, group, AT_SYMLINK_NOFOLLOW); } +#endif + static inline int chmodat (int fd, char const *file, mode_t mode) { --- m4/openat.m4.orig Tue Nov 1 00:21:12 2011 +++ m4/openat.m4 Mon Oct 31 23:30:56 2011 @@ -1,4 +1,4 @@ -# serial 37 +# serial 38 # See if we need to use our replacement for Solaris' openat et al functions. dnl Copyright (C) 2004-2011 Free Software Foundation, Inc. @@ -19,7 +19,6 @@ GNULIB_MKDIRAT=1 AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) - GNULIB_FCHOWNAT=1 GNULIB_UNLINKAT=1 AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) @@ -49,113 +48,12 @@ if test $ac_cv_func_mkdirat != yes; then HAVE_MKDIRAT=0 fi - gl_FUNC_FCHOWNAT gl_FUNC_FSTATAT dnl This is tested at least via getcwd.c. gl_MODULE_INDICATOR([openat]) ]) -# gl_FUNC_FCHOWNAT_DEREF_BUG([ACTION-IF-BUGGY[, ACTION-IF-NOT_BUGGY]]) -AC_DEFUN([gl_FUNC_FCHOWNAT_DEREF_BUG], -[ - dnl Persuade glibc's <unistd.h> to declare fchownat(). - AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) - - AC_CACHE_CHECK([whether fchownat works with AT_SYMLINK_NOFOLLOW], - gl_cv_func_fchownat_nofollow_works, - [ - gl_dangle=conftest.dangle - # Remove any remnants of a previous test. - rm -f $gl_dangle - # Arrange for deletion of the temporary file this test creates. - ac_clean_files="$ac_clean_files $gl_dangle" - ln -s conftest.no-such $gl_dangle - AC_RUN_IFELSE( - [AC_LANG_SOURCE( - [[ -#include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> -#include <errno.h> -#include <sys/types.h> -int -main () -{ - return (fchownat (AT_FDCWD, "$gl_dangle", -1, getgid (), - AT_SYMLINK_NOFOLLOW) != 0 - && errno == ENOENT); -} - ]])], - [gl_cv_func_fchownat_nofollow_works=yes], - [gl_cv_func_fchownat_nofollow_works=no], - [gl_cv_func_fchownat_nofollow_works=no], - ) - ]) - AS_IF([test $gl_cv_func_fchownat_nofollow_works = no], [$1], [$2]) -]) - -# gl_FUNC_FCHOWNAT_EMPTY_FILENAME_BUG([ACTION-IF-BUGGY[, ACTION-IF-NOT_BUGGY]]) -AC_DEFUN([gl_FUNC_FCHOWNAT_EMPTY_FILENAME_BUG], -[ - dnl Persuade glibc's <unistd.h> to declare fchownat(). - AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) - - AC_CACHE_CHECK([whether fchownat works with an empty file name], - [gl_cv_func_fchownat_empty_filename_works], - [AC_RUN_IFELSE( - [AC_LANG_PROGRAM( - [[#include <unistd.h> - #include <fcntl.h> - ]], - [[int fd; - int ret; - if (mkdir ("conftestdir", 0700) < 0) - return 2; - fd = open ("conftestdir", O_RDONLY); - if (fd < 0) - return 3; - ret = fchownat (fd, "", -1, -1, 0); - close (fd); - rmdir ("conftestdir"); - return ret == 0; - ]])], - [gl_cv_func_fchownat_empty_filename_works=yes], - [gl_cv_func_fchownat_empty_filename_works=no], - [gl_cv_func_fchownat_empty_filename_works="guessing no"]) - ]) - AS_IF([test "$gl_cv_func_fchownat_empty_filename_works" != yes], [$1], [$2]) -]) - -# If we have the fchownat function, and it has the bug (in glibc-2.4) -# that it dereferences symlinks even with AT_SYMLINK_NOFOLLOW, then -# use the replacement function. -# Also if the fchownat function, like chown, has the trailing slash bug, -# use the replacement function. -# Also use the replacement function if fchownat is simply not available. -AC_DEFUN([gl_FUNC_FCHOWNAT], -[ - AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) - AC_REQUIRE([gl_FUNC_CHOWN]) - AC_CHECK_FUNC([fchownat], - [gl_FUNC_FCHOWNAT_DEREF_BUG( - [REPLACE_FCHOWNAT=1 - AC_DEFINE([FCHOWNAT_NOFOLLOW_BUG], [1], - [Define to 1 if your platform has fchownat, but it cannot - perform lchown tasks.]) - ]) - gl_FUNC_FCHOWNAT_EMPTY_FILENAME_BUG( - [REPLACE_FCHOWNAT=1 - AC_DEFINE([FCHOWNAT_EMPTY_FILENAME_BUG], [1], - [Define to 1 if your platform has fchownat, but it does - not reject an empty file name.]) - ]) - if test $REPLACE_CHOWN = 1; then - REPLACE_FCHOWNAT=1 - fi], - [HAVE_FCHOWNAT=0]) -]) - # If we have the fstatat function, and it has the bug (in AIX 7.1) # that it does not fill in st_size correctly, use the replacement function. AC_DEFUN([gl_FUNC_FSTATAT], --- modules/openat.orig Tue Nov 1 00:21:12 2011 +++ modules/openat Tue Nov 1 00:21:09 2011 @@ -4,7 +4,6 @@ Files: lib/at-func.c lib/fchmodat.c -lib/fchownat.c lib/fstatat.c lib/mkdirat.c lib/openat.c @@ -26,7 +25,6 @@ gettext-h intprops largefile -lchown [test $HAVE_FCHOWNAT = 0 || test $REPLACE_FCHOWNAT = 1] lstat mkdir [test $HAVE_MKDIRAT = 0] open @@ -56,9 +54,6 @@ if test $ac_cv_func_unlinkat = no || test $REPLACE_UNLINKAT = 1; then AC_LIBOBJ([unlinkat]) fi -if test $HAVE_FCHOWNAT = 0 || test $REPLACE_FCHOWNAT = 1; then - AC_LIBOBJ([fchownat]) -fi Makefile.am: --- modules/openat-tests.orig Tue Nov 1 00:21:12 2011 +++ modules/openat-tests Mon Oct 31 23:45:47 2011 @@ -1,13 +1,9 @@ Files: -tests/nap.h -tests/test-chown.h -tests/test-lchown.h tests/test-lstat.h tests/test-mkdir.h tests/test-rmdir.h tests/test-stat.h tests/test-unlink.h -tests/test-fchownat.c tests/test-fstatat.c tests/test-mkdirat.c tests/test-openat.c @@ -19,25 +15,18 @@ Depends-on: getcwd-lgpl ignore-value -mgetgroups progname -usleep -stat-time symlink unlinkdir configure.ac: -AC_CHECK_FUNCS_ONCE([getegid]) Makefile.am: TESTS += \ - test-fchmodat test-fchownat test-fstatat test-mkdirat test-openat \ - test-unlinkat + test-fchmodat test-fstatat test-mkdirat test-openat test-unlinkat check_PROGRAMS += \ - test-fchmodat test-fchownat test-fstatat test-mkdirat test-openat \ - test-unlinkat + test-fchmodat test-fstatat test-mkdirat test-openat test-unlinkat test_fchmodat_LDADD = $(LDADD) @LIBINTL@ -test_fchownat_LDADD = $(LDADD) @LIBINTL@ test_fstatat_LDADD = $(LDADD) @LIBINTL@ test_mkdirat_LDADD = $(LDADD) @LIBINTL@ test_openat_LDADD = $(LDADD) @LIBINTL@ -- In memoriam Manon Roland <http://en.wikipedia.org/wiki/Madame_Roland>