+2025-08-14 Bruno Haible <bruno@clisp.org>
+
+ issymlink, issymlinkat: New modules.
+ * lib/sys_stat.in.h: Invoke _GL_INLINE_HEADER_BEGIN,
+ _GL_INLINE_HEADER_END. Include <errno.h>, <unistd.h>.
+ (_GL_ISSYMLINK_INLINE, _GL_ISSYMLINKAT_INLINE): New macros.
+ (issymlink, issymlinkat): New declarations.
+ * lib/unistd.in.h: Do the #include <fcntl.h>, when needed for O_CLOEXEC,
+ at the end of the file. So that when <fcntl.h> includes <sys/stat.h>,
+ the declarations of readlink() and readlinkat() on native Windows are
+ already present.
+ * lib/issymlink.c: New file.
+ * lib/issymlinkat.c: New file.
+ * m4/sys_stat_h.m4 (gl_SYS_STAT_H_REQUIRE_DEFAULTS): Initialize
+ GNULIB_ISSYMLINK, GNULIB_ISSYMLINKAT.
+ * modules/sys_stat-h (Depends-on): Add extern-inline.
+ (Makefile.am): Substitute GNULIB_ISSYMLINK, GNULIB_ISSYMLINKAT.
+ * modules/issymlink: New file.
+ * modules/issymlinkat: New file.
+
2025-08-11 Paul Eggert <eggert@cs.ucla.edu>
manywarnings: update C warnings for GCC 15.2
--- /dev/null
+/* Test whether a file is a symbolic link.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ 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/>. */
+
+#include <config.h>
+
+#define _GL_ISSYMLINK_INLINE _GL_EXTERN_INLINE
+#include <sys/stat.h>
--- /dev/null
+/* Test whether a file is a symbolic link.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#define _GL_ISSYMLINKAT_INLINE _GL_EXTERN_INLINE
+#include <sys/stat.h>
#define _@GUARD_PREFIX@_SYS_STAT_H
/* This file uses _GL_ATTRIBUTE_NODISCARD, _GL_ATTRIBUTE_NOTHROW,
- GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
+ _GL_INLINE, GNULIB_POSIXCHECK, HAVE_RAW_DECL_*. */
#if !_GL_CONFIG_H_INCLUDED
#error "Please include config.h first."
#endif
/* The definition of _GL_WARN_ON_USE is copied here. */
+_GL_INLINE_HEADER_BEGIN
+
+#ifndef _GL_ISSYMLINK_INLINE
+# define _GL_ISSYMLINK_INLINE _GL_INLINE
+#endif
+#ifndef _GL_ISSYMLINKAT_INLINE
+# define _GL_ISSYMLINKAT_INLINE _GL_INLINE
+#endif
+
+
/* Before doing "#define mknod rpl_mknod" below, we need to include all
headers that may declare mknod(). OS/2 kLIBC declares mknod() in
<unistd.h>, not in <sys/stat.h>. */
#endif
+#if @GNULIB_ISSYMLINK@ || @GNULIB_ISSYMLINKAT@
+/* For the inline definitions of issymlink, issymlinkat below. */
+# include <errno.h>
+# include <unistd.h> /* for readlink, readlinkat */
+#endif
+
+
#if @GNULIB_CHMOD@
# if @REPLACE_CHMOD@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
#endif
+#if @GNULIB_ISSYMLINK@
+/* Tests whether FILENAME represents a symbolic link.
+ This function is more reliable than lstat() / fstatat() followed by S_ISLNK,
+ because it avoids possible EOVERFLOW errors.
+ Returns
+ 1 if FILENAME is a symbolic link,
+ 0 if FILENAME exists and is not a symbolic link,
+ -1 with errno set if determination failed, in particular
+ -1 with errno = ENOENT or ENOTDIR if FILENAME does not exist. */
+# ifdef __cplusplus
+extern "C" {
+# endif
+_GL_ISSYMLINK_INLINE int issymlink (const char *filename)
+ _GL_ARG_NONNULL ((1));
+_GL_ISSYMLINK_INLINE int
+issymlink (const char *filename)
+{
+ char linkbuf[1];
+ if (readlink (filename, linkbuf, sizeof (linkbuf)) >= 0)
+ return 1;
+ if (errno == EINVAL)
+ return 0;
+ else
+ return -1;
+}
+# ifdef __cplusplus
+}
+# endif
+#endif
+
+
+#if @GNULIB_ISSYMLINKAT@
+/* Tests whether FILENAME represents a symbolic link.
+ This function is more reliable than lstat() / fstatat() followed by S_ISLNK,
+ because it avoids possible EOVERFLOW errors.
+ If FILENAME is a relative file name, it is interpreted as relative to the
+ directory referred to by FD (where FD = AT_FDCWD denotes the current
+ directory).
+ Returns
+ 1 if FILENAME is a symbolic link,
+ 0 if FILENAME exists and is not a symbolic link,
+ -1 with errno set if determination failed, in particular
+ -1 with errno = ENOENT or ENOTDIR if FILENAME does not exist. */
+# ifdef __cplusplus
+extern "C" {
+# endif
+_GL_ISSYMLINKAT_INLINE int issymlinkat (int fd, const char *filename)
+ _GL_ARG_NONNULL ((2));
+_GL_ISSYMLINKAT_INLINE int
+issymlinkat (int fd, const char *filename)
+{
+ char linkbuf[1];
+ if (readlinkat (fd, filename, linkbuf, sizeof (linkbuf)) >= 0)
+ return 1;
+ if (errno == EINVAL)
+ return 0;
+ else
+ return -1;
+}
+# ifdef __cplusplus
+}
+# endif
+#endif
+
+
#if @GNULIB_LCHMOD@
/* Change the mode of FILENAME to MODE, without dereferencing it if FILENAME
denotes a symbolic link. */
#endif
+_GL_INLINE_HEADER_END
+
#endif /* _@GUARD_PREFIX@_SYS_STAT_H */
#endif /* _@GUARD_PREFIX@_SYS_STAT_H */
#endif
# 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
<unistd.h>. */
/* But avoid namespace pollution on glibc systems. */
-#if ! defined O_CLOEXEC \
- || ((@GNULIB_UNLINKAT@ || defined GNULIB_POSIXCHECK) \
- && (defined __CYGWIN__ || defined __ANDROID__) \
- && ! defined __GLIBC__)
+#if ((@GNULIB_UNLINKAT@ || defined GNULIB_POSIXCHECK) \
+ && (defined __CYGWIN__ || defined __ANDROID__) \
+ && ! defined __GLIBC__)
# include <fcntl.h>
#endif
_GL_INLINE_HEADER_END
+/* FreeBSD 14.0, NetBSD 10.0, OpenBSD 7.5, Solaris 11.4, and glibc 2.41
+ do not define O_CLOEXEC in <unistd.h>. */
+#if ! defined O_CLOEXEC
+# include <fcntl.h>
+#endif
+
#endif /* _@GUARD_PREFIX@_UNISTD_H */
#endif /* _GL_INCLUDING_UNISTD_H */
#endif /* _@GUARD_PREFIX@_UNISTD_H */
# sys_stat_h.m4
-# serial 42 -*- Autoconf -*-
+# serial 43 -*- Autoconf -*-
dnl Copyright (C) 2006-2025 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FSTATAT])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FUTIMENS])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_GETUMASK])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISSYMLINK])
+ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ISSYMLINKAT])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LCHMOD])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LSTAT])
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MKDIR])
--- /dev/null
+Description:
+Test whether a file is a symbolic link.
+
+Files:
+lib/issymlink.c
+
+Depends-on:
+sys_stat-h
+fcntl-h
+readlink
+
+configure.ac:
+gl_SYS_STAT_MODULE_INDICATOR([issymlink])
+
+Makefile.am:
+lib_SOURCES += issymlink.c
+
+Include:
+<sys/stat.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
--- /dev/null
+Description:
+Test whether a file is a symbolic link.
+
+Files:
+lib/issymlinkat.c
+
+Depends-on:
+sys_stat-h
+fcntl-h
+readlinkat
+
+configure.ac:
+gl_SYS_STAT_MODULE_INDICATOR([issymlinkat])
+
+Makefile.am:
+lib_SOURCES += issymlinkat.c
+
+Include:
+<sys/stat.h>
+
+License:
+GPL
+
+Maintainer:
+all
snippet/arg-nonnull
snippet/c++defs
snippet/warn-on-use
+extern-inline
sys_types-h
time-h
-e 's/@''GNULIB_FSTATAT''@/$(GNULIB_FSTATAT)/g' \
-e 's/@''GNULIB_FUTIMENS''@/$(GNULIB_FUTIMENS)/g' \
-e 's/@''GNULIB_GETUMASK''@/$(GNULIB_GETUMASK)/g' \
+ -e 's/@''GNULIB_ISSYMLINK''@/$(GNULIB_ISSYMLINK)/g' \
+ -e 's/@''GNULIB_ISSYMLINKAT''@/$(GNULIB_ISSYMLINKAT)/g' \
-e 's/@''GNULIB_LCHMOD''@/$(GNULIB_LCHMOD)/g' \
-e 's/@''GNULIB_LSTAT''@/$(GNULIB_LSTAT)/g' \
-e 's/@''GNULIB_MKDIR''@/$(GNULIB_MKDIR)/g' \