>From 2f1bb5913edea1ae76d365b18d73c30f1e33a034 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 22 Jun 2022 01:43:52 +0200 Subject: [PATCH 2/4] chmod: New module. * lib/sys_stat.in.h (chmod): Declare when GNULIB_CHMOD is 1. * lib/chmod.c: New file, based on lib/lchmod.c. * m4/chmod.m4: New file, based on m4/fchmodat.m4. * m4/sys_stat_h.m4 (gl_SYS_STAT_H): Test whether chmod is declared. (gl_SYS_STAT_H_REQUIRE_DEFAULTS): Initialize GNULIB_CHMOD. (gl_SYS_STAT_H_DEFAULTS): Initialize REPLACE_CHMOD. * modules/sys_stat (Makefile.am): Substitute GNULIB_CHMOD, REPLACE_CHMOD. * modules/chmod: New file, based on modules/lchmod. * doc/posix-functions/chmod.texi: Mention the new module and the problems on IRIX and Windows. --- ChangeLog | 15 ++++++ doc/posix-functions/chmod.texi | 15 ++++-- lib/chmod.c | 47 +++++++++++++++++++ lib/sys_stat.in.h | 28 +++++++++++- m4/chmod.m4 | 84 ++++++++++++++++++++++++++++++++++ m4/sys_stat_h.m4 | 6 ++- modules/chmod | 32 +++++++++++++ modules/sys_stat | 2 + 8 files changed, 221 insertions(+), 8 deletions(-) create mode 100644 lib/chmod.c create mode 100644 m4/chmod.m4 create mode 100644 modules/chmod diff --git a/ChangeLog b/ChangeLog index 6163d7280a..7cf53fde6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2022-06-22 Bruno Haible + + chmod: New module. + * lib/sys_stat.in.h (chmod): Declare when GNULIB_CHMOD is 1. + * lib/chmod.c: New file, based on lib/lchmod.c. + * m4/chmod.m4: New file, based on m4/fchmodat.m4. + * m4/sys_stat_h.m4 (gl_SYS_STAT_H): Test whether chmod is declared. + (gl_SYS_STAT_H_REQUIRE_DEFAULTS): Initialize GNULIB_CHMOD. + (gl_SYS_STAT_H_DEFAULTS): Initialize REPLACE_CHMOD. + * modules/sys_stat (Makefile.am): Substitute GNULIB_CHMOD, + REPLACE_CHMOD. + * modules/chmod: New file, based on modules/lchmod. + * doc/posix-functions/chmod.texi: Mention the new module and the + problems on IRIX and Windows. + 2022-06-21 Bruno Haible lchmod: Simplify. diff --git a/doc/posix-functions/chmod.texi b/doc/posix-functions/chmod.texi index 90175fd7b9..1288964b64 100644 --- a/doc/posix-functions/chmod.texi +++ b/doc/posix-functions/chmod.texi @@ -4,16 +4,21 @@ POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html} -Gnulib module: --- +Gnulib module: chmod Portability problems fixed by Gnulib: @itemize +@item +This function does not fail when the file name argument ends in a slash +and (without the slash) names a non-directory, on some platforms: +AIX 7.2, IRIX 6.5. +@item +This function fails with a wrong error code (EINVAL instead of ENOTDIR) +when the file name argument ends in a slash and (without the slash) names +a non-directory, on some platforms: +mingw, MSVC. @end itemize Portability problems not fixed by Gnulib: @itemize -@item -This function does not fail when the file name argument ends in a slash -and (without the slash) names a non-directory, on some platforms: -AIX 7.2. @end itemize diff --git a/lib/chmod.c b/lib/chmod.c new file mode 100644 index 0000000000..cb5a4d227d --- /dev/null +++ b/lib/chmod.c @@ -0,0 +1,47 @@ +/* Implement chmod on platforms where it does not work correctly. + + Copyright 2022 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 . */ + +#include + +/* Specification. */ +#include + +#include +#include + +int +rpl_chmod (const char *filename, mode_t mode) +#undef chmod +#if defined _WIN32 && !defined __CYGWIN__ +# define chmod _chmod +#endif +{ + size_t len = strlen (filename); + if (len > 0 && filename[len - 1] == '/') + { + struct stat st; + if (lstat (filename, &st) < 0) + return -1; + if (!S_ISDIR (st.st_mode)) + { + errno = ENOTDIR; + return -1; + } + } + + return chmod (filename, mode); +} diff --git a/lib/sys_stat.in.h b/lib/sys_stat.in.h index 28ddd42f81..714c3cb189 100644 --- a/lib/sys_stat.in.h +++ b/lib/sys_stat.in.h @@ -391,7 +391,33 @@ struct stat #endif -#if @GNULIB_MDA_CHMOD@ +#if @GNULIB_CHMOD@ +# if @REPLACE_CHMOD@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef chmod +# define chmod rpl_chmod +# endif +_GL_FUNCDECL_RPL (chmod, int, (const char *filename, mode_t mode) + _GL_ARG_NONNULL ((1))); +_GL_CXXALIAS_RPL (chmod, int, (const char *filename, mode_t mode)); +# elif defined _WIN32 && !defined __CYGWIN__ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef chmod +# define chmod _chmod +# endif +/* Need to cast, because in mingw the last argument is 'int mode'. */ +_GL_CXXALIAS_MDA_CAST (chmod, int, (const char *filename, mode_t mode)); +# else +_GL_CXXALIAS_SYS (chmod, int, (const char *filename, mode_t mode)); +# endif +_GL_CXXALIASWARN (chmod); +#elif defined GNULIB_POSIXCHECK +# undef chmod +# if HAVE_RAW_DECL_CHMOD +_GL_WARN_ON_USE (chmod, "chmod has portability problems - " + "use gnulib module chmod for portability"); +# endif +#elif @GNULIB_MDA_CHMOD@ /* On native Windows, map 'chmod' to '_chmod', so that -loldnames is not required. In C++ with GNULIB_NAMESPACE, avoid differences between platforms by defining GNULIB_NAMESPACE::chmod always. */ diff --git a/m4/chmod.m4 b/m4/chmod.m4 new file mode 100644 index 0000000000..28dccb008d --- /dev/null +++ b/m4/chmod.m4 @@ -0,0 +1,84 @@ +# chmod.m4 serial 1 +dnl Copyright (C) 2004-2022 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. + +dnl From Bruno Haible. + +AC_DEFUN([gl_FUNC_CHMOD], +[ + AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CACHE_CHECK([whether chmod works], + [gl_cv_func_chmod_works], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [ + AC_INCLUDES_DEFAULT[ + #if defined _WIN32 && !defined __CYGWIN__ + #include + #endif + #include + #include + #ifndef S_IRUSR + #define S_IRUSR 0400 + #endif + #ifndef S_IWUSR + #define S_IWUSR 0200 + #endif + #ifndef S_IRWXU + #define S_IRWXU 0700 + #endif + #ifndef S_IRWXG + #define S_IRWXG 0070 + #endif + #ifndef S_IRWXO + #define S_IRWXO 0007 + #endif + ]GL_MDA_DEFINES], + [[ + int permissive = S_IRWXU | S_IRWXG | S_IRWXO; + int desired = S_IRUSR | S_IWUSR; + int result = 0; + #define file "conftest.chmod" + if (open (file, O_CREAT | O_WRONLY | O_TRUNC, permissive) < 0) + return 1; + /* Test whether chmod rejects a trailing slash on a non-directory, + with error ENOTDIR. + This test fails on AIX 7.2, IRIX 6.5 (no error) and + native Windows (error EINVAL). */ + errno = 0; + if (chmod (file "/", desired) == 0) + result |= 2; + else if (errno != ENOTDIR) + result |= 4; + return result; + ]])], + [gl_cv_func_chmod_works=yes], + [gl_cv_func_chmod_works=no], + [case "$host_os" in + # Guess no on AIX, IRIX, native Windows. + aix* | irix* | mingw*) + gl_cv_func_chmod_works="guessing no" ;; + # Guess yes on glibc, musl libc, macOS, FreeBSD, NetBSD, OpenBSD, Solaris, Haiku, Cygwin. + *-gnu* | gnu* | *-musl* | darwin* | freebsd* | midnightbsd* | netbsd* | openbsd* | solaris* | haiku* | cygwin*) + gl_cv_func_chmod_works="guessing yes" ;; + # If we don't know, obey --enable-cross-guesses. + *) + gl_cv_func_chmod_works="$gl_cross_guess_normal" ;; + esac + ]) + rm -f conftest.chmod + ]) + case "$gl_cv_func_chmod_works" in + *yes) ;; + *) REPLACE_CHMOD=1 ;; + esac +]) + +# Prerequisites of lib/chmod.c. +AC_DEFUN([gl_PREREQ_CHMOD], +[ + : +]) diff --git a/m4/sys_stat_h.m4 b/m4/sys_stat_h.m4 index b5a9789b81..2adbfdeef4 100644 --- a/m4/sys_stat_h.m4 +++ b/m4/sys_stat_h.m4 @@ -1,4 +1,4 @@ -# sys_stat_h.m4 serial 41 -*- Autoconf -*- +# sys_stat_h.m4 serial 42 -*- Autoconf -*- dnl Copyright (C) 2006-2022 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -46,7 +46,7 @@ AC_DEFUN_ONCE([gl_SYS_STAT_H], dnl Check for declarations of anything we want to poison if the dnl corresponding gnulib module is not in use. gl_WARN_ON_USE_PREPARE([[#include - ]], [fchmodat fstat fstatat futimens getumask lchmod lstat + ]], [chmod fchmodat fstat fstatat futimens getumask lchmod lstat mkdirat mkfifo mkfifoat mknod mknodat stat utimensat]) AC_REQUIRE([AC_C_RESTRICT]) @@ -72,6 +72,7 @@ AC_DEFUN([gl_SYS_STAT_H_REQUIRE_DEFAULTS], [ m4_defun(GL_MODULE_INDICATOR_PREFIX[_SYS_STAT_H_MODULE_INDICATOR_DEFAULTS], [ gl_UNISTD_H_REQUIRE_DEFAULTS dnl for REPLACE_FCHDIR + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CHMOD]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FCHMODAT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSTAT]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSTATAT]) @@ -112,6 +113,7 @@ AC_DEFUN([gl_SYS_STAT_H_DEFAULTS], HAVE_MKNOD=1; AC_SUBST([HAVE_MKNOD]) HAVE_MKNODAT=1; AC_SUBST([HAVE_MKNODAT]) HAVE_UTIMENSAT=1; AC_SUBST([HAVE_UTIMENSAT]) + REPLACE_CHMOD=0; AC_SUBST([REPLACE_CHMOD]) REPLACE_FCHMODAT=0; AC_SUBST([REPLACE_FCHMODAT]) REPLACE_FSTAT=0; AC_SUBST([REPLACE_FSTAT]) REPLACE_FSTATAT=0; AC_SUBST([REPLACE_FSTATAT]) diff --git a/modules/chmod b/modules/chmod new file mode 100644 index 0000000000..0efe7b0019 --- /dev/null +++ b/modules/chmod @@ -0,0 +1,32 @@ +Description: +chmod() function: change the permissions of a file + +Files: +lib/chmod.c +m4/chmod.m4 + +Depends-on: +sys_stat +lstat [test $REPLACE_CHMOD = 1] + +configure.ac: +gl_FUNC_CHMOD +gl_CONDITIONAL([GL_COND_OBJ_CHMOD], [test $REPLACE_CHMOD = 1]) +AM_COND_IF([GL_COND_OBJ_CHMOD], [ + gl_PREREQ_CHMOD +]) +gl_SYS_STAT_MODULE_INDICATOR([chmod]) + +Makefile.am: +if GL_COND_OBJ_CHMOD +lib_SOURCES += chmod.c +endif + +Include: + + +License: +GPL + +Maintainer: +Paul Eggert, Bruno Haible diff --git a/modules/sys_stat b/modules/sys_stat index 629eac1b41..d5ab154157 100644 --- a/modules/sys_stat +++ b/modules/sys_stat @@ -36,6 +36,7 @@ sys/stat.h: sys_stat.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNU -e 's|@''NEXT_SYS_STAT_H''@|$(NEXT_SYS_STAT_H)|g' \ -e 's|@''WINDOWS_64_BIT_ST_SIZE''@|$(WINDOWS_64_BIT_ST_SIZE)|g' \ -e 's|@''WINDOWS_STAT_TIMESPEC''@|$(WINDOWS_STAT_TIMESPEC)|g' \ + -e 's/@''GNULIB_CHMOD''@/$(GNULIB_CHMOD)/g' \ -e 's/@''GNULIB_FCHMODAT''@/$(GNULIB_FCHMODAT)/g' \ -e 's/@''GNULIB_FSTAT''@/$(GNULIB_FSTAT)/g' \ -e 's/@''GNULIB_FSTATAT''@/$(GNULIB_FSTATAT)/g' \ @@ -67,6 +68,7 @@ sys/stat.h: sys_stat.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNU -e 's|@''HAVE_MKNOD''@|$(HAVE_MKNOD)|g' \ -e 's|@''HAVE_MKNODAT''@|$(HAVE_MKNODAT)|g' \ -e 's|@''HAVE_UTIMENSAT''@|$(HAVE_UTIMENSAT)|g' \ + -e 's|@''REPLACE_CHMOD''@|$(REPLACE_CHMOD)|g' \ -e 's|@''REPLACE_FCHMODAT''@|$(REPLACE_FCHMODAT)|g' \ -e 's|@''REPLACE_FSTAT''@|$(REPLACE_FSTAT)|g' \ -e 's|@''REPLACE_FSTATAT''@|$(REPLACE_FSTATAT)|g' \ -- 2.25.1