aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorPaul Eggert2025-12-07 15:34:42 -0800
committerPaul Eggert2025-12-07 15:45:20 -0800
commitb211e5489b95f39f07baa769fc581b05b393c4a3 (patch)
tree34f59c09f3779fdf25f32bccbe8aa48491ee5b4f /lib
parent0d43f2a562c84ff440da978a9275fc44e6f5d9da (diff)
downloademacs-b211e5489b95f39f07baa769fc581b05b393c4a3.tar.gz
emacs-b211e5489b95f39f07baa769fc581b05b393c4a3.zip
Update from Gnulib by running admin/merge-gnulib
* admin/merge-gnulib (AVOIDED_MODULES): Add strncpy, as Emacs is not likely to exercise the FreeBSD 15 strncpy bug that this module fixes. * lib/issymlinkat.h: New file, taken from Gnulib.
Diffstat (limited to 'lib')
-rw-r--r--lib/attribute.h8
-rw-r--r--lib/dup2.c43
-rw-r--r--lib/fchmodat.c2
-rw-r--r--lib/fcntl.c87
-rw-r--r--lib/file-has-acl.c4
-rw-r--r--lib/free.c4
-rw-r--r--lib/getloadavg.c4
-rw-r--r--lib/gnulib.mk.in7
-rw-r--r--lib/issymlink.h46
-rw-r--r--lib/issymlinkat.c2
-rw-r--r--lib/issymlinkat.h68
-rw-r--r--lib/lchmod.c1
-rw-r--r--lib/realloc.c2
-rw-r--r--lib/str-two-way.h86
-rw-r--r--lib/string.in.h29
-rw-r--r--lib/time_rz.c4
16 files changed, 262 insertions, 135 deletions
diff --git a/lib/attribute.h b/lib/attribute.h
index c85412d90af..f24f5b18f1e 100644
--- a/lib/attribute.h
+++ b/lib/attribute.h
@@ -257,7 +257,7 @@
257 calls to the function with the same arguments, so long as the state 257 calls to the function with the same arguments, so long as the state
258 addressed by its arguments is the same. 258 addressed by its arguments is the same.
259 This attribute is safe for a function that is effectless, idempotent, 259 This attribute is safe for a function that is effectless, idempotent,
260 stateless, and independent; see ISO C 23 § 6.7.12.7 for a definition of 260 stateless, and independent; see ISO C 23 § 6.7.13.8 for a definition of
261 these terms. 261 these terms.
262 (This attribute is stricter than REPRODUCIBLE because the function 262 (This attribute is stricter than REPRODUCIBLE because the function
263 must be stateless and independent. It is looser than ATTRIBUTE_CONST 263 must be stateless and independent. It is looser than ATTRIBUTE_CONST
@@ -266,7 +266,7 @@
266 See also <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2956.htm> and 266 See also <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2956.htm> and
267 <https://stackoverflow.com/questions/76847905/>. 267 <https://stackoverflow.com/questions/76847905/>.
268 ATTENTION! Efforts are underway to change the meaning of this attribute. 268 ATTENTION! Efforts are underway to change the meaning of this attribute.
269 See <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3424.htm>. */ 269 See <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3494.htm>. */
270/* Applies to: functions, pointer to functions, function type. */ 270/* Applies to: functions, pointer to functions, function type. */
271#define UNSEQUENCED _GL_ATTRIBUTE_UNSEQUENCED 271#define UNSEQUENCED _GL_ATTRIBUTE_UNSEQUENCED
272 272
@@ -287,7 +287,7 @@
287 addressed by its arguments is the same and is updated in time for 287 addressed by its arguments is the same and is updated in time for
288 the rest of the program. 288 the rest of the program.
289 This attribute is safe for a function that is effectless and idempotent; see 289 This attribute is safe for a function that is effectless and idempotent; see
290 ISO C 23 § 6.7.12.7 for a definition of these terms. 290 ISO C 23 § 6.7.13.8 for a definition of these terms.
291 (This attribute is looser than UNSEQUENCED because the function need 291 (This attribute is looser than UNSEQUENCED because the function need
292 not be stateless and idempotent. It is looser than ATTRIBUTE_PURE 292 not be stateless and idempotent. It is looser than ATTRIBUTE_PURE
293 because the function need not return exactly once and can affect 293 because the function need not return exactly once and can affect
@@ -295,7 +295,7 @@
295 See also <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2956.htm> and 295 See also <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2956.htm> and
296 <https://stackoverflow.com/questions/76847905/>. 296 <https://stackoverflow.com/questions/76847905/>.
297 ATTENTION! Efforts are underway to change the meaning of this attribute. 297 ATTENTION! Efforts are underway to change the meaning of this attribute.
298 See <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3424.htm>. */ 298 See <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3494.htm>. */
299/* Applies to: functions, pointer to functions, function type. */ 299/* Applies to: functions, pointer to functions, function type. */
300#define REPRODUCIBLE _GL_ATTRIBUTE_REPRODUCIBLE 300#define REPRODUCIBLE _GL_ATTRIBUTE_REPRODUCIBLE
301 301
diff --git a/lib/dup2.c b/lib/dup2.c
index 69b37196dee..434e78c2bc6 100644
--- a/lib/dup2.c
+++ b/lib/dup2.c
@@ -114,10 +114,10 @@ klibc_dup2dirfd (int fd, int desired_fd)
114 int dupfd; 114 int dupfd;
115 115
116 tempfd = open ("NUL", O_RDONLY); 116 tempfd = open ("NUL", O_RDONLY);
117 if (tempfd == -1) 117 if (tempfd < 0)
118 return -1; 118 return tempfd;
119 119
120 if (tempfd == desired_fd) 120 if (tempfd >= desired_fd)
121 { 121 {
122 close (tempfd); 122 close (tempfd);
123 123
@@ -125,7 +125,29 @@ klibc_dup2dirfd (int fd, int desired_fd)
125 if (__libc_Back_ioFHToPath (fd, path, sizeof (path))) 125 if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
126 return -1; 126 return -1;
127 127
128 return open(path, O_RDONLY); 128 for (;;)
129 {
130 close (desired_fd);
131
132 dupfd = open (path, O_RDONLY);
133 if (dupfd < 0)
134 return dupfd;
135
136 if (dupfd == desired_fd)
137 return dupfd;
138
139 /* If lower FD was closed by other threads, fill again. */
140 if (dupfd < desired_fd)
141 {
142 tempfd = dupfd;
143 break;
144 }
145
146 /* desired_fd was opened by other threads. Try again. */
147 /* FIXME: Closing desired_fd opened by other threads may lead to
148 unexpected behavior. */
149 close (dupfd);
150 }
129 } 151 }
130 152
131 dupfd = klibc_dup2dirfd (fd, desired_fd); 153 dupfd = klibc_dup2dirfd (fd, desired_fd);
@@ -142,13 +164,9 @@ klibc_dup2 (int fd, int desired_fd)
142 struct stat sbuf; 164 struct stat sbuf;
143 165
144 dupfd = dup2 (fd, desired_fd); 166 dupfd = dup2 (fd, desired_fd);
145 if (dupfd == -1 && errno == ENOTSUP \ 167 if (dupfd < 0 && errno == ENOTSUP \
146 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode)) 168 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
147 { 169 return klibc_dup2dirfd (fd, desired_fd);
148 close (desired_fd);
149
150 return klibc_dup2dirfd (fd, desired_fd);
151 }
152 170
153 return dupfd; 171 return dupfd;
154} 172}
@@ -179,10 +197,11 @@ rpl_dup2 (int fd, int desired_fd)
179 result = dup2 (fd, desired_fd); 197 result = dup2 (fd, desired_fd);
180 198
181 /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */ 199 /* Correct an errno value on FreeBSD 6.1 and Cygwin 1.5.x. */
182 if (result == -1 && errno == EMFILE) 200 if (result < 0 && errno == EMFILE)
183 errno = EBADF; 201 errno = EBADF;
202
184#if REPLACE_FCHDIR 203#if REPLACE_FCHDIR
185 if (fd != desired_fd && result != -1) 204 if (! (result < 0 || fd == desired_fd))
186 result = _gl_register_dup (fd, result); 205 result = _gl_register_dup (fd, result);
187#endif 206#endif
188 return result; 207 return result;
diff --git a/lib/fchmodat.c b/lib/fchmodat.c
index 9151778b8e3..4aa764f8510 100644
--- a/lib/fchmodat.c
+++ b/lib/fchmodat.c
@@ -46,7 +46,7 @@ orig_fchmodat (int dir, char const *file, mode_t mode, int flags)
46 46
47#include <intprops.h> 47#include <intprops.h>
48 48
49#include "issymlink.h" 49#include "issymlinkat.h"
50 50
51/* Invoke chmod or lchmod on FILE, using mode MODE, in the directory 51/* Invoke chmod or lchmod on FILE, using mode MODE, in the directory
52 open on descriptor FD. If possible, do it without changing the 52 open on descriptor FD. If possible, do it without changing the
diff --git a/lib/fcntl.c b/lib/fcntl.c
index 29cb4f9eb84..abdd7b89890 100644
--- a/lib/fcntl.c
+++ b/lib/fcntl.c
@@ -29,8 +29,8 @@
29#include <unistd.h> 29#include <unistd.h>
30 30
31#ifdef __KLIBC__ 31#ifdef __KLIBC__
32# define INCL_DOS 32# include <emx/io.h>
33# include <os2.h> 33# include <InnoTekLIBC/backend.h>
34#endif 34#endif
35 35
36#if defined _WIN32 && ! defined __CYGWIN__ 36#if defined _WIN32 && ! defined __CYGWIN__
@@ -539,6 +539,41 @@ rpl_fcntl_DUPFD_CLOEXEC (int fd, int target)
539#undef fcntl 539#undef fcntl
540 540
541#ifdef __KLIBC__ 541#ifdef __KLIBC__
542static int
543klibc_dupdirfd (int fd, int minfd)
544{
545 int tempfd;
546 int dupfd;
547
548 tempfd = open ("NUL", O_RDONLY);
549 if (tempfd == -1)
550 return -1;
551
552 if (tempfd >= minfd)
553 {
554 close (tempfd);
555
556 char path[_MAX_PATH];
557 if (__libc_Back_ioFHToPath (fd, path, sizeof (path)))
558 return -1;
559
560 dupfd = open (path, O_RDONLY);
561 if (dupfd == -1)
562 return -1;
563
564 if (dupfd >= minfd)
565 return dupfd;
566
567 /* Lower FD was closed by other threads. Fill again. */
568 tempfd = dupfd;
569 }
570
571 dupfd = klibc_dupdirfd (fd, minfd);
572
573 close (tempfd);
574
575 return dupfd;
576}
542 577
543static int 578static int
544klibc_fcntl (int fd, int action, /* arg */...) 579klibc_fcntl (int fd, int action, /* arg */...)
@@ -555,46 +590,50 @@ klibc_fcntl (int fd, int action, /* arg */...)
555 if (result == -1 && (errno == EPERM || errno == ENOTSUP) 590 if (result == -1 && (errno == EPERM || errno == ENOTSUP)
556 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode)) 591 && !fstat (fd, &sbuf) && S_ISDIR (sbuf.st_mode))
557 { 592 {
558 ULONG ulMode; 593 PLIBCFH pFH;
594 unsigned fFlags;
559 595
560 switch (action) 596 switch (action)
561 { 597 {
562 case F_DUPFD: 598 case F_DUPFD:
563 /* Find available fd */ 599 result = klibc_dupdirfd (fd, arg);
564 while (fcntl (arg, F_GETFL) != -1 || errno != EBADF)
565 arg++;
566
567 result = dup2 (fd, arg);
568 break; 600 break;
569 601
570 /* Using underlying APIs is right ? */
571 case F_GETFD: 602 case F_GETFD:
572 if (DosQueryFHState (fd, &ulMode)) 603 pFH = __libc_FH (fd);
573 break; 604 if (!pFH)
605 {
606 errno = EBADF;
607 break;
608 }
574 609
575 result = (ulMode & OPEN_FLAGS_NOINHERIT) ? FD_CLOEXEC : 0; 610 result = (pFH->fFlags & ((FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT )
611 | O_NOINHERIT)) ? FD_CLOEXEC : 0;
576 break; 612 break;
577 613
578 case F_SETFD: 614 case F_SETFD:
579 if (arg & ~FD_CLOEXEC) 615 if (arg & ~FD_CLOEXEC)
580 break; 616 break;
581 617
582 if (DosQueryFHState (fd, &ulMode)) 618 pFH = __libc_FH (fd);
583 break; 619 if (!pFH)
620 {
621 errno = EBADF;
622 break;
623 }
584 624
625 fFlags = pFH->fFlags;
585 if (arg & FD_CLOEXEC) 626 if (arg & FD_CLOEXEC)
586 ulMode |= OPEN_FLAGS_NOINHERIT; 627 fFlags |= (FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT) | O_NOINHERIT;
587 else 628 else
588 ulMode &= ~OPEN_FLAGS_NOINHERIT; 629 fFlags &= ~((FD_CLOEXEC << __LIBC_FH_FDFLAGS_SHIFT) | O_NOINHERIT);
589 630
590 /* Filter supported flags. */ 631 result = __libc_FHSetFlags (pFH, fd, fFlags);
591 ulMode &= (OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR 632 if (result < 0)
592 | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT); 633 {
593 634 errno = -result;
594 if (DosSetFHState (fd, ulMode)) 635 result = -1;
595 break; 636 }
596
597 result = 0;
598 break; 637 break;
599 638
600 case F_GETFL: 639 case F_GETFL:
diff --git a/lib/file-has-acl.c b/lib/file-has-acl.c
index b1eb1f2e8e7..9a5a18aabcf 100644
--- a/lib/file-has-acl.c
+++ b/lib/file-has-acl.c
@@ -399,9 +399,9 @@ acl_get_link_np (char const *name, acl_type_t type)
399 if (fd < 0) 399 if (fd < 0)
400 return NULL; 400 return NULL;
401 acl_t r = acl_get_fd (fd); 401 acl_t r = acl_get_fd (fd);
402 int err = errno; 402 int saved_errno = errno;
403 close (fd); 403 close (fd);
404 errno = err; 404 errno = saved_errno;
405 return r; 405 return r;
406} 406}
407# define HAVE_ACL_GET_LINK_NP 1 407# define HAVE_ACL_GET_LINK_NP 1
diff --git a/lib/free.c b/lib/free.c
index 394d8d13905..3a6577f13fa 100644
--- a/lib/free.c
+++ b/lib/free.c
@@ -44,9 +44,9 @@ rpl_free (void *p)
44 free (p); 44 free (p);
45 errno = err[errno == 0]; 45 errno = err[errno == 0];
46# else 46# else
47 int err = errno; 47 int saved_errno = errno;
48 free (p); 48 free (p);
49 errno = err; 49 errno = saved_errno;
50# endif 50# endif
51} 51}
52 52
diff --git a/lib/getloadavg.c b/lib/getloadavg.c
index f9ed97b04bd..ec7305f5d48 100644
--- a/lib/getloadavg.c
+++ b/lib/getloadavg.c
@@ -551,11 +551,11 @@ getloadavg (double loadavg[], int nelem)
551 if (fd < 0) 551 if (fd < 0)
552 return fd; 552 return fd;
553 int nread = read (fd, readbuf, sizeof readbuf - 1); 553 int nread = read (fd, readbuf, sizeof readbuf - 1);
554 int err = errno; 554 int saved_errno = errno;
555 close (fd); 555 close (fd);
556 if (nread < 0) 556 if (nread < 0)
557 { 557 {
558 errno = err; 558 errno = saved_errno;
559 return -1; 559 return -1;
560 } 560 }
561 readbuf[nread] = '\0'; 561 readbuf[nread] = '\0';
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 96d9cd8bd44..297af181c57 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -71,6 +71,7 @@
71# --avoid=stat \ 71# --avoid=stat \
72# --avoid=std-gnu11 \ 72# --avoid=std-gnu11 \
73# --avoid=stdarg-h \ 73# --avoid=stdarg-h \
74# --avoid=strncpy \
74# --avoid=threadlib \ 75# --avoid=threadlib \
75# --avoid=tzset \ 76# --avoid=tzset \
76# --avoid=unsetenv \ 77# --avoid=unsetenv \
@@ -631,6 +632,7 @@ GL_GNULIB_STRERROR_R = @GL_GNULIB_STRERROR_R@
631GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@ 632GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@
632GL_GNULIB_STRINGEQ = @GL_GNULIB_STRINGEQ@ 633GL_GNULIB_STRINGEQ = @GL_GNULIB_STRINGEQ@
633GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@ 634GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@
635GL_GNULIB_STRNCPY = @GL_GNULIB_STRNCPY@
634GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@ 636GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@
635GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@ 637GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@
636GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@ 638GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@
@@ -1327,6 +1329,7 @@ REPLACE_STRERROR_L = @REPLACE_STRERROR_L@
1327REPLACE_STRERROR_R = @REPLACE_STRERROR_R@ 1329REPLACE_STRERROR_R = @REPLACE_STRERROR_R@
1328REPLACE_STRFTIME = @REPLACE_STRFTIME@ 1330REPLACE_STRFTIME = @REPLACE_STRFTIME@
1329REPLACE_STRNCAT = @REPLACE_STRNCAT@ 1331REPLACE_STRNCAT = @REPLACE_STRNCAT@
1332REPLACE_STRNCPY = @REPLACE_STRNCPY@
1330REPLACE_STRNDUP = @REPLACE_STRNDUP@ 1333REPLACE_STRNDUP = @REPLACE_STRNDUP@
1331REPLACE_STRNLEN = @REPLACE_STRNLEN@ 1334REPLACE_STRNLEN = @REPLACE_STRNLEN@
1332REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@ 1335REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@
@@ -2650,7 +2653,7 @@ ifneq (,$(gl_GNULIB_ENABLED_issymlinkat_CONDITION))
2650libgnu_a_SOURCES += issymlinkat.c 2653libgnu_a_SOURCES += issymlinkat.c
2651 2654
2652endif 2655endif
2653EXTRA_DIST += issymlink.h 2656EXTRA_DIST += issymlinkat.h
2654 2657
2655endif 2658endif
2656## end gnulib module issymlinkat 2659## end gnulib module issymlinkat
@@ -3757,6 +3760,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
3757 -e 's/@''GNULIB_STRDUP''@/$(GL_GNULIB_STRDUP)/g' \ 3760 -e 's/@''GNULIB_STRDUP''@/$(GL_GNULIB_STRDUP)/g' \
3758 -e 's/@''GNULIB_STRINGEQ''@/$(GL_GNULIB_STRINGEQ)/g' \ 3761 -e 's/@''GNULIB_STRINGEQ''@/$(GL_GNULIB_STRINGEQ)/g' \
3759 -e 's/@''GNULIB_STRNCAT''@/$(GL_GNULIB_STRNCAT)/g' \ 3762 -e 's/@''GNULIB_STRNCAT''@/$(GL_GNULIB_STRNCAT)/g' \
3763 -e 's/@''GNULIB_STRNCPY''@/$(GL_GNULIB_STRNCPY)/g' \
3760 -e 's/@''GNULIB_STRNDUP''@/$(GL_GNULIB_STRNDUP)/g' \ 3764 -e 's/@''GNULIB_STRNDUP''@/$(GL_GNULIB_STRNDUP)/g' \
3761 -e 's/@''GNULIB_STRNLEN''@/$(GL_GNULIB_STRNLEN)/g' \ 3765 -e 's/@''GNULIB_STRNLEN''@/$(GL_GNULIB_STRNLEN)/g' \
3762 -e 's/@''GNULIB_STRPBRK''@/$(GL_GNULIB_STRPBRK)/g' \ 3766 -e 's/@''GNULIB_STRPBRK''@/$(GL_GNULIB_STRPBRK)/g' \
@@ -3818,6 +3822,7 @@ string.h: string.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H
3818 -e 's|@''REPLACE_STRCHRNUL''@|$(REPLACE_STRCHRNUL)|g' \ 3822 -e 's|@''REPLACE_STRCHRNUL''@|$(REPLACE_STRCHRNUL)|g' \
3819 -e 's|@''REPLACE_STRDUP''@|$(REPLACE_STRDUP)|g' \ 3823 -e 's|@''REPLACE_STRDUP''@|$(REPLACE_STRDUP)|g' \
3820 -e 's|@''REPLACE_STRNCAT''@|$(REPLACE_STRNCAT)|g' \ 3824 -e 's|@''REPLACE_STRNCAT''@|$(REPLACE_STRNCAT)|g' \
3825 -e 's|@''REPLACE_STRNCPY''@|$(REPLACE_STRNCPY)|g' \
3821 -e 's|@''REPLACE_STRNDUP''@|$(REPLACE_STRNDUP)|g' \ 3826 -e 's|@''REPLACE_STRNDUP''@|$(REPLACE_STRNDUP)|g' \
3822 -e 's|@''REPLACE_STRNLEN''@|$(REPLACE_STRNLEN)|g' \ 3827 -e 's|@''REPLACE_STRNLEN''@|$(REPLACE_STRNLEN)|g' \
3823 -e 's|@''REPLACE_STRSTR''@|$(REPLACE_STRSTR)|g' \ 3828 -e 's|@''REPLACE_STRSTR''@|$(REPLACE_STRSTR)|g' \
diff --git a/lib/issymlink.h b/lib/issymlink.h
index af6dc965645..a3f97cb5211 100644
--- a/lib/issymlink.h
+++ b/lib/issymlink.h
@@ -23,7 +23,7 @@
23#endif 23#endif
24 24
25#include <errno.h> 25#include <errno.h>
26#include <unistd.h> /* for readlink, readlinkat */ 26#include <unistd.h> /* for readlink */
27 27
28 28
29_GL_INLINE_HEADER_BEGIN 29_GL_INLINE_HEADER_BEGIN
@@ -31,11 +31,7 @@ _GL_INLINE_HEADER_BEGIN
31#ifndef _GL_ISSYMLINK_INLINE 31#ifndef _GL_ISSYMLINK_INLINE
32# define _GL_ISSYMLINK_INLINE _GL_INLINE 32# define _GL_ISSYMLINK_INLINE _GL_INLINE
33#endif 33#endif
34#ifndef _GL_ISSYMLINKAT_INLINE
35# define _GL_ISSYMLINKAT_INLINE _GL_INLINE
36#endif
37 34
38#if GNULIB_ISSYMLINK
39/* Tests whether FILENAME represents a symbolic link. 35/* Tests whether FILENAME represents a symbolic link.
40 This function is more reliable than lstat() / fstatat() followed by S_ISLNK, 36 This function is more reliable than lstat() / fstatat() followed by S_ISLNK,
41 because it avoids possible EOVERFLOW errors. 37 because it avoids possible EOVERFLOW errors.
@@ -44,9 +40,9 @@ _GL_INLINE_HEADER_BEGIN
44 0 if FILENAME exists and is not a symbolic link, 40 0 if FILENAME exists and is not a symbolic link,
45 -1 with errno set if determination failed, in particular 41 -1 with errno set if determination failed, in particular
46 -1 with errno = ENOENT or ENOTDIR if FILENAME does not exist. */ 42 -1 with errno = ENOENT or ENOTDIR if FILENAME does not exist. */
47# ifdef __cplusplus 43#ifdef __cplusplus
48extern "C" { 44extern "C" {
49# endif 45#endif
50_GL_ISSYMLINK_INLINE int issymlink (const char *filename) 46_GL_ISSYMLINK_INLINE int issymlink (const char *filename)
51 _GL_ARG_NONNULL ((1)); 47 _GL_ARG_NONNULL ((1));
52_GL_ISSYMLINK_INLINE int 48_GL_ISSYMLINK_INLINE int
@@ -60,42 +56,8 @@ issymlink (const char *filename)
60 else 56 else
61 return -1; 57 return -1;
62} 58}
63# ifdef __cplusplus 59#ifdef __cplusplus
64}
65# endif
66#endif
67
68#if GNULIB_ISSYMLINKAT
69/* Tests whether FILENAME represents a symbolic link.
70 This function is more reliable than lstat() / fstatat() followed by S_ISLNK,
71 because it avoids possible EOVERFLOW errors.
72 If FILENAME is a relative file name, it is interpreted as relative to the
73 directory referred to by FD (where FD = AT_FDCWD denotes the current
74 directory).
75 Returns
76 1 if FILENAME is a symbolic link,
77 0 if FILENAME exists and is not a symbolic link,
78 -1 with errno set if determination failed, in particular
79 -1 with errno = ENOENT or ENOTDIR if FILENAME does not exist. */
80# ifdef __cplusplus
81extern "C" {
82# endif
83_GL_ISSYMLINKAT_INLINE int issymlinkat (int fd, const char *filename)
84 _GL_ARG_NONNULL ((2));
85_GL_ISSYMLINKAT_INLINE int
86issymlinkat (int fd, const char *filename)
87{
88 char linkbuf[1];
89 if (readlinkat (fd, filename, linkbuf, sizeof (linkbuf)) >= 0)
90 return 1;
91 if (errno == EINVAL)
92 return 0;
93 else
94 return -1;
95}
96# ifdef __cplusplus
97} 60}
98# endif
99#endif 61#endif
100 62
101_GL_INLINE_HEADER_END 63_GL_INLINE_HEADER_END
diff --git a/lib/issymlinkat.c b/lib/issymlinkat.c
index 8286356c8a2..ebd937e91bc 100644
--- a/lib/issymlinkat.c
+++ b/lib/issymlinkat.c
@@ -17,4 +17,4 @@
17#include <config.h> 17#include <config.h>
18 18
19#define _GL_ISSYMLINKAT_INLINE _GL_EXTERN_INLINE 19#define _GL_ISSYMLINKAT_INLINE _GL_EXTERN_INLINE
20#include "issymlink.h" 20#include "issymlinkat.h"
diff --git a/lib/issymlinkat.h b/lib/issymlinkat.h
new file mode 100644
index 00000000000..abbbbfff837
--- /dev/null
+++ b/lib/issymlinkat.h
@@ -0,0 +1,68 @@
1/* Test whether a file is a symbolic link.
2 Copyright (C) 2025 Free Software Foundation, Inc.
3
4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU Lesser General Public License as
6 published by the Free Software Foundation; either version 2.1 of the
7 License, or (at your option) any later version.
8
9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17#ifndef _ISSYMLINKAT_H
18#define _ISSYMLINKAT_H
19
20/* This file uses _GL_ARG_NONNULL, _GL_INLINE. */
21#if !_GL_CONFIG_H_INCLUDED
22 #error "Please include config.h first."
23#endif
24
25#include <errno.h>
26#include <unistd.h> /* for readlinkat */
27
28
29_GL_INLINE_HEADER_BEGIN
30
31#ifndef _GL_ISSYMLINKAT_INLINE
32# define _GL_ISSYMLINKAT_INLINE _GL_INLINE
33#endif
34
35/* Tests whether FILENAME represents a symbolic link.
36 This function is more reliable than lstat() / fstatat() followed by S_ISLNK,
37 because it avoids possible EOVERFLOW errors.
38 If FILENAME is a relative file name, it is interpreted as relative to the
39 directory referred to by FD (where FD = AT_FDCWD denotes the current
40 directory).
41 Returns
42 1 if FILENAME is a symbolic link,
43 0 if FILENAME exists and is not a symbolic link,
44 -1 with errno set if determination failed, in particular
45 -1 with errno = ENOENT or ENOTDIR if FILENAME does not exist. */
46#ifdef __cplusplus
47extern "C" {
48#endif
49_GL_ISSYMLINKAT_INLINE int issymlinkat (int fd, const char *filename)
50 _GL_ARG_NONNULL ((2));
51_GL_ISSYMLINKAT_INLINE int
52issymlinkat (int fd, const char *filename)
53{
54 char linkbuf[1];
55 if (readlinkat (fd, filename, linkbuf, sizeof (linkbuf)) >= 0)
56 return 1;
57 if (errno == EINVAL)
58 return 0;
59 else
60 return -1;
61}
62#ifdef __cplusplus
63}
64#endif
65
66_GL_INLINE_HEADER_END
67
68#endif /* _ISSYMLINKAT_H */
diff --git a/lib/lchmod.c b/lib/lchmod.c
index deba4c50f5b..acccef629cc 100644
--- a/lib/lchmod.c
+++ b/lib/lchmod.c
@@ -30,6 +30,7 @@
30 30
31#include <intprops.h> 31#include <intprops.h>
32#include "issymlink.h" 32#include "issymlink.h"
33#include "issymlinkat.h"
33 34
34/* Work like chmod, except when FILE is a symbolic link. 35/* Work like chmod, except when FILE is a symbolic link.
35 In that case, on systems where permissions on symbolic links are unsupported 36 In that case, on systems where permissions on symbolic links are unsupported
diff --git a/lib/realloc.c b/lib/realloc.c
index 62efd5a39ff..cf0bf6e9f70 100644
--- a/lib/realloc.c
+++ b/lib/realloc.c
@@ -94,7 +94,7 @@ rpl_realloc (void *p, size_t n)
94 94
95 void *result = realloc (p, n1); 95 void *result = realloc (p, n1);
96 96
97# if !HAVE_MALLOC_POSIX 97# if !HAVE_REALLOC_POSIX
98 if (result == NULL) 98 if (result == NULL)
99 errno = ENOMEM; 99 errno = ENOMEM;
100# endif 100# endif
diff --git a/lib/str-two-way.h b/lib/str-two-way.h
index 852e5d078f2..1da773eb70e 100644
--- a/lib/str-two-way.h
+++ b/lib/str-two-way.h
@@ -374,32 +374,34 @@ two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
374 } 374 }
375 memory = 0; 375 memory = 0;
376 j += shift; 376 j += shift;
377 continue;
378 }
379 /* Scan for matches in right half. The last byte has
380 already been matched, by virtue of the shift table. */
381 size_t i = MAX (suffix, memory);
382 while (i < needle_len - 1 && (CANON_ELEMENT (needle[i])
383 == CANON_ELEMENT (haystack[i + j])))
384 ++i;
385 if (needle_len - 1 <= i)
386 {
387 /* Scan for matches in left half. */
388 i = suffix - 1;
389 while (memory < i + 1 && (CANON_ELEMENT (needle[i])
390 == CANON_ELEMENT (haystack[i + j])))
391 --i;
392 if (i + 1 < memory + 1)
393 return (RETURN_TYPE) (haystack + j);
394 /* No match, so remember how many repetitions of period
395 on the right half were scanned. */
396 j += period;
397 memory = needle_len - period;
398 } 377 }
399 else 378 else
400 { 379 {
401 j += i - suffix + 1; 380 /* Scan for matches in right half. The last byte has
402 memory = 0; 381 already been matched, by virtue of the shift table. */
382 size_t i = MAX (suffix, memory);
383 while (i < needle_len - 1 && (CANON_ELEMENT (needle[i])
384 == CANON_ELEMENT (haystack[i + j])))
385 ++i;
386 if (needle_len - 1 <= i)
387 {
388 /* Scan for matches in left half. */
389 i = suffix - 1;
390 while (memory < i + 1 && (CANON_ELEMENT (needle[i])
391 == CANON_ELEMENT (haystack[i + j])))
392 --i;
393 if (i + 1 < memory + 1)
394 return (RETURN_TYPE) (haystack + j);
395 /* No match, so remember how many repetitions of period
396 on the right half were scanned. */
397 j += period;
398 memory = needle_len - period;
399 }
400 else
401 {
402 j += i - suffix + 1;
403 memory = 0;
404 }
403 } 405 }
404 } 406 }
405 } 407 }
@@ -418,27 +420,29 @@ two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
418 if (0 < shift) 420 if (0 < shift)
419 { 421 {
420 j += shift; 422 j += shift;
421 continue;
422 } 423 }
423 /* Scan for matches in right half. The last byte has 424 else
424 already been matched, by virtue of the shift table. */
425 size_t i = suffix;
426 while (i < needle_len - 1 && (CANON_ELEMENT (needle[i])
427 == CANON_ELEMENT (haystack[i + j])))
428 ++i;
429 if (needle_len - 1 <= i)
430 { 425 {
431 /* Scan for matches in left half. */ 426 /* Scan for matches in right half. The last byte has
432 i = suffix - 1; 427 already been matched, by virtue of the shift table. */
433 while (i != SIZE_MAX && (CANON_ELEMENT (needle[i]) 428 size_t i = suffix;
434 == CANON_ELEMENT (haystack[i + j]))) 429 while (i < needle_len - 1 && (CANON_ELEMENT (needle[i])
435 --i; 430 == CANON_ELEMENT (haystack[i + j])))
436 if (i == SIZE_MAX) 431 ++i;
437 return (RETURN_TYPE) (haystack + j); 432 if (needle_len - 1 <= i)
438 j += period; 433 {
434 /* Scan for matches in left half. */
435 i = suffix - 1;
436 while (i != SIZE_MAX && (CANON_ELEMENT (needle[i])
437 == CANON_ELEMENT (haystack[i + j])))
438 --i;
439 if (i == SIZE_MAX)
440 return (RETURN_TYPE) (haystack + j);
441 j += period;
442 }
443 else
444 j += i - suffix + 1;
439 } 445 }
440 else
441 j += i - suffix + 1;
442 } 446 }
443 } 447 }
444 return NULL; 448 return NULL;
diff --git a/lib/string.in.h b/lib/string.in.h
index a323b1cd6da..f316878b4c9 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -840,6 +840,35 @@ _GL_WARN_ON_USE (strncat, "strncat is unportable - "
840# endif 840# endif
841#endif 841#endif
842 842
843/* Copy no more than N bytes of SRC to DST, returning DST. */
844#if @GNULIB_STRNCPY@
845# if @REPLACE_STRNCPY@
846# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
847# undef strncpy
848# define strncpy rpl_strncpy
849# endif
850_GL_FUNCDECL_RPL (strncpy, char *,
851 (char *restrict __dst, char const *restrict __src,
852 size_t __n),
853 _GL_ARG_NONNULL ((1, 2)));
854_GL_CXXALIAS_RPL (strncpy, char *,
855 (char *restrict __dst, char const *restrict __src,
856 size_t __n));
857# else
858_GL_CXXALIAS_SYS (strncpy, char *,
859 (char *restrict __dst, char const *restrict __src,
860 size_t __n));
861# endif
862# if __GLIBC__ >= 2
863_GL_CXXALIASWARN (strncpy);
864# endif
865#elif defined GNULIB_POSIXCHECK
866# if HAVE_RAW_DECL_STRNCPY
867_GL_WARN_ON_USE (strncpy, "strncpy is unportable - "
868 "use gnulib module strncpy for portability");
869# endif
870#endif
871
843/* Return a newly allocated copy of at most N bytes of STRING. */ 872/* Return a newly allocated copy of at most N bytes of STRING. */
844#if @GNULIB_STRNDUP@ 873#if @GNULIB_STRNDUP@
845# if @REPLACE_STRNDUP@ 874# if @REPLACE_STRNDUP@
diff --git a/lib/time_rz.c b/lib/time_rz.c
index 8a8eb44c357..116ac39ad2d 100644
--- a/lib/time_rz.c
+++ b/lib/time_rz.c
@@ -57,9 +57,9 @@ void
57tzfree (timezone_t tz) 57tzfree (timezone_t tz)
58# undef tzfree 58# undef tzfree
59{ 59{
60 int err = errno; 60 int saved_errno = errno;
61 tzfree (tz); 61 tzfree (tz);
62 errno = err; 62 errno = saved_errno;
63} 63}
64 64
65#else 65#else