diff options
| author | Paul Eggert <eggert@cs.ucla.edu> | 2025-06-27 22:32:33 -0700 |
|---|---|---|
| committer | Paul Eggert <eggert@cs.ucla.edu> | 2025-06-27 23:06:40 -0700 |
| commit | dbdf761187d7cccfad20a2899bab3dc77f379c3a (patch) | |
| tree | d4e160b187f6f56e27dad185dfdd4cb955c4ec80 /lib | |
| parent | 68100ca656ad76e937622a1a74b6ca185bc82e07 (diff) | |
Update from Gnulib by running admin/merge-gnulib
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/_Noreturn.h | 38 | ||||
| -rw-r--r-- | lib/acl.h | 2 | ||||
| -rw-r--r-- | lib/attribute.h | 5 | ||||
| -rw-r--r-- | lib/boot-time.h | 13 | ||||
| -rw-r--r-- | lib/fcntl.in.h | 6 | ||||
| -rw-r--r-- | lib/file-has-acl.c | 173 | ||||
| -rw-r--r-- | lib/gettext.h | 67 | ||||
| -rw-r--r-- | lib/gnulib.mk.in | 18 | ||||
| -rw-r--r-- | lib/open.c | 115 | ||||
| -rw-r--r-- | lib/qcopy-acl.c | 29 | ||||
| -rw-r--r-- | lib/regcomp.c | 53 | ||||
| -rw-r--r-- | lib/regexec.c | 2 | ||||
| -rw-r--r-- | lib/stat-time.h | 43 | ||||
| -rw-r--r-- | lib/stdckdint.in.h | 39 | ||||
| -rw-r--r-- | lib/stddef.in.h | 61 | ||||
| -rw-r--r-- | lib/string.in.h | 27 | ||||
| -rw-r--r-- | lib/sys_stat.in.h | 6 | ||||
| -rw-r--r-- | lib/unistd.in.h | 18 |
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> |
