summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2022-06-22 01:43:52 +0200
committerBruno Haible <bruno@clisp.org>2022-06-22 01:43:52 +0200
commit2f1bb5913edea1ae76d365b18d73c30f1e33a034 (patch)
tree59a091a71d1927ead359a6335cd362b0e0bcdc0b
parente67a519439200086ba122678807b4831fbeb8ac7 (diff)
downloadgnulib-2f1bb5913edea1ae76d365b18d73c30f1e33a034.tar.gz
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.
-rw-r--r--ChangeLog15
-rw-r--r--doc/posix-functions/chmod.texi15
-rw-r--r--lib/chmod.c47
-rw-r--r--lib/sys_stat.in.h28
-rw-r--r--m4/chmod.m484
-rw-r--r--m4/sys_stat_h.m46
-rw-r--r--modules/chmod32
-rw-r--r--modules/sys_stat2
8 files changed, 221 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 6163d7280a..7cf53fde6b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2022-06-22 Bruno Haible <bruno@clisp.org>
+
+ 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 <bruno@clisp.org>
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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+/* Specification. */
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <string.h>
+
+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 <io.h>
+ #endif
+ #include <errno.h>
+ #include <fcntl.h>
+ #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 <sys/stat.h>
- ]], [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:
+<sys/stat.h>
+
+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' \