]> git.ipfire.org Git - thirdparty/gnulib.git/commitdiff
issymlink, issymlinkat: New modules.
authorBruno Haible <bruno@clisp.org>
Thu, 14 Aug 2025 16:36:00 +0000 (18:36 +0200)
committerBruno Haible <bruno@clisp.org>
Thu, 14 Aug 2025 22:22:28 +0000 (00:22 +0200)
* 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.

ChangeLog
lib/issymlink.c [new file with mode: 0644]
lib/issymlinkat.c [new file with mode: 0644]
lib/sys_stat.in.h
lib/unistd.in.h
m4/sys_stat_h.m4
modules/issymlink [new file with mode: 0644]
modules/issymlinkat [new file with mode: 0644]
modules/sys_stat-h

index 6084329d2e261c842e172171f9facebf1e8e2761..09afcc04c61ddc2be49a9e6f8c574b9192a4178a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+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
diff --git a/lib/issymlink.c b/lib/issymlink.c
new file mode 100644 (file)
index 0000000..fba06ff
--- /dev/null
@@ -0,0 +1,20 @@
+/* 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>
diff --git a/lib/issymlinkat.c b/lib/issymlinkat.c
new file mode 100644 (file)
index 0000000..924df45
--- /dev/null
@@ -0,0 +1,20 @@
+/* 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>
index c3c38fd653e0705eeebaea2b7b837924b24a06e7..1ffc255134b409a20c41de504464530d8c5ec609 100644 (file)
@@ -56,7 +56,7 @@
 #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>.  */
@@ -430,6 +440,13 @@ struct stat
 #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)
@@ -626,6 +643,71 @@ _GL_WARN_ON_USE (getumask, "getumask is not portable - "
 #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.  */
@@ -1007,6 +1089,8 @@ _GL_WARN_ON_USE (utimensat, "utimensat is not portable - "
 #endif
 
 
+_GL_INLINE_HEADER_END
+
 #endif /* _@GUARD_PREFIX@_SYS_STAT_H */
 #endif /* _@GUARD_PREFIX@_SYS_STAT_H */
 #endif
index 9f057d30cdf81c8e4a70401090e413fd9cf51eae..0cf272802009a9e57c8ea399d89b4a2b8f539fcb 100644 (file)
 # 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
 
@@ -2493,6 +2490,12 @@ _GL_CXXALIASWARN (write);
 
 _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 */
index fdcc89545bc96e08bbbf166fd24a878ef642921b..a2dd603d63e0536fa2f4eb827b7a38121766b855 100644 (file)
@@ -1,5 +1,5 @@
 # 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,
@@ -80,6 +80,8 @@ AC_DEFUN([gl_SYS_STAT_H_REQUIRE_DEFAULTS],
     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])
diff --git a/modules/issymlink b/modules/issymlink
new file mode 100644 (file)
index 0000000..d7977e8
--- /dev/null
@@ -0,0 +1,25 @@
+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
diff --git a/modules/issymlinkat b/modules/issymlinkat
new file mode 100644 (file)
index 0000000..15740ac
--- /dev/null
@@ -0,0 +1,25 @@
+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
index 5552db8e0071ea3ba7cb0e49c582aeb00ed23423..5257bad1814b71b294fb15c1912e5c84c8bee263 100644 (file)
@@ -13,6 +13,7 @@ include_next
 snippet/arg-nonnull
 snippet/c++defs
 snippet/warn-on-use
+extern-inline
 sys_types-h
 time-h
 
@@ -42,6 +43,8 @@ sys/stat.h: sys_stat.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNU
              -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' \