mirror of
https://sourceware.org/git/glibc.git
synced 2026-10-24 01:33:52 +03:00
linux: Add openat2 (BZ 31664)
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>
This commit is contained in:
4
NEWS
4
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
|
||||
|
||||
@@ -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{}}}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -341,6 +341,7 @@ libc {
|
||||
}
|
||||
GLIBC_2.43 {
|
||||
mseal;
|
||||
openat2;
|
||||
}
|
||||
GLIBC_PRIVATE {
|
||||
# functions used in other libraries
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
49
sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h
Normal file
49
sysdeps/unix/sysv/linux/bits/fcntl-linux-fortify.h
Normal file
@@ -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 */
|
||||
@@ -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
|
||||
|
||||
60
sysdeps/unix/sysv/linux/bits/openat2.h
Normal file
60
sysdeps/unix/sysv/linux/bits/openat2.h
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
29
sysdeps/unix/sysv/linux/openat2.c
Normal file
29
sysdeps/unix/sysv/linux/openat2.c
Normal file
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
63
sysdeps/unix/sysv/linux/tst-openat2-consts.py
Executable file
63
sysdeps/unix/sysv/linux/tst-openat2-consts.py
Executable file
@@ -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()
|
||||
1
sysdeps/unix/sysv/linux/tst-openat2-lfs.c
Normal file
1
sysdeps/unix/sysv/linux/tst-openat2-lfs.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "tst-openat2.c"
|
||||
482
sysdeps/unix/sysv/linux/tst-openat2.c
Normal file
482
sysdeps/unix/sysv/linux/tst-openat2.c
Normal file
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user