]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
linux: Add openat2 (BZ 31664)
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>
Wed, 19 Nov 2025 16:44:34 +0000 (13:44 -0300)
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>
Tue, 9 Dec 2025 14:14:16 +0000 (11:14 -0300)
The openat2 syscall was added on Linux 5.6, as an extension of openat.
Unlike other open-like functions, the kernel only provides the LFS
variant (so files larger than 4GB always succeed, unlike other
functions with an offset larger than off_t).  Also, similar to other
open functions, the new symbol is a cancellable entrypoint.

The test case added only stress tests for some of the syscalls' provided
functionality, and it is based on an existing kernel self-test.

A fortify wrapper is added to verify the argument size if not larger
than the current support open_how struct.

Gnulib added an openat2 module, which uses read-only for the open_how
argument [1].  There is no clear indication whether the kernel will
indeed use the argument as in-out, how it would do so, or for which
kind of functionality [2]. Also, adding a potentially different prototype
than gnulib only would add extra unnecessary friction and extra
wrappers to handle it.

Checked on x86_64-linux-gnu and aarch64-linux-gnu.

[1] https://gitweb.git.savannah.gnu.org/gitweb/?p=gnulib.git;a=commit;h=0b97ffdf32bdab909d02449043447237273df75e
[2] https://sourceware.org/pipermail/libc-alpha/2025-September/169740.html

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
43 files changed:
NEWS
manual/llio.texi
sysdeps/unix/sysv/linux/Makefile
sysdeps/unix/sysv/linux/Versions
sysdeps/unix/sysv/linux/aarch64/libc.abilist
sysdeps/unix/sysv/linux/alpha/libc.abilist
sysdeps/unix/sysv/linux/arc/libc.abilist
sysdeps/unix/sysv/linux/arm/be/libc.abilist
sysdeps/unix/sysv/linux/arm/le/libc.abilist
sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/bits/fcntl-linux.h
sysdeps/unix/sysv/linux/bits/openat2.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/csky/libc.abilist
sysdeps/unix/sysv/linux/hppa/libc.abilist
sysdeps/unix/sysv/linux/i386/libc.abilist
sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
sysdeps/unix/sysv/linux/openat2.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/or1k/libc.abilist
sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
sysdeps/unix/sysv/linux/sh/be/libc.abilist
sysdeps/unix/sysv/linux/sh/le/libc.abilist
sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
sysdeps/unix/sysv/linux/tst-openat2-consts.py [new file with mode: 0755]
sysdeps/unix/sysv/linux/tst-openat2-lfs.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/tst-openat2.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist

diff --git a/NEWS b/NEWS
index b70dc27ebb82e097ae4aecde434e8a81178faf79..6964ca074e3a9547a1b68920e3d1f86403aaef03 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -54,6 +54,10 @@ Major new features:
   targets, and libgcc compatible runtime (including libgcc_s.so for
   pthread cancellation and backtrace runtime support).
 
+* On Linux, the openat2 function has been added.  It is an extension of
+  openat and provides a superset of its functionality.  It is supported only
+  in LFS mode and it is a cancellable entrypoint.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * Support for dumped heaps has been removed - malloc_set_state() now always
index 806ff0a27d5e0f05e861a032a9ed8e820931def4..7094ff4145eb8c4c71734e2ff8f7dcf4458c3f45 100644 (file)
@@ -218,6 +218,104 @@ new, extended API using 64 bit file sizes and offsets transparently
 replaces the old API.
 @end deftypefun
 
+@deftp {Data Type} {struct open_how}
+@standards{Linux, fcntl.h}
+The @code{open_how} structure describes how to open a file using @code{openat2}.
+
+@strong{Portability note:} In the future, additional fields can be added
+to @code{struct open_how}, so that the size of this data type increases.
+Do not use it in places where this matters, such as structure fields in
+installed header files, where such a change could affect the application
+binary interface (ABI).
+
+The following generic fields are available.
+
+@table @code
+@item flags
+This field specifies the file creation and file status flags to use when
+opening the file.
+All of the @code{O_*} flags defined for @code{openat} are valid.
+The @code{openat2} is stricter than @code{openat} in rejecting unknown or
+conflicting values. For example, @code{openat2} rejects a mode that
+exceeds 07777, whereas @code{openat} silently ignores
+excess high-order bits.
+
+@item mode
+This field specifies the mode for the new file, similar to @code{mode}
+argument of @code{openat}. It should be in the range 0..07777.
+
+@item resolve
+This is a bitmask of flags that affect the resolution of file name components.
+Unlike @code{O_NOFOLLOW}, it affects all file name components, not just the
+last one. The following flags are available.
+
+@table @code
+@item RESOLVE_NO_XDEV
+Disallow traversal of mount points during path resolution (including all
+bind mounts).
+
+@item RESOLVE_NO_MAGICLINKS
+Disallow all @strong{magic-link} resolution during path resolution. Magic
+links are symbolic link-like objects that are found in @strong{procfs};
+for example the @code{/proc/pid/exe}.
+
+@item RESOLVE_NO_SYMLINKS
+Disallow resolution of symbolic links during path resolution.
+This option implies @code{RESOLVE_NO_MAGICLINKS}.
+
+@item RESOLVE_BENEATH
+This rejects absolute pathnames, pathnames containing @file{..}@:
+components that would be resolved relative to @var{dfd},
+and symbolic links that resolve to pathnames that would be rejected.
+The rejection occurs even if @var{dfd} is the root directory.
+
+@item RESOLVE_IN_ROOT
+Treat absolute pathnames as being relative to @var{dfd},
+treat a @file{..}@: component as being equivalent to @file{.}@:
+if it is resolved relative to @var{dfd},
+and treat symbolic link contents consistently with this.
+@end table
+
+@end table
+
+@end deftp
+
+
+@deftypefun int openat2 (int @var{dirfd}, const char *@var{pathname}, const struct open_how *@var{how}, size_t @var{size})
+@standards{Linux, fcntl.h}
+@safety{@mtsafe{}@assafe{}@acsafe{}}
+This function is an extension of the @code{openat} and provides a superset of its
+functionality.  @xref{Descriptor-Relative Access}.
+
+The @var{size} argument must equal @code{sizeof *@var{how}}. For portability
+to future API versions that may extend @code{struct open_how}, @code{*@var{how}}
+should be fully initialized e.g., by a struct initializer, by @code{memset} to zero,
+or by having static storage duration.
+
+On failure, @code{openat2} returns @math{-1} and sets @code{errno}. It can
+fail for any of the reasons @code{openat} fails, plus the following reasons:
+
+@table @code
+@item E2BIG
+@var{size} is too large for any future extension, @code{*@var{how}} contains
+non-zero members that are future extensions not supported by this kernel
+
+@item EINVAL
+An unknown flag or invalid value was used on @code{*@var{how}}; or
+@code{@var{how}->mode} is non-zero, but @code{@var{how}->flags} does not contain
+@code{O_CREAT} or @code{O_TMPFILE}, or @var{size} is smaller than the ones supported
+by the kernel.
+@end table
+
+It can also return all the errors @code{openat} returns.
+
+Similar to @code{openat}, @code{openat2} is a cancellation point.
+
+Unlike other @code{open}-like functions, this function ignores
+@code{_FILE_OFFSET_BITS} and always operates in large file mode.
+@end deftypefun
+
+
 @deftypefn {Obsolete function} int creat (const char *@var{filename}, mode_t @var{mode})
 @standards{POSIX.1, fcntl.h}
 @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}}
index f6b59d80dcdb422986019cd96ad5a3f4190c2858..955d3163625e09bbaa082dd17cc37f5b21f66e58 100644 (file)
@@ -135,6 +135,7 @@ sysdep_headers += \
   bits/mman-linux.h \
   bits/mman-map-flags-generic.h \
   bits/mman-shared.h \
+  bits/openat2.h \
   bits/procfs-extra.h \
   bits/procfs-id.h \
   bits/procfs-prregset.h \
@@ -623,6 +624,7 @@ sysdep_routines += \
   internal_statvfs \
   open64_nocancel \
   open_nocancel \
+  openat2 \
   openat64_nocancel \
   openat_nocancel \
   pread64_nocancel \
@@ -634,7 +636,12 @@ sysdep_routines += \
   xstatconv \
   # sysdep_routines
 
+routines_no_fortify += \
+  openat2 \
+  # routines_no_fortify
+
 sysdep_headers += \
+  bits/fcntl-linux-fortify.h \
   bits/fcntl-linux.h \
   # sysdep_headers
 
@@ -643,7 +650,24 @@ tests += \
   tst-fallocate64 \
   tst-getcwd-smallbuff \
   tst-o_path-locks \
+  tst-openat2 \
+  tst-openat2-lfs \
   # tests
+
+tests-special += \
+  $(objpfx)tst-openat2-consts.out \
+  # tests-special
+$(objpfx)tst-openat2-consts.out: ../sysdeps/unix/sysv/linux/tst-openat2-consts.py
+       $(sysdeps-linux-python) \
+         ../sysdeps/unix/sysv/linux/tst-openat2-consts.py \
+           $(sysdeps-linux-python-cc) \
+         < /dev/null > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-openat2-consts.out: $(sysdeps-linux-python-deps)
+
+# openat2 only provides LFS support, the tests check if the interface is correctly
+# provided regardless of the flags.
+CFLAGS-tst-openat2-lfs.c += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
+
 endif
 
 ifeq ($(subdir),elf)
index 8f4d71ad7fe00a73c1577a8711383b711ccae33f..c7f199f13f29693842acf3cf7989a84103f1802a 100644 (file)
@@ -341,6 +341,7 @@ libc {
   }
   GLIBC_2.43 {
     mseal;
+    openat2;
   }
   GLIBC_PRIVATE {
     # functions used in other libraries
index d161d268d94fb300323f9409594a88db7a1d9a57..3156688addba39332341f1eaa695c47da4c563aa 100644 (file)
@@ -2773,4 +2773,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index 62879b6a0821b45ff6ee654d0f3d3bd95dd2d673..8af5b0b5818832fc738f074e2650879ec91d9ebd 100644 (file)
@@ -3120,6 +3120,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index bd5fa65e93651b9522a4224f34e508e5ae8e948b..35fcef2cc4c14c8a7480259b04448b3d974fbe7e 100644 (file)
@@ -2534,4 +2534,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index 7d975dafab506265bb6738aa30a52e4c19961d29..a6c6b951bfa736ac7f7a729c4e659b6a2fb2e8e2 100644 (file)
@@ -2826,6 +2826,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index c95bbfe6df84780b8a81ecaec07815d6dec2fcdd..e76015fe666aca5a38774d16b35e51c02db38ca8 100644 (file)
@@ -2823,6 +2823,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h b/sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h
new file mode 100644 (file)
index 0000000..e6b414d
--- /dev/null
@@ -0,0 +1,49 @@
+/* Checking macros for fcntl functions.  Linux version.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef        _FCNTL_H
+# error "Never include <bits/fcntl-linux-fortify.h> directly; use <fcntl.h> instead."
+#endif
+
+#ifdef __USE_GNU
+
+extern int __REDIRECT (__openat2_alias, (int __dfd, const char *__filename,
+                                        const struct open_how *__how,
+                                        size_t __usize), openat2)
+     __nonnull ((2, 3));
+
+#if !__fortify_use_clang
+__errordecl (__openat2_invalid_size,
+            "the specified size is larger than sizeof (struct open_how)");
+#endif
+
+__fortify_function int
+openat2 (int __dfd, const char *__filename, const struct open_how *__how,
+        size_t __usize)
+     __fortify_clang_warning (__builtin_constant_p (__usize)
+                             && __usize > sizeof (struct open_how),
+                             "the specified size is larger than sizeof (struct open_how)")
+{
+#if !__fortify_use_clang
+  if (__builtin_constant_p (__usize) && __usize > sizeof (struct open_how))
+    __openat2_invalid_size ();
+#endif
+  return __openat2_alias (__dfd, __filename, __how, __usize);
+}
+
+#endif /* use GNU */
index f9b3de11f44263f91d0252764fbb20e4ea501347..bdab40f559eeb6d69e562126919427d3f560522c 100644 (file)
@@ -463,6 +463,33 @@ extern int name_to_handle_at (int __dfd, const char *__name,
 extern int open_by_handle_at (int __mountdirfd, struct file_handle *__handle,
                              int __flags);
 
+#ifdef __has_include
+# if __has_include ("linux/openat2.h")
+#  include "linux/openat2.h"
+#  define __glibc_has_open_how 1
+# endif
+#endif
+
+#include <bits/openat2.h>
+
+/* Similar to `openat' but the arguments are packed on HOW with the size
+   USIZE.  If flags and mode from HOW are non-zero, then openat2 operates
+   like openat.
+
+   Unlike openat, unknown or invalid flags result in an error (EINVAL),
+   rather than being ignored.  The mode must be zero unless one of O_CREAT
+   or O_TMPFILE are set.
+
+   The kernel does not support legacy non-LFS interface.  */
+extern int openat2 (int __dfd, const char * __filename,
+                   const struct open_how * __how,
+                   __SIZE_TYPE__ __usize)
+     __nonnull ((2, 3));
+
 #endif /* use GNU */
 
+#if __USE_FORTIFY_LEVEL > 0 && defined __fortify_function
+# include <bits/fcntl-linux-fortify.h>
+#endif
+
 __END_DECLS
diff --git a/sysdeps/unix/sysv/linux/bits/openat2.h b/sysdeps/unix/sysv/linux/bits/openat2.h
new file mode 100644 (file)
index 0000000..a3fe858
--- /dev/null
@@ -0,0 +1,60 @@
+/* openat2 definition.  Linux specific.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _FCNTL_H
+# error "Never use <bits/openat2.h> directly; include <fcntl.h> instead."
+#endif
+
+#ifndef __glibc_has_open_how
+/* Arguments for how openat2 should open the target path.  */
+struct open_how
+{
+  __uint64_t flags;
+  __uint64_t mode;
+  __uint64_t resolve;
+};
+#endif
+
+/* how->resolve flags for openat2. */
+#ifndef RESOLVE_NO_XDEV
+# define RESOLVE_NO_XDEV       0x01 /* Block mount-point crossings
+                                       (includes bind-mounts).  */
+#endif
+#ifndef RESOLVE_NO_MAGICLINKS
+# define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style
+                                       "magic-links".  */
+#endif
+#ifndef RESOLVE_NO_SYMLINKS
+# define RESOLVE_NO_SYMLINKS   0x04 /* Block traversal through all symlinks.  */
+#endif
+#ifndef RESOLVE_BENEATH
+# define RESOLVE_BENEATH       0x08 /* Block "lexical" trickery like
+                                       "..", symlinks, and absolute
+                                       paths which escape the dirfd.  */
+#endif
+#ifndef RESOLVE_IN_ROOT
+# define RESOLVE_IN_ROOT       0x10 /* Make all jumps to "/" and ".."
+                                       be scoped inside the dirfd
+                                       (similar to chroot).  */
+#endif
+#ifndef RESOLVE_CACHED
+# define RESOLVE_CACHED                0x20 /* Only complete if resolution can be
+                                       completed through cached lookup. May
+                                       return -EAGAIN if that's not
+                                       possible.  */
+#endif
index 6fc91899ff9828f0cdbff9ce10c4bf35403c1f73..1fb7cdcad5de82f05743cd6cee306bf082bae117 100644 (file)
@@ -2810,4 +2810,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index 8a83722bf5ba70c48817a66e84492376958e1784..0710ccecf9d684f2208e24ef48cb3068280be51d 100644 (file)
@@ -2847,6 +2847,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 3b96177e1db5b7c5b07d4aac8aa9eef96c210ef3..3afe3a88eb42663b5cce262dc3668103eb6345f7 100644 (file)
@@ -3030,6 +3030,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index bc39d18d6de19bcc73b6f55f374ec3bc7eaf4c67..c2b3a66d3a1de6a4457741fd72a61a0a70388ab2 100644 (file)
@@ -2294,4 +2294,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index b42b4fe920e92ab752b58968f3bcadc91a808709..d6855131e8b8c4f815b8ae5e326ea29bbdf82492 100644 (file)
@@ -2806,6 +2806,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 854bf3c1498612177d9b9aaa789e79ad67b27713..4e3fe9c42f287006abaca07de365771d5f5c9da2 100644 (file)
@@ -2973,6 +2973,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index ab3d67bd60bb5e9b6f4084bf0a75fa8e886cc5ee..29f0c5f954b5c44fc2713b1cfbcefa46cffdb485 100644 (file)
@@ -2859,4 +2859,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index 510b3a24d0c39f8510d4b2f25cbdcb10cf8fa9a2..2ef62838f75cf5d7994ec38e38cbd67f5eab0d58 100644 (file)
@@ -2856,4 +2856,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index dd2baab3c9bac67bc60a1ea9ea6ec8bb9d603e96..031e8961acce6d51f556b7b55e515a9d0f35a466 100644 (file)
@@ -2936,6 +2936,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 88fa8b9a978b4b241434dd41f0468cf0f43b6ac9..8dc99d81b4bb8dca7fc4f9b6e348b1918327938f 100644 (file)
@@ -2934,6 +2934,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 00993fef2b763088fe55b4fc35c1fcfc8bd06dd6..054c5b6391b94e4212f351adcb12052a278a8a8f 100644 (file)
@@ -2942,6 +2942,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 136da09f7176efd3890d9fa0b6fe41714cff67d5..13f0148bc0005a9c0b7a3f953bb04fdb624cd383 100644 (file)
@@ -2844,6 +2844,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/openat2.c b/sysdeps/unix/sysv/linux/openat2.c
new file mode 100644 (file)
index 0000000..d45eb05
--- /dev/null
@@ -0,0 +1,29 @@
+/* Linux openat2 syscall implementation.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <fcntl.h>
+#include <bits/openat2.h>
+#include <sysdep-cancel.h>
+
+int
+__openat2 (int dfd, const char *filename,
+          const struct open_how *how, size_t usize)
+{
+  return SYSCALL_CANCEL (openat2, dfd, filename, how, usize);
+}
+weak_alias (__openat2, openat2)
index 1a2a3673c7b7697bd9a3bea4a59d8e1d15211c5f..e7ffe07dd8d5339e7b1c8390e44586c7793064ba 100644 (file)
@@ -2284,4 +2284,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index f00901f956ae58860d7b3f722b2d704c47c80707..dea4b20f05c15c21ca7fd91ba9e7aaa69975ca4f 100644 (file)
@@ -3163,6 +3163,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index de23059026408efdf76d652b06afdb9b21fbc3f4..b45e127463688c3bb3858c3a0f4c9d6cdccbff86 100644 (file)
@@ -3208,6 +3208,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 1ae78ec7efb7e792d08e37267ade7b02798c6eb7..942cf6a02763fabe972151083748f78ad0a463c0 100644 (file)
@@ -2917,6 +2917,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 53cb317a092eedd630be12b9dcc320719171c0de..65d78e50760b5d6b1a9cb39016a7bf8064224794 100644 (file)
@@ -2993,4 +2993,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index e6fd213d5c4c1b70c80422403aae46a608583183..dcab30d72eec70a29924c892d6e0cdc08999af4e 100644 (file)
@@ -2537,4 +2537,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index 905323b8896984228fb1b27310e706331537554b..796ef35e26e5aa84dc1338dd332bd915e3f842f2 100644 (file)
@@ -2737,4 +2737,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
index c35e099d2cade7574bcb10ae5c499ce26b4ce484..9bd9f5eb787fe42502bfd106ec8f37e3d9aba39e 100644 (file)
@@ -3161,6 +3161,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 9f34c5fab39965f860dda08bbca2147b568b8df1..8f2350ee0b64635c1cce1e4e055f24275efcc86e 100644 (file)
@@ -2954,6 +2954,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index f26980c57c4dd2bd2a9ef3bb07032c059af4bb1b..7aa98c5aede5138de5dc7acd1b6519b8be03dc2a 100644 (file)
@@ -2853,6 +2853,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index e8ee581fa7500737c71d651c6bd04677584a7b8d..6bd4f8f63a1ae8599a6c630b82cbea1f6b6e4d06 100644 (file)
@@ -2850,6 +2850,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 3d0665d197c39d34e2466f6e9a3445782a299079..b52cab2a3515b918bbbaaa4fbdc243e2f223d03a 100644 (file)
@@ -3184,6 +3184,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 0b7644d8fe542fc0e62ffc4a432f1604f7dd318f..ff99cd4f219a9033cf9a94136b69be4ff32047a0 100644 (file)
@@ -2820,6 +2820,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/tst-openat2-consts.py b/sysdeps/unix/sysv/linux/tst-openat2-consts.py
new file mode 100755 (executable)
index 0000000..9b65d18
--- /dev/null
@@ -0,0 +1,63 @@
+#!/usr/bin/python3
+# Test that glibc's sys/openat2.h constants match the kernel's.
+# Copyright (C) 2025 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library 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.
+#
+# The GNU C Library 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 the GNU C Library; if not, see
+# <https://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+
+import glibcextract
+import glibcsyscalls
+
+
+def main():
+    """The main entry point."""
+    parser = argparse.ArgumentParser(
+        description="Test that glibc's sys/openat2.h constants "
+        "match the kernel's.")
+    parser.add_argument('--cc', metavar='CC',
+                        help='C compiler (including options) to use')
+    args = parser.parse_args()
+
+    if glibcextract.compile_c_snippet(
+            '#include <linux/openat2.h>',
+            args.cc).returncode != 0:
+        sys.exit (77)
+
+    linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+    # Constants in glibc were updated to match Linux v6.8.  When glibc
+    # constants are updated this value should be updated to match the
+    # released kernel version from which the constants were taken.
+    linux_version_glibc = (6, 8)
+    def check(cte, exclude=None):
+        return glibcextract.compare_macro_consts(
+                '#define _FCNTL_H\n'
+                '#include <stdint.h>\n'
+                '#include <bits/openat2.h>\n',
+                '#include <asm/fcntl.h>\n'
+                '#include <linux/openat2.h>\n',
+                args.cc,
+                cte,
+                exclude,
+                linux_version_glibc > linux_version_headers,
+                linux_version_headers > linux_version_glibc)
+
+    status = check('RESOLVE.*')
+    sys.exit(status)
+
+if __name__ == '__main__':
+    main()
diff --git a/sysdeps/unix/sysv/linux/tst-openat2-lfs.c b/sysdeps/unix/sysv/linux/tst-openat2-lfs.c
new file mode 100644 (file)
index 0000000..85962d3
--- /dev/null
@@ -0,0 +1 @@
+#include "tst-openat2.c"
diff --git a/sysdeps/unix/sysv/linux/tst-openat2.c b/sysdeps/unix/sysv/linux/tst-openat2.c
new file mode 100644 (file)
index 0000000..0778b98
--- /dev/null
@@ -0,0 +1,482 @@
+/* Linux openat2 tests.
+   Copyright (C) 2025 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library 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.
+
+   The GNU C Library 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 the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <array_length.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdint.h>
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/test-driver.h>
+#include <support/xunistd.h>
+
+static int dir_fd;
+static char *temp_dir;
+static char *temp_subdir;
+static char *temp_some_file;
+
+#define TEST_DIR_LINK    "test_dir_link"
+#define TEST_DIR_LINK_2  "test_dir_link_2"
+#define TEMP_DIR_LINK    "temp_dir_link"
+#define INVALID_LINK     "invalid-link"
+#define VALID_LINK       "valid-link"
+
+static void
+create_symlink (const char *target, const char *linkpath)
+{
+  TEST_VERIFY_EXIT (symlinkat (target, dir_fd, linkpath) == 0);
+  add_temp_file (xasprintf ("%s/%s", temp_dir, linkpath));
+}
+
+static void
+do_prepare (int argc, char *argv[])
+{
+  /*
+     Construct a test directory with the following structure:
+
+     temp_dir/
+     |- tst-openat2.xxxxxxx
+        |- test_dir_link -> test_dir (/tmp)
+        |- test_dir_link_2 -> test_dir_link
+        |- temp_dir_link -> temp_dir/tst-openat2.xxxxxxx
+        |- some-file.xxxxxxx
+        |- invalid_link -> temp_dir/tst-openat2.xxxxxxx/some-file.xxxxxxx
+        |- valid_link -> some-file.xxxxxxx
+       |- subdir.xxxxxxx
+          |- some-file.xxxxxxx
+  */
+
+  temp_dir = support_create_temp_directory ("tst-openat2.");
+  dir_fd = xopen (temp_dir, O_RDONLY | O_DIRECTORY, 0);
+
+  create_symlink (test_dir, TEST_DIR_LINK);
+  create_symlink (TEST_DIR_LINK, TEST_DIR_LINK_2);
+  create_symlink (temp_dir, TEMP_DIR_LINK);
+
+  {
+    char *filename;
+    int fd = create_temp_file_in_dir ("some-file.", temp_dir, &filename);
+    TEST_VERIFY_EXIT (fd != -1);
+
+    create_symlink (filename, INVALID_LINK);
+
+    create_symlink (basename (filename), VALID_LINK);
+  }
+
+  temp_subdir = support_create_temp_directory (xasprintf ("%s/subdir.",
+                                                         basename (temp_dir)));
+  {
+    int fd = create_temp_file_in_dir ("some-file.", temp_subdir,
+                                     &temp_some_file);
+    TEST_VERIFY_EXIT (fd != -1);
+  }
+}
+#define PREPARE do_prepare
+
+static int
+do_test_struct (void)
+{
+  static struct struct_test
+  {
+    struct open_how_ext
+    {
+      struct open_how inner;
+      int extra1;
+      int extra2;
+      int extra3;
+    } arg;
+    size_t size;
+    int err;
+  } tests[] =
+  {
+    {
+      /* Zero size.  */
+      .arg.inner.flags = O_RDONLY,
+      .size = 0,
+      .err = EINVAL,
+    },
+    {
+      /* Normal struct.  */
+      .arg.inner.flags = O_RDONLY,
+      .size = sizeof (struct open_how),
+    },
+    {
+      /* Larger struct, zeroed out the unused values.  */
+      .arg.inner.flags = O_RDONLY,
+      .size = sizeof (struct open_how_ext),
+    },
+    {
+      /* Larger struct, non-zeroed out the unused values.  */
+      .arg.inner.flags = O_RDONLY,
+      .arg.extra1 = 0xdeadbeef,
+      .size = sizeof (struct open_how_ext),
+      .err = E2BIG,
+    },
+    {
+      /* Larger struct, non-zeroed out the unused values.  */
+      .arg.inner.flags = O_RDONLY,
+      .arg.extra2 = 0xdeadbeef,
+      .size = sizeof (struct open_how_ext),
+      .err = E2BIG,
+    },
+  };
+
+  for (struct struct_test *t = tests; t != array_end (tests); t++)
+    {
+      int fd = openat2 (AT_FDCWD, ".", (struct open_how *) &t->arg, t->size);
+      if (t->err != 0)
+       {
+         TEST_COMPARE (fd, -1);
+         TEST_COMPARE (errno, t->err);
+       }
+      else
+       TEST_VERIFY (fd >= 0);
+    }
+
+  return 0;
+}
+
+static int
+do_test_flags (void)
+{
+  static struct flag_test
+  {
+    const char *path;
+    struct open_how how;
+    int err;
+  } tests[] =
+  {
+    /* O_TMPFILE is incompatible with O_PATH and O_CREAT.  */
+    {
+      .how.flags = O_TMPFILE | O_PATH | O_RDWR,
+      .err = EINVAL },
+    {
+      .how.flags = O_TMPFILE | O_CREAT | O_RDWR,
+      .err = EINVAL },
+
+    /* O_PATH only permits certain other flags to be set ...  */
+    {
+      .how.flags = O_PATH | O_CLOEXEC
+    },
+    {
+      .how.flags = O_PATH | O_DIRECTORY
+    },
+    {
+      .how.flags = O_PATH | O_NOFOLLOW
+    },
+    /* ... and others are absolutely not permitted. */
+    {
+      .how.flags = O_PATH | O_RDWR,
+      .err = EINVAL },
+    {
+      .how.flags = O_PATH | O_CREAT,
+      .err = EINVAL },
+    {
+      .how.flags = O_PATH | O_EXCL,
+      .err = EINVAL },
+    {
+      .how.flags = O_PATH | O_NOCTTY,
+      .err = EINVAL },
+    {
+      .how.flags = O_PATH | O_DIRECT,
+      .err = EINVAL },
+
+    /* ->mode must only be set with O_{CREAT,TMPFILE}. */
+    {
+      .how.flags = O_RDONLY,
+      .how.mode = 0600,
+      .err = EINVAL },
+    {
+      .how.flags = O_PATH,
+      .how.mode = 0600,
+      .err = EINVAL },
+    {
+      .how.flags = O_CREAT,
+      .how.mode = 0600 },
+    {
+      .how.flags = O_TMPFILE | O_RDWR,
+      .how.mode = 0600 },
+    /* ->mode must only contain 0777 bits. */
+    {
+      .how.flags = O_CREAT, .how.mode = 0xFFFF, .err = EINVAL },
+    {
+      .how.flags = O_CREAT, .how.mode = 0xC000000000000000ULL,
+      .err = EINVAL },
+    {
+      .how.flags = O_TMPFILE | O_RDWR, .how.mode = 0x1337,
+      .err = EINVAL },
+    {
+      .how.flags = O_TMPFILE | O_RDWR,
+      .how.mode = 0x0000A00000000000ULL,
+      .err = EINVAL
+    },
+
+    /* ->resolve flags must not conflict. */
+    {
+      .how.flags = O_RDONLY,
+      .how.resolve = RESOLVE_BENEATH | RESOLVE_IN_ROOT,
+      .err = EINVAL
+    },
+
+    /* ->resolve must only contain RESOLVE_* flags.  */
+    {
+      .how.flags = O_RDONLY,
+      .how.resolve = 0x1337,
+      .err = EINVAL
+    },
+    {
+      .how.flags = O_CREAT,
+      .how.resolve = 0x1337,
+      .err = EINVAL
+    },
+    {
+      .how.flags = O_TMPFILE | O_RDWR,
+      .how.resolve = 0x1337,
+      .err = EINVAL
+    },
+    {
+      .how.flags = O_PATH,
+      .how.resolve = 0x1337,
+      .err = EINVAL
+    },
+
+    /* currently unknown upper 32 bit rejected.  */
+    {
+      .how.flags = O_RDONLY | (1ULL << 63),
+      .how.resolve = 0,
+      .err = EINVAL
+    },
+  };
+
+  for (struct flag_test *t = tests; t != array_end (tests); t++)
+    {
+      const char *path;
+      if (t->how.flags & O_CREAT)
+       {
+         char *newfile;
+         int temp_fd = create_temp_file ("tst-openat2.", &newfile);
+         TEST_VERIFY_EXIT (temp_fd != -1);
+         xunlink (newfile);
+         path = newfile;
+       }
+      else
+       path = ".";
+
+      int fd = openat2 (AT_FDCWD, path, &t->how, sizeof (struct open_how));
+      if (fd != 0 && errno == EOPNOTSUPP)
+       {
+         /* Skip the testcase if FS does not support the operation (e.g.
+            valid O_TMPFILE on NFS).  */
+         continue;
+       }
+
+      if (t->err != 0)
+       {
+         TEST_COMPARE (fd, -1);
+         TEST_COMPARE (errno, t->err);
+       }
+      else
+       TEST_VERIFY (fd >= 0);
+    }
+
+  return 0;
+}
+
+static void
+do_test_resolve (void)
+{
+  int fd;
+
+  /* TEMP_DIR_LINK links to the absolute temp_dir, which escapes the temporary
+     test directory.  */
+  fd = openat2 (dir_fd,
+               TEST_DIR_LINK,
+               &(struct open_how)
+               {
+                 .resolve = RESOLVE_BENEATH,
+               },
+               sizeof (struct open_how));
+  TEST_COMPARE (fd, -1);
+  TEST_COMPARE (errno, EXDEV);
+
+  /* Same as before, TEMP_DIR_LINK_2 links to TEMP_DIR_LINK.  */
+  fd = openat2 (dir_fd,
+               TEST_DIR_LINK_2,
+               &(struct open_how)
+               {
+                 .resolve = RESOLVE_BENEATH,
+               },
+               sizeof (struct open_how));
+  TEST_COMPARE (fd, -1);
+  TEST_COMPARE (errno, EXDEV);
+
+  /* TEMP_DIR_LINK links to the temporary directory itself (dir_fd).  */
+  fd = openat2 (dir_fd,
+               TEMP_DIR_LINK,
+               &(struct open_how)
+               {
+                 .resolve = RESOLVE_BENEATH,
+               },
+               sizeof (struct open_how));
+  TEST_COMPARE (fd, -1);
+  TEST_COMPARE (errno, EXDEV);
+
+  /* Although it points to a valid file in same path, the link refers to
+     an absolute path.  */
+  fd = openat2 (dir_fd,
+               INVALID_LINK,
+               &(struct open_how)
+               {
+                 .resolve = RESOLVE_BENEATH,
+               },
+               sizeof (struct open_how));
+  TEST_COMPARE (fd, -1);
+  TEST_COMPARE (errno, EXDEV);
+
+  fd = openat2 (dir_fd,
+               VALID_LINK,
+               &(struct open_how)
+               {
+                 .resolve = RESOLVE_BENEATH,
+               },
+               sizeof (struct open_how));
+  TEST_VERIFY (fd != -1);
+  xclose (fd);
+
+  /* There is no such file in temp_dir/tst-openat2.xxxxxxx.  */
+  fd = openat2 (dir_fd,
+              "should-not-work",
+              &(struct open_how)
+              {
+                .resolve = RESOLVE_IN_ROOT,
+              },
+              sizeof (struct open_how));
+  TEST_COMPARE (fd, -1);
+  TEST_COMPARE (errno, ENOENT);
+
+  {
+    int subdir_fd = openat2 (dir_fd,
+                            basename (temp_subdir),
+                            &(struct open_how)
+                            {
+                              .flags = O_RDONLY | O_DIRECTORY,
+                              .resolve = RESOLVE_IN_ROOT,
+                            },
+                            sizeof (struct open_how));
+    TEST_VERIFY (subdir_fd != -1);
+
+    /* Open the file within the subdir.xxxxxx with both tst-openat2.xxxxxxx
+       and tst-openat2.xxxxxxx/subdir.xxxxxxx file descriptors.  */
+    fd = openat2 (subdir_fd,
+                 basename (temp_some_file),
+                 &(struct open_how)
+                 {
+                   .resolve = RESOLVE_IN_ROOT,
+                 },
+                 sizeof (struct open_how));
+    TEST_VERIFY (fd != -1);
+    xclose (fd);
+
+    fd = openat2 (dir_fd,
+                 xasprintf ("%s/%s",
+                            basename (temp_subdir),
+                            basename (temp_some_file)),
+                 &(struct open_how)
+                 {
+                   .resolve = RESOLVE_IN_ROOT,
+                 },
+                 sizeof (struct open_how));
+    TEST_VERIFY (fd != -1);
+    xclose (fd);
+  }
+}
+
+static int
+do_test_basic (void)
+{
+  int fd;
+
+  fd = openat2 (dir_fd,
+               "some-file",
+               &(struct open_how)
+               {
+                 .flags = O_CREAT|O_RDWR|O_EXCL,
+                 .mode = 0666,
+               },
+               sizeof (struct open_how));
+  TEST_VERIFY (fd != -1);
+
+  xwrite (fd, "hello", 5);
+
+  /* Before closing the file, try using this file descriptor to open
+     another file.  This must fail.  */
+  {
+    int fd2 = openat2 (fd,
+                      "should-not-work",
+                      &(struct open_how)
+                      {
+                        .flags = O_CREAT|O_RDWR|O_EXCL,
+                        .mode = 0666,
+                      },
+                      sizeof (struct open_how));
+    TEST_COMPARE (fd2, -1);
+    TEST_COMPARE (errno, ENOTDIR);
+  }
+
+  /* Remove the created file.  */
+  int cwdfd = xopen (".", O_RDONLY | O_DIRECTORY, 0);
+  TEST_COMPARE (fchdir (dir_fd), 0);
+  xunlink ("some-file");
+  TEST_COMPARE (fchdir (cwdfd), 0);
+
+  xclose (dir_fd);
+  xclose (cwdfd);
+
+  fd = openat2 (dir_fd,
+               "some-file",
+               &(struct open_how)
+               {
+                 .flags = O_CREAT|O_RDWR|O_EXCL,
+                 .mode = 0666,
+               },
+               sizeof (struct open_how));
+  TEST_COMPARE (fd, -1);
+  TEST_COMPARE (errno, EBADF);
+
+  return 0;
+}
+
+static int
+do_test (void)
+{
+  if (openat2 (AT_FDCWD, ".", &(struct open_how) {}, sizeof (struct open_how))
+      == -1 && errno == ENOSYS)
+    FAIL_UNSUPPORTED ("openat2 is not supported by the kernel");
+
+  do_test_struct ();
+  do_test_flags ();
+  do_test_resolve ();
+  do_test_basic ();
+
+  return 0;
+}
+
+#include <support/test-driver.c>
index 85533e9c073ad54d0fff81b0edf58a04bcbb2cd5..306cd627fd823997e79a7bc1a9ca613eebbeb97d 100644 (file)
@@ -2769,6 +2769,7 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
index 2b2a351150c8e0c94c70e56bbb1a6591a1ecafc5..8b9c448742edce0c81829bf8f3a687f108830683 100644 (file)
@@ -2788,4 +2788,5 @@ GLIBC_2.43 free_sized F
 GLIBC_2.43 memalignment F
 GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
+GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F