summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2025-06-27 22:32:33 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2025-06-27 23:06:40 -0700
commitdbdf761187d7cccfad20a2899bab3dc77f379c3a (patch)
treed4e160b187f6f56e27dad185dfdd4cb955c4ec80 /lib
parent68100ca656ad76e937622a1a74b6ca185bc82e07 (diff)
Update from Gnulib by running admin/merge-gnulib
Diffstat (limited to 'lib')
-rw-r--r--lib/_Noreturn.h38
-rw-r--r--lib/acl.h2
-rw-r--r--lib/attribute.h5
-rw-r--r--lib/boot-time.h13
-rw-r--r--lib/fcntl.in.h6
-rw-r--r--lib/file-has-acl.c173
-rw-r--r--lib/gettext.h67
-rw-r--r--lib/gnulib.mk.in18
-rw-r--r--lib/open.c115
-rw-r--r--lib/qcopy-acl.c29
-rw-r--r--lib/regcomp.c53
-rw-r--r--lib/regexec.c2
-rw-r--r--lib/stat-time.h43
-rw-r--r--lib/stdckdint.in.h39
-rw-r--r--lib/stddef.in.h61
-rw-r--r--lib/string.in.h27
-rw-r--r--lib/sys_stat.in.h6
-rw-r--r--lib/unistd.in.h18
18 files changed, 503 insertions, 212 deletions
diff --git a/lib/_Noreturn.h b/lib/_Noreturn.h
index 0d452649fb2..8e63387914c 100644
--- a/lib/_Noreturn.h
+++ b/lib/_Noreturn.h
@@ -14,33 +14,25 @@
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
+/* The _Noreturn keyword of C11.
+ Do not use [[noreturn]], because with it the syntax
+ extern _Noreturn void func (...);
+ would not be valid; such a declaration would be valid only with 'extern'
+ and '_Noreturn' swapped, or without the 'extern' keyword. However, some
+ AIX system header files and several gnulib header files use precisely
+ this syntax with 'extern'. So even though C23 deprecates _Noreturn,
+ it is currently more portable to prefer it to [[noreturn]].
+
+ Also, do not try to work around LLVM bug 59792 (clang 15 or earlier).
+ This rare bug can be worked around by compiling with 'clang -D_Noreturn=',
+ though the workaround may generate many false-alarm warnings. */
#ifndef _Noreturn
-# if (defined __cplusplus \
- && ((201103 <= __cplusplus && !(__GNUC__ == 4 && __GNUC_MINOR__ == 7)) \
- || (defined _MSC_VER && 1900 <= _MSC_VER)) \
- && 0)
- /* [[noreturn]] is not practically usable, because with it the syntax
- extern _Noreturn void func (...);
- would not be valid; such a declaration would only be valid with 'extern'
- and '_Noreturn' swapped, or without the 'extern' keyword. However, some
- AIX system header files and several gnulib header files use precisely
- this syntax with 'extern'. */
-# define _Noreturn [[noreturn]]
-# elif (defined __clang__ && __clang_major__ < 16 \
- && defined _GL_WORK_AROUND_LLVM_BUG_59792)
- /* Compile with -D_GL_WORK_AROUND_LLVM_BUG_59792 to work around
- that rare LLVM bug, though you may get many false-alarm warnings. */
-# define _Noreturn
-# elif ((!defined __cplusplus || defined __clang__) \
- && (201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0) \
- || (!defined __STRICT_ANSI__ \
- && (4 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __clang__ \
- || (defined __apple_build_version__ \
- ? 6000000 <= __apple_build_version__ \
- : 3 < __clang_major__ + (5 <= __clang_minor__))))))
+# if 201112 <= (defined __STDC_VERSION__ ? __STDC_VERSION__ : 0)
/* _Noreturn works as-is. */
# elif (2 < __GNUC__ + (8 <= __GNUC_MINOR__) || defined __clang__ \
|| 0x5110 <= __SUNPRO_C)
+ /* Prefer __attribute__ ((__noreturn__)) to plain _Noreturn even if the
+ latter works, as 'gcc -std=gnu99 -Wpedantic' warns about _Noreturn. */
# define _Noreturn __attribute__ ((__noreturn__))
# elif 1200 <= (defined _MSC_VER ? _MSC_VER : 0)
# define _Noreturn __declspec (noreturn)
diff --git a/lib/acl.h b/lib/acl.h
index 90fd24e152d..e3c134fb41c 100644
--- a/lib/acl.h
+++ b/lib/acl.h
@@ -79,6 +79,8 @@ struct aclinfo
bool acl_errno_valid (int) _GL_ATTRIBUTE_CONST;
int file_has_acl (char const *, struct stat const *);
int file_has_aclinfo (char const *restrict, struct aclinfo *restrict, int);
+int fdfile_has_aclinfo (int, char const *restrict,
+ struct aclinfo *restrict, int);
#if HAVE_LINUX_XATTR_H && HAVE_LISTXATTR
bool aclinfo_has_xattr (struct aclinfo const *, char const *)
diff --git a/lib/attribute.h b/lib/attribute.h
index ae7bbe8e2cb..c85412d90af 100644
--- a/lib/attribute.h
+++ b/lib/attribute.h
@@ -50,8 +50,9 @@
- In a function declaration/definition with a storage-class
specifier: between the storage-class specifier and the return
type.
- - Or after the parameter list,
- ∙ but after ATTRIBUTE_NOTHROW if present.
+ - Or, in a function declaration:
+ after the parameter list,
+ ∙ but after ATTRIBUTE_NOTHROW if present.
In other declarations, such as variable declarations:
diff --git a/lib/boot-time.h b/lib/boot-time.h
index 195839a2c53..7abfa12e444 100644
--- a/lib/boot-time.h
+++ b/lib/boot-time.h
@@ -29,11 +29,16 @@ extern "C" {
/* Store the approximate time when the machine last booted in *P_BOOT_TIME,
and return 0. If it cannot be determined, return -1.
+ If the machine is a container inside another host machine,
+ return the boot time of the container, not the host.
+ The difference can matter in GNU/Linux, where times in /proc/stat
+ might be relative to boot time of the host, not the container.
+
This function is not multithread-safe, since on many platforms it
- invokes the functions setutxent, getutxent, endutxent. These
- functions are needed because they may lock FILE (so that we don't
- read garbage when a concurrent process writes to FILE), but their
- drawback is that they have a common global state. */
+ invokes the functions setutxent, getutxent, endutxent.
+ These functions may lock a file like /var/log/wtmp (so that we
+ don't read garbage when a concurrent process writes to that file),
+ but their drawback is that they have a common global state. */
extern int get_boot_time (struct timespec *p_boot_time);
diff --git a/lib/fcntl.in.h b/lib/fcntl.in.h
index d7f551b30f3..c5068ed48a0 100644
--- a/lib/fcntl.in.h
+++ b/lib/fcntl.in.h
@@ -209,7 +209,9 @@ _GL_WARN_ON_USE (open, "open is not always POSIX compliant - "
# undef open
# define open _open
# endif
-_GL_CXXALIAS_MDA (open, int, (const char *filename, int flags, ...));
+/* Need to cast, because in MSVC the parameter list of _open as a C++ function
+ is (const char *, int, int = 0). */
+_GL_CXXALIAS_MDA_CAST (open, int, (const char *filename, int flags, ...));
# else
_GL_CXXALIAS_SYS (open, int, (const char *filename, int flags, ...));
# endif
@@ -313,7 +315,7 @@ _GL_WARN_ON_USE (openat, "openat is not portable - "
#endif
#ifndef O_DIRECTORY
-# define O_DIRECTORY 0
+# define O_DIRECTORY 0x20000000 /* Try to not collide with system O_* flags. */
#endif
#ifndef O_DSYNC
diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
index 66b920c1ab2..a9cfbf3a16e 100644
--- a/lib/file-has-acl.c
+++ b/lib/file-has-acl.c
@@ -85,6 +85,13 @@ smack_new_label_from_path (MAYBE_UNUSED const char *path,
{
return -1;
}
+static ssize_t
+smack_new_label_from_file (MAYBE_UNUSED int fd,
+ MAYBE_UNUSED const char *xattr,
+ MAYBE_UNUSED char **label)
+{
+ return -1;
+}
# endif
static bool
is_smack_enabled (void)
@@ -115,14 +122,16 @@ aclinfo_may_indicate_xattr (struct aclinfo const *ai)
static bool
has_xattr (char const *xattr, struct aclinfo const *ai,
- MAYBE_UNUSED char const *restrict name, MAYBE_UNUSED int flags)
+ int fd, char const *restrict name, int flags)
{
if (ai && aclinfo_has_xattr (ai, xattr))
return true;
else if (!ai || aclinfo_may_indicate_xattr (ai))
{
- int ret = ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr)
- (name, xattr, NULL, 0));
+ int ret = (fd < 0
+ ? ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr)
+ (name, xattr, NULL, 0))
+ : fgetxattr (fd, xattr, NULL, 0));
if (0 <= ret || (errno == ERANGE || errno == E2BIG))
return true;
}
@@ -145,11 +154,12 @@ aclinfo_has_xattr (struct aclinfo const *ai, char const *xattr)
return false;
}
-/* Get attributes of the file NAME into AI, if USE_ACL.
+/* Get attributes of the file FD aka NAME into AI, if USE_ACL.
+ Ignore FD if it is negative.
If FLAGS & ACL_GET_SCONTEXT, also get security context.
If FLAGS & ACL_SYMLINK_FOLLOW, follow symbolic links. */
static void
-get_aclinfo (char const *name, struct aclinfo *ai, int flags)
+get_aclinfo (int fd, char const *name, struct aclinfo *ai, int flags)
{
int scontext_err = ENOTSUP;
ai->buf = ai->u.__gl_acl_ch;
@@ -163,7 +173,9 @@ get_aclinfo (char const *name, struct aclinfo *ai, int flags)
= (flags & ACL_SYMLINK_FOLLOW ? listxattr : llistxattr);
while (true)
{
- ai->size = lsxattr (name, ai->buf, acl_alloc);
+ ai->size = (fd < 0
+ ? lsxattr (name, ai->buf, acl_alloc)
+ : flistxattr (fd, ai->buf, acl_alloc));
if (0 < ai->size)
break;
ai->u.err = ai->size < 0 ? errno : 0;
@@ -171,7 +183,9 @@ get_aclinfo (char const *name, struct aclinfo *ai, int flags)
break;
/* The buffer was too small. Find how large it should have been. */
- ssize_t size = lsxattr (name, NULL, 0);
+ ssize_t size = (fd < 0
+ ? lsxattr (name, NULL, 0)
+ : flistxattr (fd, NULL, 0));
if (size <= 0)
{
ai->size = size;
@@ -214,9 +228,13 @@ get_aclinfo (char const *name, struct aclinfo *ai, int flags)
{
if (ai->size < 0 || aclinfo_has_xattr (ai, XATTR_NAME_SMACK))
{
- ssize_t r = smack_new_label_from_path (name, "security.SMACK64",
- flags & ACL_SYMLINK_FOLLOW,
- &ai->scontext);
+ static char const SMACK64[] = "security.SMACK64";
+ ssize_t r =
+ (fd < 0
+ ? smack_new_label_from_path (name, SMACK64,
+ flags & ACL_SYMLINK_FOLLOW,
+ &ai->scontext)
+ : smack_new_label_from_file (fd, SMACK64, &ai->scontext));
scontext_err = r < 0 ? errno : 0;
}
}
@@ -226,8 +244,10 @@ get_aclinfo (char const *name, struct aclinfo *ai, int flags)
if (ai->size < 0 || aclinfo_has_xattr (ai, XATTR_NAME_SELINUX))
{
ssize_t r =
- ((flags & ACL_SYMLINK_FOLLOW ? getfilecon : lgetfilecon)
- (name, &ai->scontext));
+ (fd < 0
+ ? ((flags & ACL_SYMLINK_FOLLOW ? getfilecon : lgetfilecon)
+ (name, &ai->scontext))
+ : fgetfilecon (fd, &ai->scontext));
scontext_err = r < 0 ? errno : 0;
# ifndef SE_SELINUX_INLINE
/* Gnulib's selinux-h module is not in use, so getfilecon and
@@ -362,11 +382,14 @@ acl_nfs4_nontrivial (uint32_t *xattr, ssize_t nbytes)
}
#endif
-#if (!USE_LINUX_XATTR && USE_ACL && HAVE_ACL_GET_FD \
- && !HAVE_ACL_EXTENDED_FILE && !HAVE_ACL_TYPE_EXTENDED \
- && !HAVE_ACL_GET_LINK_NP)
-# include <fcntl.h>
-# ifdef O_PATH
+#if (!USE_LINUX_XATTR && USE_ACL && HAVE_ACL_GET_FILE \
+ && !HAVE_ACL_EXTENDED_FILE && !HAVE_ACL_TYPE_EXTENDED)
+/* FreeBSD, NetBSD >= 10, IRIX, Tru64, Cygwin >= 2.5 */
+
+# if HAVE_ACL_GET_FD && !HAVE_ACL_GET_LINK_NP /* IRIX, Tru64, Cygwin >= 2.5 */
+# include <fcntl.h>
+# ifdef O_PATH
+# define acl_get_fd_np(fd, type) acl_get_fd (fd)
/* Like acl_get_file, but do not follow symbolic links. */
static acl_t
@@ -381,8 +404,24 @@ acl_get_link_np (char const *name, acl_type_t type)
errno = err;
return r;
}
-# define HAVE_ACL_GET_LINK_NP 1
+# define HAVE_ACL_GET_LINK_NP 1
+# endif
# endif
+
+static acl_t
+acl_get_fdfile (int fd, char const *name, acl_type_t type, int flags)
+{
+ acl_t (*get) (char const *, acl_type_t) = acl_get_file;
+# if HAVE_ACL_GET_LINK_NP /* FreeBSD, NetBSD >= 10, Cygwin >= 2.5 */
+ if (0 <= fd)
+ return acl_get_fd_np (fd, type);
+ if (! (flags & ACL_SYMLINK_FOLLOW))
+ get = acl_get_link_np;
+# else
+ /* Ignore FD and FLAGS, unfortunately. */
+# endif
+ return get (name, type);
+}
#endif
/* Return 1 if NAME has a nontrivial access control list,
@@ -398,14 +437,35 @@ acl_get_link_np (char const *name, acl_type_t type)
If the d_type value is not known, use DT_UNKNOWN though this may be less
efficient. */
int
-file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
+file_has_aclinfo (char const *restrict name,
struct aclinfo *restrict ai, int flags)
{
+ return fdfile_has_aclinfo (-1, name, ai, flags);
+}
+
+/* Return 1 if FD aka NAME has a nontrivial access control list,
+ 0 if ACLs are not supported, or if NAME has no or only a base ACL,
+ and -1 (setting errno) on error. Note callers can determine
+ if ACLs are not supported as errno is set in that case also.
+ Ignore FD if it is negative.
+ Set *AI to ACL info regardless of return value.
+ FLAGS should be a <dirent.h> d_type value, optionally ORed with
+ - _GL_DT_NOTDIR if it is known that NAME is not a directory,
+ - ACL_GET_SCONTEXT to retrieve security context and return 1 if present,
+ - ACL_SYMLINK_FOLLOW to follow the link if NAME is a symbolic link;
+ otherwise do not follow them if possible.
+ If the d_type value is not known, use DT_UNKNOWN though this may be less
+ efficient. */
+int
+fdfile_has_aclinfo (MAYBE_UNUSED int fd,
+ MAYBE_UNUSED char const *restrict name,
+ struct aclinfo *restrict ai, int flags)
+{
MAYBE_UNUSED unsigned char d_type = flags & UCHAR_MAX;
#if USE_LINUX_XATTR
int initial_errno = errno;
- get_aclinfo (name, ai, flags);
+ get_aclinfo (fd, name, ai, flags);
if (!aclinfo_may_indicate_xattr (ai) && ai->size <= 0)
{
@@ -418,11 +478,11 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
In earlier Fedora the two types of ACLs were mutually exclusive.
Attempt to work correctly on both kinds of systems. */
- if (!has_xattr (XATTR_NAME_NFSV4_ACL, ai, name, flags))
+ if (!has_xattr (XATTR_NAME_NFSV4_ACL, ai, fd, name, flags))
return
- (has_xattr (XATTR_NAME_POSIX_ACL_ACCESS, ai, name, flags)
+ (has_xattr (XATTR_NAME_POSIX_ACL_ACCESS, ai, fd, name, flags)
|| ((d_type == DT_DIR || d_type == DT_UNKNOWN)
- && has_xattr (XATTR_NAME_POSIX_ACL_DEFAULT, ai, name, flags)));
+ && has_xattr (XATTR_NAME_POSIX_ACL_DEFAULT, ai, fd, name, flags)));
/* A buffer large enough to hold any trivial NFSv4 ACL.
The max length of a trivial NFSv4 ACL is 6 words for owner,
@@ -432,8 +492,10 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
everyone is another word to hold "EVERYONE@". */
uint32_t buf[2 * (6 + 6 + 7)];
- int ret = ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr)
- (name, XATTR_NAME_NFSV4_ACL, buf, sizeof buf));
+ int ret = (fd < 0
+ ? ((flags & ACL_SYMLINK_FOLLOW ? getxattr : lgetxattr)
+ (name, XATTR_NAME_NFSV4_ACL, buf, sizeof buf))
+ : fgetxattr (fd, XATTR_NAME_NFSV4_ACL, buf, sizeof buf));
if (ret < 0)
switch (errno)
{
@@ -467,20 +529,23 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
/* On Linux, acl_extended_file is an optimized function: It only
makes two calls to getxattr(), one for ACL_TYPE_ACCESS, one for
ACL_TYPE_DEFAULT. */
- ret = ((flags & ACL_SYMLINK_FOLLOW
- ? acl_extended_file
- : acl_extended_file_nofollow)
- (name));
+ ret = (fd < 0
+ ? ((flags & ACL_SYMLINK_FOLLOW
+ ? acl_extended_file
+ : acl_extended_file_nofollow)
+ (name))
+ : acl_extended_fd (fd));
# elif HAVE_ACL_TYPE_EXTENDED /* Mac OS X */
/* On Mac OS X, acl_get_file (name, ACL_TYPE_ACCESS)
and acl_get_file (name, ACL_TYPE_DEFAULT)
always return NULL / EINVAL. There is no point in making
these two useless calls. The real ACL is retrieved through
- acl_get_file (name, ACL_TYPE_EXTENDED). */
- acl_t acl = ((flags & ACL_SYMLINK_FOLLOW
- ? acl_get_file
- : acl_get_link_np)
- (name, ACL_TYPE_EXTENDED));
+ ACL_TYPE_EXTENDED. */
+ acl_t acl =
+ (fd < 0
+ ? ((flags & ACL_SYMLINK_FOLLOW ? acl_get_file : acl_get_link_np)
+ (name, ACL_TYPE_EXTENDED))
+ : acl_get_fd_np (fd, ACL_TYPE_EXTENDED));
if (acl)
{
ret = acl_extended_nontrivial (acl);
@@ -489,13 +554,8 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
else
ret = -1;
# else /* FreeBSD, NetBSD >= 10, IRIX, Tru64, Cygwin >= 2.5 */
- acl_t (*acl_get_file_or_link) (char const *, acl_type_t) = acl_get_file;
-# if HAVE_ACL_GET_LINK_NP /* FreeBSD, NetBSD >= 10, Cygwin >= 2.5 */
- if (! (flags & ACL_SYMLINK_FOLLOW))
- acl_get_file_or_link = acl_get_link_np;
-# endif
- acl_t acl = acl_get_file_or_link (name, ACL_TYPE_ACCESS);
+ acl_t acl = acl_get_fdfile (fd, name, ACL_TYPE_ACCESS, flags);
if (acl)
{
ret = acl_access_nontrivial (acl);
@@ -517,7 +577,7 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
&& (d_type == DT_DIR
|| (d_type == DT_UNKNOWN && !(flags & _GL_DT_NOTDIR))))
{
- acl = acl_get_file_or_link (name, ACL_TYPE_DEFAULT);
+ acl = acl_get_fdfile (fd, name, ACL_TYPE_DEFAULT, flags);
if (acl)
{
# ifdef __CYGWIN__ /* Cygwin >= 2.5 */
@@ -562,7 +622,10 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
/* Solaris 10 (newer version), which has additional API declared in
<sys/acl.h> (acl_t) and implemented in libsec (acl_set, acl_trivial,
- acl_fromtext, ...). */
+ acl_fromtext, ...).
+
+ Ignore FD, unfortunately. That is better than mishandling
+ ZFS-style ACLs, as the general case code does. */
return acl_trivial (name);
# else /* Solaris, Cygwin, general case */
@@ -586,7 +649,9 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
for (;;)
{
- count = acl (name, GETACL, alloc, entries);
+ count = (fd < 0
+ ? acl (name, GETACL, alloc, entries)
+ : facl (fd, GETACL, alloc, entries));
if (count < 0 && errno == ENOSPC)
{
/* Increase the size of the buffer. */
@@ -657,7 +722,9 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
for (;;)
{
- count = acl (name, ACE_GETACL, alloc, entries);
+ count = (fd < 0
+ ? acl (name, ACE_GETACL, alloc, entries)
+ : facl (fd, ACE_GETACL, alloc, entries));
if (count < 0 && errno == ENOSPC)
{
/* Increase the size of the buffer. */
@@ -722,7 +789,9 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
struct acl_entry entries[NACLENTRIES];
int count;
- count = getacl (name, NACLENTRIES, entries);
+ count = (fd < 0
+ ? getacl (name, NACLENTRIES, entries)
+ : fgetacl (fd, NACLENTRIES, entries));
if (count < 0)
{
@@ -751,7 +820,8 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
{
struct stat statbuf;
- if (stat (name, &statbuf) == -1 && errno != EOVERFLOW)
+ if ((fd < 0 ? stat (name, &statbuf) : fstat (fd, &statbuf)) < 0
+ && errno != EOVERFLOW)
return -1;
return acl_nontrivial (count, entries);
@@ -765,6 +835,7 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
struct acl entries[NACLVENTRIES];
int count;
+ /* Ignore FD, unfortunately. */
count = acl ((char *) name, ACL_GET, NACLVENTRIES, entries);
if (count < 0)
@@ -809,7 +880,9 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
/* The docs say that type being 0 is equivalent to ACL_ANY, but it
is not true, in AIX 5.3. */
type.u64 = ACL_ANY;
- if (aclx_get (name, 0, &type, aclbuf, &aclsize, &mode) >= 0)
+ if (0 <= (fd < 0
+ ? aclx_get (name, 0, &type, aclbuf, &aclsize, &mode)
+ : aclx_fget (fd, 0, &type, aclbuf, &aclsize, &mode)))
break;
if (errno == ENOSYS)
return 0;
@@ -855,7 +928,10 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
union { struct acl a; char room[4096]; } u;
- if (statacl ((char *) name, STX_NORMAL, &u.a, sizeof (u)) < 0)
+ if ((fd < 0
+ ? statacl ((char *) name, STX_NORMAL, &u.a, sizeof u)
+ : fstatacl (fd, STX_NORMAL, &u.a, sizeof u))
+ < 0)
return -1;
return acl_nontrivial (&u.a);
@@ -866,6 +942,7 @@ file_has_aclinfo (MAYBE_UNUSED char const *restrict name,
struct acl entries[NACLENTRIES];
int count;
+ /* Ignore FD, unfortunately. */
count = acl ((char *) name, ACL_GET, NACLENTRIES, entries);
if (count < 0)
diff --git a/lib/gettext.h b/lib/gettext.h
index ea0c27e0002..fd6c62b7eb7 100644
--- a/lib/gettext.h
+++ b/lib/gettext.h
@@ -59,18 +59,61 @@
# endif
# endif
-/* Disabled NLS.
- The casts to 'const char *' serve the purpose of producing warnings
- for invalid uses of the value returned from these functions.
- On pre-ANSI systems without 'const', the config.h file is supposed to
- contain "#define const". */
-# undef gettext
-# define gettext(Msgid) ((const char *) (Msgid))
-# undef dgettext
-# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
-# undef dcgettext
-# define dcgettext(Domainname, Msgid, Category) \
- ((void) (Category), dgettext (Domainname, Msgid))
+/* Disabled NLS. */
+# if defined __GNUC__ && !defined __clang__ && !defined __cplusplus
+/* Use inline functions, to avoid warnings
+ warning: format not a string literal and no format arguments
+ that don't occur with enabled NLS. */
+/* The return type 'const char *' serves the purpose of producing warnings
+ for invalid uses of the value returned from these functions. */
+# if __GNUC__ >= 9
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch"
+# endif
+__attribute__ ((__always_inline__, __gnu_inline__)) extern inline
+# if !defined(__sun)
+const
+# endif
+char *
+gettext (const char *msgid)
+{
+ return msgid;
+}
+__attribute__ ((__always_inline__, __gnu_inline__)) extern inline
+# if !defined(__sun)
+const
+# endif
+char *
+dgettext (const char *domain, const char *msgid)
+{
+ (void) domain;
+ return msgid;
+}
+__attribute__ ((__always_inline__, __gnu_inline__)) extern inline
+# if !defined(__sun)
+const
+# endif
+char *
+dcgettext (const char *domain, const char *msgid, int category)
+{
+ (void) domain;
+ (void) category;
+ return msgid;
+}
+# if __GNUC__ >= 9
+# pragma GCC diagnostic pop
+# endif
+# else
+/* The casts to 'const char *' serve the purpose of producing warnings
+ for invalid uses of the value returned from these functions. */
+# undef gettext
+# define gettext(Msgid) ((const char *) (Msgid))
+# undef dgettext
+# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid))
+# undef dcgettext
+# define dcgettext(Domainname, Msgid, Category) \
+ ((void) (Category), dgettext (Domainname, Msgid))
+# endif
# undef ngettext
# define ngettext(Msgid1, Msgid2, N) \
((N) == 1 \
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index fb34cf2cc1d..bb147b69eed 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -739,6 +739,9 @@ HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@
HAVE_CHOWN = @HAVE_CHOWN@
HAVE_CLOSEDIR = @HAVE_CLOSEDIR@
HAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@
+HAVE_CXX_STDCKDINT_H = @HAVE_CXX_STDCKDINT_H@
+HAVE_C_STDCKDINT_H = @HAVE_C_STDCKDINT_H@
+HAVE_C_UNREACHABLE = @HAVE_C_UNREACHABLE@
HAVE_DECL_DIRFD = @HAVE_DECL_DIRFD@
HAVE_DECL_ECVT = @HAVE_DECL_ECVT@
HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@
@@ -911,6 +914,7 @@ HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
HAVE_SIGSET_T = @HAVE_SIGSET_T@
HAVE_SLEEP = @HAVE_SLEEP@
HAVE_SPAWN_H = @HAVE_SPAWN_H@
+HAVE_STDCKDINT_H = @HAVE_STDCKDINT_H@
HAVE_STDINT_H = @HAVE_STDINT_H@
HAVE_STPCPY = @HAVE_STPCPY@
HAVE_STPNCPY = @HAVE_STPNCPY@
@@ -960,6 +964,8 @@ HAVE_VASPRINTF = @HAVE_VASPRINTF@
HAVE_VDPRINTF = @HAVE_VDPRINTF@
HAVE_WCHAR_H = @HAVE_WCHAR_H@
HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WORKING_CXX_STDCKDINT_H = @HAVE_WORKING_CXX_STDCKDINT_H@
+HAVE_WORKING_C_STDCKDINT_H = @HAVE_WORKING_C_STDCKDINT_H@
HAVE_XSERVER = @HAVE_XSERVER@
HAVE__EXIT = @HAVE__EXIT@
IEEE754_H = @IEEE754_H@
@@ -1087,6 +1093,7 @@ NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@
NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@
NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@
NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H = @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@
+NEXT_AS_FIRST_DIRECTIVE_STDCKDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDCKDINT_H@
NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@
NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@
NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@
@@ -1107,6 +1114,7 @@ NEXT_GETOPT_H = @NEXT_GETOPT_H@
NEXT_INTTYPES_H = @NEXT_INTTYPES_H@
NEXT_LIMITS_H = @NEXT_LIMITS_H@
NEXT_SIGNAL_H = @NEXT_SIGNAL_H@
+NEXT_STDCKDINT_H = @NEXT_STDCKDINT_H@
NEXT_STDDEF_H = @NEXT_STDDEF_H@
NEXT_STDINT_H = @NEXT_STDINT_H@
NEXT_STDIO_H = @NEXT_STDIO_H@
@@ -3202,6 +3210,15 @@ BUILT_SOURCES += $(STDCKDINT_H)
ifneq (,$(GL_GENERATE_STDCKDINT_H_CONDITION))
stdckdint.h: stdckdint.in.h $(top_builddir)/config.status
$(gl_V_at)$(SED_HEADER_STDOUT) \
+ -e 's|@''GUARD_PREFIX''@|GL|g' \
+ -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
+ -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
+ -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
+ -e 's|@''NEXT_STDCKDINT_H''@|$(NEXT_STDCKDINT_H)|g' \
+ -e 's|@''HAVE_C_STDCKDINT_H''@|$(HAVE_C_STDCKDINT_H)|g' \
+ -e 's|@''HAVE_WORKING_C_STDCKDINT_H''@|$(HAVE_WORKING_C_STDCKDINT_H)|g' \
+ -e 's|@''HAVE_CXX_STDCKDINT_H''@|$(HAVE_CXX_STDCKDINT_H)|g' \
+ -e 's|@''HAVE_WORKING_CXX_STDCKDINT_H''@|$(HAVE_WORKING_CXX_STDCKDINT_H)|g' \
$(srcdir)/stdckdint.in.h > $@-t
$(AM_V_at)mv $@-t $@
else
@@ -3234,6 +3251,7 @@ stddef.h: stddef.in.h $(top_builddir)/config.status
-e 's|@''STDDEF_NOT_IDEMPOTENT''@|$(STDDEF_NOT_IDEMPOTENT)|g' \
-e 's|@''REPLACE_NULL''@|$(REPLACE_NULL)|g' \
-e 's|@''HAVE_MAX_ALIGN_T''@|$(HAVE_MAX_ALIGN_T)|g' \
+ -e 's|@''HAVE_C_UNREACHABLE''@|$(HAVE_C_UNREACHABLE)|g' \
$(srcdir)/stddef.in.h > $@-t
$(AM_V_at)mv $@-t $@
else
diff --git a/lib/open.c b/lib/open.c
index 7415b48f81c..8356c14f5b3 100644
--- a/lib/open.c
+++ b/lib/open.c
@@ -55,24 +55,25 @@ orig_open (const char *filename, int flags, mode_t mode)
#include <sys/stat.h>
#include <unistd.h>
+#ifndef OPEN_TRAILING_SLASH_BUG
+# define OPEN_TRAILING_SLASH_BUG false
+#endif
+
#ifndef REPLACE_OPEN_DIRECTORY
-# define REPLACE_OPEN_DIRECTORY 0
+# define REPLACE_OPEN_DIRECTORY false
#endif
+static int
+lstatif (char const *filename, struct stat *st, int flags)
+{
+ return flags & O_NOFOLLOW ? lstat (filename, st) : stat (filename, st);
+}
+
int
open (const char *filename, int flags, ...)
{
- /* 0 = unknown, 1 = yes, -1 = no. */
-#if GNULIB_defined_O_CLOEXEC
- int have_cloexec = -1;
-#else
- static int have_cloexec;
-#endif
+ mode_t mode = 0;
- mode_t mode;
- int fd;
-
- mode = 0;
if (flags & O_CREAT)
{
va_list arg;
@@ -99,7 +100,6 @@ open (const char *filename, int flags, ...)
filename = "NUL";
#endif
-#if OPEN_TRAILING_SLASH_BUG
/* Fail if one of O_CREAT, O_WRONLY, O_RDWR is specified and the filename
ends in a slash, as POSIX says such a filename must name a directory
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>:
@@ -118,21 +118,55 @@ open (const char *filename, int flags, ...)
directories,
- if O_WRONLY or O_RDWR is specified, open() must fail because the
file does not contain a '.' directory. */
- if ((flags & O_CREAT)
- || (flags & O_ACCMODE) == O_RDWR
- || (flags & O_ACCMODE) == O_WRONLY)
+ bool check_for_slash_bug;
+ if (OPEN_TRAILING_SLASH_BUG)
{
size_t len = strlen (filename);
- if (len > 0 && filename[len - 1] == '/')
+ check_for_slash_bug = len && filename[len - 1] == '/';
+ }
+ else
+ check_for_slash_bug = false;
+
+ if (check_for_slash_bug
+ && (flags & O_CREAT
+ || (flags & O_ACCMODE) == O_RDWR
+ || (flags & O_ACCMODE) == O_WRONLY))
+ {
+ errno = EISDIR;
+ return -1;
+ }
+
+ /* With the trailing slash bug or without working O_DIRECTORY, check with
+ stat first lest we hang trying to open a fifo. Although there is
+ a race between this and opening the file, we can do no better.
+ After opening the file we will check again with fstat. */
+ bool check_directory =
+ (check_for_slash_bug
+ || (!HAVE_WORKING_O_DIRECTORY && flags & O_DIRECTORY));
+ if (check_directory)
+ {
+ struct stat statbuf;
+ if (lstatif (filename, &statbuf, flags) < 0)
{
- errno = EISDIR;
+ if (! (flags & O_CREAT && errno == ENOENT))
+ return -1;
+ }
+ else if (!S_ISDIR (statbuf.st_mode))
+ {
+ errno = ENOTDIR;
return -1;
}
}
+
+ /* 0 = unknown, 1 = yes, -1 = no. */
+#if GNULIB_defined_O_CLOEXEC
+ int have_cloexec = -1;
+#else
+ static int have_cloexec;
#endif
- fd = orig_open (filename,
- flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode);
+ int fd = orig_open (filename,
+ flags & ~(have_cloexec < 0 ? O_CLOEXEC : 0), mode);
if (flags & O_CLOEXEC)
{
@@ -154,19 +188,21 @@ open (const char *filename, int flags, ...)
#if REPLACE_FCHDIR
/* Implementing fchdir and fdopendir requires the ability to open a
directory file descriptor. If open doesn't support that (as on
- mingw), we use a dummy file that behaves the same as directories
+ mingw), use a dummy file that behaves the same as directories
on Linux (ie. always reports EOF on attempts to read()), and
- override fstat() in fchdir.c to hide the fact that we have a
- dummy. */
+ override fstat in fchdir.c to hide the dummy. */
if (REPLACE_OPEN_DIRECTORY && fd < 0 && errno == EACCES
- && ((flags & O_ACCMODE) == O_RDONLY
- || (O_SEARCH != O_RDONLY && (flags & O_ACCMODE) == O_SEARCH)))
+ && ((flags & (O_ACCMODE | O_CREAT)) == O_RDONLY
+ || (O_SEARCH != O_RDONLY
+ && (flags & (O_ACCMODE | O_CREAT)) == O_SEARCH)))
{
struct stat statbuf;
- if (stat (filename, &statbuf) == 0 && S_ISDIR (statbuf.st_mode))
+ if (check_directory
+ || (lstatif (filename, &statbuf, flags) == 0
+ && S_ISDIR (statbuf.st_mode)))
{
/* Maximum recursion depth of 1. */
- fd = open ("/dev/null", flags, mode);
+ fd = open ("/dev/null", flags & ~O_DIRECTORY, mode);
if (0 <= fd)
fd = _gl_register_fd (fd, filename);
}
@@ -175,10 +211,8 @@ open (const char *filename, int flags, ...)
}
#endif
-#if OPEN_TRAILING_SLASH_BUG
- /* If the filename ends in a slash and fd does not refer to a directory,
- then fail.
- Rationale: POSIX says such a filename must name a directory
+ /* If checking for directories, fail if fd does not refer to a directory.
+ Rationale: A filename ending in slash cannot name a non-directory
<https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13>:
"A pathname that contains at least one non-<slash> character and that
ends with one or more trailing <slash> characters shall not be resolved
@@ -186,23 +220,18 @@ open (const char *filename, int flags, ...)
<slash> characters names an existing directory"
If the named file without the slash is not a directory, open() must fail
with ENOTDIR. */
- if (fd >= 0)
+ if (check_directory && 0 <= fd)
{
- /* We know len is positive, since open did not fail with ENOENT. */
- size_t len = strlen (filename);
- if (filename[len - 1] == '/')
+ struct stat statbuf;
+ int r = fstat (fd, &statbuf);
+ if (r < 0 || !S_ISDIR (statbuf.st_mode))
{
- struct stat statbuf;
-
- if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode))
- {
- close (fd);
- errno = ENOTDIR;
- return -1;
- }
+ int err = r < 0 ? errno : ENOTDIR;
+ close (fd);
+ errno = err;
+ return -1;
}
}
-#endif
#if REPLACE_FCHDIR
if (!REPLACE_OPEN_DIRECTORY && 0 <= fd)
diff --git a/lib/qcopy-acl.c b/lib/qcopy-acl.c
index ad7966152aa..282f4b2d2a5 100644
--- a/lib/qcopy-acl.c
+++ b/lib/qcopy-acl.c
@@ -26,6 +26,7 @@
#if USE_XATTR
# include <attr/libattr.h>
+# include <dirent.h>
# include <string.h>
# if HAVE_LINUX_XATTR_H
@@ -61,6 +62,7 @@ is_attr_permissions (const char *name, struct error_context *ctx)
a valid file descriptor, use file descriptor operations, else use
filename based operations on SRC_NAME. Likewise for DEST_DESC and
DST_NAME.
+ MODE should be the source file's st_mode.
If access control lists are not available, fchmod the target file to
MODE. Also sets the non-permission bits of the destination file
(S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set.
@@ -86,10 +88,29 @@ qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
Functions attr_copy_* return 0 in case we copied something OR nothing
to copy */
if (ret == 0)
- ret = source_desc <= 0 || dest_desc <= 0
- ? attr_copy_file (src_name, dst_name, is_attr_permissions, NULL)
- : attr_copy_fd (src_name, source_desc, dst_name, dest_desc,
- is_attr_permissions, NULL);
+ {
+ ret = source_desc <= 0 || dest_desc <= 0
+ ? attr_copy_file (src_name, dst_name, is_attr_permissions, NULL)
+ : attr_copy_fd (src_name, source_desc, dst_name, dest_desc,
+ is_attr_permissions, NULL);
+
+ /* Copying can fail with EOPNOTSUPP even when the source
+ permissions are trivial (Bug#78328). Don't report an error
+ in this case, as the chmod_or_fchmod suffices. */
+ if (ret < 0 && errno == EOPNOTSUPP)
+ {
+ /* fdfile_has_aclinfo cares only about DT_DIR, _GL_DT_NOTDIR,
+ and DT_LNK (but DT_LNK is not possible here),
+ so use _GL_DT_NOTDIR | DT_UNKNOWN for other file types. */
+ int flags = S_ISDIR (mode) ? DT_DIR : _GL_DT_NOTDIR | DT_UNKNOWN;
+
+ struct aclinfo ai;
+ if (!fdfile_has_aclinfo (source_desc, src_name, &ai, flags))
+ ret = 0;
+ aclinfo_free (&ai);
+ errno = EOPNOTSUPP;
+ }
+ }
#else
/* no XATTR, so we proceed the old dusty way */
struct permission_context ctx;
diff --git a/lib/regcomp.c b/lib/regcomp.c
index a23f289d7a1..878b65baf07 100644
--- a/lib/regcomp.c
+++ b/lib/regcomp.c
@@ -1001,21 +1001,25 @@ create_initial_state (re_dfa_t *dfa)
Idx dest_idx = dfa->edests[node_idx].elems[0];
if (!re_node_set_contains (&init_nodes, dest_idx))
{
- reg_errcode_t merge_err
+ err
= re_node_set_merge (&init_nodes, dfa->eclosures + dest_idx);
- if (merge_err != REG_NOERROR)
- return merge_err;
+ if (err != REG_NOERROR)
+ break;
i = 0;
}
}
}
/* It must be the first time to invoke acquire_state. */
- dfa->init_state = re_acquire_state_context (&err, dfa, &init_nodes, 0);
- /* We don't check ERR here, since the initial state must not be NULL. */
+ dfa->init_state
+ = (err == REG_NOERROR
+ ? re_acquire_state_context (&err, dfa, &init_nodes, 0)
+ : NULL);
if (__glibc_unlikely (dfa->init_state == NULL))
- return err;
- if (dfa->init_state->has_constraint)
+ {
+ /* Don't check ERR here, as the initial state must not be null. */
+ }
+ else if (dfa->init_state->has_constraint)
{
dfa->init_state_word = re_acquire_state_context (&err, dfa, &init_nodes,
CONTEXT_WORD);
@@ -1025,17 +1029,13 @@ create_initial_state (re_dfa_t *dfa)
&init_nodes,
CONTEXT_NEWLINE
| CONTEXT_BEGBUF);
- if (__glibc_unlikely (dfa->init_state_word == NULL
- || dfa->init_state_nl == NULL
- || dfa->init_state_begbuf == NULL))
- return err;
}
else
dfa->init_state_word = dfa->init_state_nl
= dfa->init_state_begbuf = dfa->init_state;
re_node_set_free (&init_nodes);
- return REG_NOERROR;
+ return err;
}
/* If it is possible to do searching in single byte encoding instead of UTF-8
@@ -1677,12 +1677,11 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
{
err = duplicate_node_closure (dfa, node, node, node,
dfa->nodes[node].constraint);
- if (__glibc_unlikely (err != REG_NOERROR))
- return err;
}
/* Expand each epsilon destination nodes. */
- if (IS_EPSILON_NODE(dfa->nodes[node].type))
+ if (__glibc_likely (err == REG_NOERROR)
+ && IS_EPSILON_NODE (dfa->nodes[node].type))
for (i = 0; i < dfa->edests[node].nelem; ++i)
{
re_node_set eclosure_elem;
@@ -1700,14 +1699,14 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
{
err = calc_eclosure_iter (&eclosure_elem, dfa, edest, false);
if (__glibc_unlikely (err != REG_NOERROR))
- return err;
+ break;
}
else
eclosure_elem = dfa->eclosures[edest];
/* Merge the epsilon closure of 'edest'. */
err = re_node_set_merge (&eclosure, &eclosure_elem);
if (__glibc_unlikely (err != REG_NOERROR))
- return err;
+ break;
/* If the epsilon closure of 'edest' is incomplete,
the epsilon closure of this node is also incomplete. */
if (dfa->eclosures[edest].nelem == 0)
@@ -1717,12 +1716,18 @@ calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa, Idx node, bool root)
}
}
- if (incomplete && !root)
- dfa->eclosures[node].nelem = 0;
+ if (err != REG_NOERROR)
+ re_node_set_free (&eclosure);
else
- dfa->eclosures[node] = eclosure;
- *new_set = eclosure;
- return REG_NOERROR;
+ {
+ if (incomplete && !root)
+ dfa->eclosures[node].nelem = 0;
+ else
+ dfa->eclosures[node] = eclosure;
+ *new_set = eclosure;
+ }
+
+ return err;
}
/* Functions for token which are used in the parser. */
@@ -3275,6 +3280,7 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
else
{
free_charset (mbcset);
+ mbcset = NULL;
/* Build a tree for simple bracket. */
br_token.type = SIMPLE_BRACKET;
br_token.opr.sbcset = sbcset;
@@ -3288,7 +3294,8 @@ parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa, re_token_t *token,
*err = REG_ESPACE;
parse_bracket_exp_free_return:
re_free (sbcset);
- free_charset (mbcset);
+ if (__glibc_likely (mbcset != NULL))
+ free_charset (mbcset);
return NULL;
}
diff --git a/lib/regexec.c b/lib/regexec.c
index c5ab9b6649f..0d14ac35fe9 100644
--- a/lib/regexec.c
+++ b/lib/regexec.c
@@ -2271,7 +2271,7 @@ merge_state_with_log (reg_errcode_t *err, re_match_context_t *mctx,
these destinations and the results of the transition table. */
pstate = mctx->state_log[cur_idx];
log_nodes = pstate->entrance_nodes;
- if (next_state != NULL)
+ if (next_state != NULL && next_state->entrance_nodes != NULL)
{
table_nodes = next_state->entrance_nodes;
*err = re_node_set_init_union (&next_nodes, table_nodes,
diff --git a/lib/stat-time.h b/lib/stat-time.h
index 69813932d5e..38315b9f569 100644
--- a/lib/stat-time.h
+++ b/lib/stat-time.h
@@ -117,6 +117,31 @@ get_stat_birthtime_ns (_GL_UNUSED struct stat const *st)
# endif
}
+/* Constructs a 'struct timespec' with the given contents.
+ This macro / function is private to stat-time.h. */
+#if !defined __cplusplus
+/* Use a C99 compound literal.
+ This is guaranteed to initialize also the padding bits, for example on
+ platforms where tv_sec is 64 bits and tv_nsec is 32 bits, thus avoiding
+ gcc -Wuse-of-uninitialized-value warnings. */
+# define _gl_make_timespec(sec,nsec) \
+ (struct timespec) { .tv_sec = (sec), .tv_nsec = (nsec) }
+#else
+/* C++ does not have C99 compound literals.
+ A constructor invocation
+ timespec { (sec), (nsec) }
+ would make assumptions about the order of the fields of 'struct timespec',
+ which are not guaranteed by POSIX. So, use an inline function. */
+static inline struct timespec
+_gl_make_timespec (time_t sec, long nsec)
+{
+ struct timespec ts;
+ ts.tv_sec = sec;
+ ts.tv_nsec = nsec;
+ return ts;
+}
+#endif
+
/* Return *ST's access time. */
_GL_STAT_TIME_INLINE struct timespec _GL_ATTRIBUTE_PURE
get_stat_atime (struct stat const *st)
@@ -124,8 +149,7 @@ get_stat_atime (struct stat const *st)
#ifdef STAT_TIMESPEC
return STAT_TIMESPEC (st, st_atim);
#else
- return (struct timespec) { .tv_sec = st->st_atime,
- .tv_nsec = get_stat_atime_ns (st) };
+ return _gl_make_timespec (st->st_atime, get_stat_atime_ns (st));
#endif
}
@@ -136,8 +160,7 @@ get_stat_ctime (struct stat const *st)
#ifdef STAT_TIMESPEC
return STAT_TIMESPEC (st, st_ctim);
#else
- return (struct timespec) { .tv_sec = st->st_ctime,
- .tv_nsec = get_stat_ctime_ns (st) };
+ return _gl_make_timespec (st->st_ctime, get_stat_ctime_ns (st));
#endif
}
@@ -148,8 +171,7 @@ get_stat_mtime (struct stat const *st)
#ifdef STAT_TIMESPEC
return STAT_TIMESPEC (st, st_mtim);
#else
- return (struct timespec) { .tv_sec = st->st_mtime,
- .tv_nsec = get_stat_mtime_ns (st) };
+ return _gl_make_timespec (st->st_mtime, get_stat_mtime_ns (st));
#endif
}
@@ -164,8 +186,7 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st)
|| defined HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC)
t = STAT_TIMESPEC (st, st_birthtim);
#elif defined HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC
- t = (struct timespec) { .tv_sec = st->st_birthtime,
- .tv_nsec = st->st_birthtimensec };
+ t = _gl_make_timespec (st->st_birthtime, st->st_birthtimensec);
#elif defined _WIN32 && ! defined __CYGWIN__
/* Native Windows platforms (but not Cygwin) put the "file creation
time" in st_ctime (!). See
@@ -173,11 +194,11 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st)
# if _GL_WINDOWS_STAT_TIMESPEC
t = st->st_ctim;
# else
- t = (struct timespec) { .tv_sec = st->st_ctime };
+ t = _gl_make_timespec (st->st_ctime, 0);
# endif
#else
/* Birth time is not supported. */
- t = (struct timespec) { .tv_sec = -1, .tv_nsec = -1 };
+ t = _gl_make_timespec (-1, -1);
#endif
#if (defined HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC \
@@ -189,7 +210,7 @@ get_stat_birthtime (_GL_UNUSED struct stat const *st)
sometimes returns junk in the birth time fields; work around this
bug if it is detected. */
if (! (t.tv_sec && 0 <= t.tv_nsec && t.tv_nsec < 1000000000))
- t = (struct timespec) { .tv_sec = -1, .tv_nsec = -1 };
+ t = _gl_make_timespec (-1, -1);
#endif
return t;
diff --git a/lib/stdckdint.in.h b/lib/stdckdint.in.h
index 83277b728ee..bb9089b4a13 100644
--- a/lib/stdckdint.in.h
+++ b/lib/stdckdint.in.h
@@ -15,10 +15,30 @@
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
-#ifndef _GL_STDCKDINT_H
-#define _GL_STDCKDINT_H
+#if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
+#endif
+@PRAGMA_COLUMNS@
-#include "intprops-internal.h"
+#ifndef _@GUARD_PREFIX@_STDCKDINT_H
+
+/* The include_next requires a split double-inclusion guard. */
+#if defined __cplusplus ? @HAVE_CXX_STDCKDINT_H@ : @HAVE_C_STDCKDINT_H@
+# @INCLUDE_NEXT@ @NEXT_STDCKDINT_H@
+#endif
+
+#ifndef _@GUARD_PREFIX@_STDCKDINT_H
+#define _@GUARD_PREFIX@_STDCKDINT_H
+
+/* Do nothing but include the system header if it works properly. */
+# if defined __cplusplus ? !@HAVE_WORKING_CXX_STDCKDINT_H@ : !@HAVE_WORKING_C_STDCKDINT_H@
+
+/* Avoid redefining macros. */
+# undef ckd_add
+# undef ckd_sub
+# undef ckd_mul
+
+# include "intprops-internal.h"
/* Store into *R the low-order bits of A + B, A - B, A * B, respectively.
Return 1 if the result overflows, 0 otherwise.
@@ -26,10 +46,13 @@
bit-precise integer type, or an enumeration type.
These are like the standard macros introduced in C23, except that
- arguments should not have side effects. */
+ arguments should not have side effects. The C++26 standard is
+ expected to add this header and it's macros. */
-#define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r))
-#define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r))
-#define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r))
+# define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r))
+# define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r))
+# define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r))
-#endif /* _GL_STDCKDINT_H */
+# endif /* defined __cplusplus ? @HAVE_WORKING_CXX_STDCKDINT_H@ : @HAVE_WORKING_C_STDCKDINT_H@ */
+#endif /* _@GUARD_PREFIX@_STDCKDINT_H */
+#endif /* _@GUARD_PREFIX@_STDCKDINT_H */
diff --git a/lib/stddef.in.h b/lib/stddef.in.h
index dc689b8df80..e8c55ff1cdc 100644
--- a/lib/stddef.in.h
+++ b/lib/stddef.in.h
@@ -188,38 +188,57 @@ typedef union
#endif
/* ISO C 23 § 7.21.1 The unreachable macro */
-#ifndef unreachable
+/* This macro is only usable in C, not in C++.
+ There is no way to define it as a macro in C++, because that would break code
+ that does
+ #include <utility>
+ ... std::unreachable() ...
+ Similarly, there is no way to define it as an inline function in C++, because
+ that would break code that does
+ #include <utility>
+ using std::unreachable;
+ As a workaround, we define a macro gl_unreachable, that is like unreachable,
+ but is usable in both C and C++. */
/* Code borrowed from verify.h. */
-# ifndef _GL_HAS_BUILTIN_UNREACHABLE
-# if defined __clang_major__ && __clang_major__ < 5
-# define _GL_HAS_BUILTIN_UNREACHABLE 0
-# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) && !defined __clang__
-# define _GL_HAS_BUILTIN_UNREACHABLE 1
-# elif defined __has_builtin
-# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
-# else
-# define _GL_HAS_BUILTIN_UNREACHABLE 0
-# endif
+#ifndef _GL_HAS_BUILTIN_UNREACHABLE
+# if defined __clang_major__ && __clang_major__ < 5
+# define _GL_HAS_BUILTIN_UNREACHABLE 0
+# elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__) && !defined __clang__
+# define _GL_HAS_BUILTIN_UNREACHABLE 1
+# elif defined __has_builtin
+# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
+# else
+# define _GL_HAS_BUILTIN_UNREACHABLE 0
# endif
+#endif
-# if _GL_HAS_BUILTIN_UNREACHABLE
-# define unreachable() __builtin_unreachable ()
-# elif 1200 <= _MSC_VER
-# define unreachable() __assume (0)
-# else
+#if _GL_HAS_BUILTIN_UNREACHABLE
+# define gl_unreachable() __builtin_unreachable ()
+#elif 1200 <= _MSC_VER
+# define gl_unreachable() __assume (0)
+#elif !defined __cplusplus && @HAVE_C_UNREACHABLE@
+# define gl_unreachable() unreachable ()
+#else
/* Declare abort(), without including <stdlib.h>. */
extern
-# if defined __cplusplus
+# if defined __cplusplus
"C"
-# endif
+# endif
_Noreturn
void abort (void)
-# if defined __cplusplus && (__GLIBC__ >= 2)
+# if defined __cplusplus && (__GLIBC__ >= 2)
_GL_ATTRIBUTE_NOTHROW
-# endif
+# endif
;
-# define unreachable() abort ()
+# define gl_unreachable() abort ()
+#endif
+
+#if !defined __cplusplus && !@HAVE_C_UNREACHABLE@
+/* In C, define unreachable as a macro. */
+
+# ifndef unreachable
+# define unreachable() gl_unreachable ()
# endif
#endif
diff --git a/lib/string.in.h b/lib/string.in.h
index e7642211685..e3d94b76c17 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -215,25 +215,49 @@ _GL_EXTERN_C void free (void *);
/* Declarations for ISO C N3322. */
#if defined __GNUC__ && __GNUC__ >= 15 && !defined __clang__
_GL_EXTERN_C void *memcpy (void *__dest, const void *__src, size_t __n)
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+ _GL_ATTRIBUTE_NOTHROW
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
_GL_EXTERN_C void *memccpy (void *__dest, const void *__src, int __c, size_t __n)
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+ _GL_ATTRIBUTE_NOTHROW
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 4)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 4);
_GL_EXTERN_C void *memmove (void *__dest, const void *__src, size_t __n)
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+ _GL_ATTRIBUTE_NOTHROW
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
_GL_EXTERN_C char *strncpy (char *__dest, const char *__src, size_t __n)
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+ _GL_ATTRIBUTE_NOTHROW
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
_GL_EXTERN_C char *strndup (const char *__s, size_t __n)
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+ _GL_ATTRIBUTE_NOTHROW
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 2);
_GL_EXTERN_C char *strncat (char *__dest, const char *__src, size_t __n)
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+ _GL_ATTRIBUTE_NOTHROW
+# endif
_GL_ARG_NONNULL ((1)) _GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
_GL_EXTERN_C int memcmp (const void *__s1, const void *__s2, size_t __n)
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+ _GL_ATTRIBUTE_NOTHROW
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
_GL_EXTERN_C int strncmp (const char *__s1, const char *__s2, size_t __n)
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+ _GL_ATTRIBUTE_NOTHROW
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (2, 3);
# ifndef __cplusplus
@@ -243,6 +267,9 @@ _GL_EXTERN_C void *memrchr (const void *__s, int __c, size_t __n)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
# endif
_GL_EXTERN_C void *memset (void *__s, int __c, size_t __n)
+# if __GLIBC__ + (__GLIBC_MINOR__ >= 2) > 2
+ _GL_ATTRIBUTE_NOTHROW
+# endif
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
_GL_EXTERN_C void *memset_explicit (void *__s, int __c, size_t __n)
_GL_ATTRIBUTE_NONNULL_IF_NONZERO (1, 3);
diff --git a/lib/sys_stat.in.h b/lib/sys_stat.in.h
index 8bde5a7d631..c3c38fd653e 100644
--- a/lib/sys_stat.in.h
+++ b/lib/sys_stat.in.h
@@ -849,7 +849,11 @@ _GL_WARN_ON_USE (mknodat, "mknodat is not portable - "
# elif @WINDOWS_64_BIT_ST_SIZE@
/* Above, we define stat to _stati64. */
# if defined __MINGW32__ && defined _stati64
-# ifndef _USE_32BIT_TIME_T
+# ifdef _USE_32BIT_TIME_T
+ /* The system headers possibly define _stati64 to _stat32i64. */
+# undef _stat32i64
+# define _stat32i64(name, st) rpl_stat (name, st)
+# else
/* The system headers define _stati64 to _stat64. */
# undef _stat64
# define _stat64(name, st) rpl_stat (name, st)
diff --git a/lib/unistd.in.h b/lib/unistd.in.h
index c135a770dc1..9f057d30cdf 100644
--- a/lib/unistd.in.h
+++ b/lib/unistd.in.h
@@ -95,6 +95,15 @@
# include <stdio.h>
#endif
+/* Native Windows platforms declare _chdir, _getcwd, _rmdir in
+ <io.h> and/or <direct.h>, not in <unistd.h>.
+ They also declare _access(), _chmod(), _close(), _dup(), _dup2(), _isatty(),
+ _lseek(), _read(), _unlink(), _write() in <io.h>. */
+#if defined _WIN32 && !defined __CYGWIN__
+# include <io.h>
+# include <direct.h>
+#endif
+
/* FreeBSD 14.0, NetBSD 10.0, OpenBSD 7.5, Solaris 11.4, and glibc 2.41
do not define O_CLOEXEC in <unistd.h>. */
/* Cygwin 1.7.1 and Android 4.3 declare unlinkat in <fcntl.h>, not in
@@ -120,15 +129,6 @@
# undef __need_system_stdlib_h
#endif
-/* Native Windows platforms declare _chdir, _getcwd, _rmdir in
- <io.h> and/or <direct.h>, not in <unistd.h>.
- They also declare _access(), _chmod(), _close(), _dup(), _dup2(), _isatty(),
- _lseek(), _read(), _unlink(), _write() in <io.h>. */
-#if defined _WIN32 && !defined __CYGWIN__
-# include <io.h>
-# include <direct.h>
-#endif
-
/* Native Windows platforms declare _execl*, _execv* in <process.h>. */
#if defined _WIN32 && !defined __CYGWIN__
# include <process.h>