diff --git a/glibc-RHEL-50545-1.patch b/glibc-RHEL-50545-1.patch new file mode 100644 index 0000000..a8a3fa1 --- /dev/null +++ b/glibc-RHEL-50545-1.patch @@ -0,0 +1,121 @@ +From 3bfdc4e2bceb601b90c81a9baa73c1904db58b2f Mon Sep 17 00:00:00 2001 +From: Andreas Schwab +Date: Tue, 28 Feb 2023 10:37:18 -0300 +Subject: [PATCH] support: use 64-bit time_t (bug 30111) +Content-type: text/plain; charset=UTF-8 + +Ensure to use 64-bit time_t in the test infrastructure. +--- + support/Makefile | 18 ++++++++++++++++++ + support/shell-container.c | 2 -- + support/support_can_chroot.c | 4 ++-- + support/support_copy_file.c | 2 +- + support/support_descriptor_supports_holes.c | 2 +- + support/test-container.c | 2 -- + 6 files changed, 22 insertions(+), 8 deletions(-) + +diff --git a/support/Makefile b/support/Makefile +index b29b7eb505..a304c5cdc0 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -239,6 +239,24 @@ CFLAGS-support_paths.c = \ + CFLAGS-timespec.c += -fexcess-precision=standard + CFLAGS-timespec-time64.c += -fexcess-precision=standard + ++# Ensure that general support files use 64-bit time_t ++CFLAGS-delayed_exit.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-shell-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-support_can_chroot.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-support_copy_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-support_copy_file_range.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-support_descriptor_supports_holes.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-support_descriptors.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-support_process_state.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-support_stat_nanoseconds.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-support_subprocess.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-support_test_main.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-test-container.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++CFLAGS-xmkdirp.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++# This is required to get an mkstemp which can create large files on some ++# 32-bit platforms. ++CFLAGS-temp_file.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 ++ + ifeq (,$(CXX)) + LINKS_DSO_PROGRAM = links-dso-program-c + else +diff --git a/support/shell-container.c b/support/shell-container.c +index e9ac9b6d04..ffa3378b5e 100644 +--- a/support/shell-container.c ++++ b/support/shell-container.c +@@ -16,8 +16,6 @@ + License along with the GNU C Library; if not, see + . */ + +-#define _FILE_OFFSET_BITS 64 +- + #include + #include + #include +diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c +index 7d9f91205d..7b4f491b53 100644 +--- a/support/support_can_chroot.c ++++ b/support/support_can_chroot.c +@@ -29,14 +29,14 @@ static void + callback (void *closure) + { + int *result = closure; +- struct stat64 before; ++ struct stat before; + xstat ("/dev", &before); + if (chroot ("/dev") != 0) + { + *result = errno; + return; + } +- struct stat64 after; ++ struct stat after; + xstat ("/", &after); + TEST_VERIFY (before.st_dev == after.st_dev); + TEST_VERIFY (before.st_ino == after.st_ino); +diff --git a/support/support_copy_file.c b/support/support_copy_file.c +index 50ff87b9f1..f3e0a2d1b7 100644 +--- a/support/support_copy_file.c ++++ b/support/support_copy_file.c +@@ -24,7 +24,7 @@ + void + support_copy_file (const char *from, const char *to) + { +- struct stat64 st; ++ struct stat st; + xstat (from, &st); + int fd_from = xopen (from, O_RDONLY, 0); + mode_t mode = st.st_mode & 0777; +diff --git a/support/support_descriptor_supports_holes.c b/support/support_descriptor_supports_holes.c +index 7af5934808..91db216bf0 100644 +--- a/support/support_descriptor_supports_holes.c ++++ b/support/support_descriptor_supports_holes.c +@@ -40,7 +40,7 @@ support_descriptor_supports_holes (int fd) + block_headroom = 32, + }; + +- struct stat64 st; ++ struct stat st; + xfstat (fd, &st); + if (!S_ISREG (st.st_mode)) + FAIL_EXIT1 ("descriptor %d does not refer to a regular file", fd); +diff --git a/support/test-container.c b/support/test-container.c +index f1a68b224a..e68f16eecf 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -16,8 +16,6 @@ + License along with the GNU C Library; if not, see + . */ + +-#define _FILE_OFFSET_BITS 64 +- + #include + #include + #include +-- +2.43.5 + diff --git a/glibc-RHEL-50545-10.patch b/glibc-RHEL-50545-10.patch new file mode 100644 index 0000000..714be39 --- /dev/null +++ b/glibc-RHEL-50545-10.patch @@ -0,0 +1,1337 @@ +From f169509ded534537eec9df00cfada6dbca908352 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 30 Aug 2024 21:52:53 +0200 +Subject: [PATCH] support: Add FUSE-based file system test framework to + support/ +Content-type: text/plain; charset=UTF-8 + +This allows to monitor the exact file system operations +performed by glibc and inject errors. + +Hurd does not have . To get the sources to compile +at least, the same approach as in support/test-container.c is used. + +Reviewed-by: DJ Delorie + +Conflicts + support/Makefile + context +--- + support/Makefile | 2 + + support/fuse.h | 215 +++++++++++ + support/support_fuse.c | 705 +++++++++++++++++++++++++++++++++++++ + support/tst-support_fuse.c | 348 ++++++++++++++++++ + 4 files changed, 1270 insertions(+) + create mode 100644 support/fuse.h + create mode 100644 support/support_fuse.c + create mode 100644 support/tst-support_fuse.c + +diff --git a/support/Makefile b/support/Makefile +index 8fb4d2c500..93d32ae75f 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -62,6 +62,7 @@ libsupport-routines = \ + support_format_herrno \ + support_format_hostent \ + support_format_netent \ ++ support_fuse \ + support_isolate_in_subprocess \ + support_need_proc \ + support_path_support_time64 \ +@@ -300,6 +301,7 @@ tests = \ + tst-support_capture_subprocess \ + tst-support_descriptors \ + tst-support_format_dns_packet \ ++ tst-support_fuse \ + tst-support-open-dev-null-range \ + tst-support-process_state \ + tst-support_quote_blob \ +diff --git a/support/fuse.h b/support/fuse.h +new file mode 100644 +index 0000000000..4c365fbc0c +--- /dev/null ++++ b/support/fuse.h +@@ -0,0 +1,215 @@ ++/* Facilities for FUSE-backed file system tests. ++ Copyright (C) 2024 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 ++ . */ ++ ++/* Before using this functionality, use support_enter_mount_namespace ++ to ensure that mounts do not impact the overall system. */ ++ ++#ifndef SUPPORT_FUSE_H ++#define SUPPORT_FUSE_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* This function must be called furst, before support_fuse_mount, to ++ prepare unprivileged mounting. */ ++void support_fuse_init (void); ++ ++/* This function can be called instead of support_fuse_init. It does ++ not use mount and user namespaces, so it requires root privileges, ++ and cleanup after testing may be incomplete. This is intended only ++ for test development. */ ++void support_fuse_init_no_namespace (void); ++ ++/* Opaque type for tracking FUSE mount state. */ ++struct support_fuse; ++ ++/* This function disables a mount point created using ++ support_fuse_mount. */ ++void support_fuse_unmount (struct support_fuse *) __nonnull ((1)); ++ ++/* This function is called on a separate thread after calling ++ support_fuse_mount. F is the mount state, and CLOSURE the argument ++ that was passed to support_fuse_mount. The callback function is ++ expected to call support_fuse_next to read packets from the kernel ++ and handle them according to the test's need. */ ++typedef void (*support_fuse_callback) (struct support_fuse *f, void *closure); ++ ++/* This function creates a new mount point, implemented by CALLBACK. ++ CLOSURE is passed to CALLBACK as the second argument. */ ++struct support_fuse *support_fuse_mount (support_fuse_callback callback, ++ void *closure) ++ __nonnull ((1)) __attr_dealloc (support_fuse_unmount, 1); ++ ++/* This function returns the path to the mount point for F. The ++ returned string is valid until support_fuse_unmount (F) is called. */ ++const char * support_fuse_mountpoint (struct support_fuse *f) __nonnull ((1)); ++ ++ ++/* Renders the OPCODE as a string (FUSE_* constant. The caller must ++ free the returned string. */ ++char * support_fuse_opcode (uint32_t opcode) __attr_dealloc_free; ++ ++/* Use to provide a checked cast facility. Use the ++ support_fuse_in_cast macro below. */ ++void *support_fuse_cast_internal (struct fuse_in_header *, uint32_t) ++ __nonnull ((1)); ++void *support_fuse_cast_name_internal (struct fuse_in_header *, uint32_t, ++ size_t skip, char **name) ++ __nonnull ((1)); ++ ++/* The macro expansion support_fuse_in_cast (P, TYPE) casts the ++ pointer INH to the appropriate type corresponding to the FUSE_TYPE ++ opcode. It fails (terminates the process) if INH->opcode does not ++ match FUSE_TYPE. The type of the returned pointer matches that of ++ the FUSE_* constant. ++ ++ Maintenance note: Adding support for additional struct fuse_*_in ++ types is generally easy, except when there is trailing data after ++ the struct (see below for support_fuse_cast_name, for example), and ++ the kernel has changed struct sizes over time. This has happened ++ recently with struct fuse_setxattr_in, and would require special ++ handling if implemented. */ ++#define support_fuse_payload_type_INIT struct fuse_init_in ++#define support_fuse_payload_type_LOOKUP char ++#define support_fuse_payload_type_OPEN struct fuse_open_in ++#define support_fuse_payload_type_READ struct fuse_read_in ++#define support_fuse_payload_type_SETATTR struct fuse_setattr_in ++#define support_fuse_payload_type_WRITE struct fuse_write_in ++#define support_fuse_cast(typ, inh) \ ++ ((support_fuse_payload_type_##typ *) \ ++ support_fuse_cast_internal ((inh), FUSE_##typ)) ++ ++/* Same as support_fuse_cast, but also writes the passed name to *NAMEP. */ ++#define support_fuse_payload_name_type_CREATE struct fuse_create_in ++#define support_fuse_payload_name_type_MKDIR struct fuse_mkdir_in ++#define support_fuse_cast_name(typ, inh, namep) \ ++ ((support_fuse_payload_name_type_##typ *) \ ++ support_fuse_cast_name_internal \ ++ ((inh), FUSE_##typ, sizeof (support_fuse_payload_name_type_##typ), \ ++ (namep))) ++ ++/* This function should be called from the callback function. It ++ returns NULL if the mount point has been unmounted. The result can ++ be cast using support_fuse_in_cast. The pointer is invalidated ++ with the next call to support_fuse_next. ++ ++ Typical use involves handling some basics using the ++ support_fuse_handle_* building blocks, following by a switch ++ statement on the result member of the returned struct, to implement ++ what a particular test needs. Casts to payload data should be made ++ using support_fuse_in_cast. ++ ++ By default, FUSE_FORGET responses are filtered. See ++ support_fuse_filter_forget for turning that off. */ ++struct fuse_in_header *support_fuse_next (struct support_fuse *f) ++ __nonnull ((1)); ++ ++/* This function can be called from a callback function to handle ++ basic aspects of directories (OPENDIR, GETATTR, RELEASEDIR). ++ inh->nodeid is used as the inode number for the directory. This ++ function must be called after support_fuse_next. */ ++bool support_fuse_handle_directory (struct support_fuse *f) __nonnull ((1)); ++ ++/* This function can be called from a callback function to handle ++ access to the mount point itself, after call support_fuse_next. */ ++bool support_fuse_handle_mountpoint (struct support_fuse *f) __nonnull ((1)); ++ ++/* If FILTER_ENABLED, future support_fuse_next calls will not return ++ FUSE_FORGET events (and simply discared them, as they require no ++ reply). If !FILTER_ENABLED, the callback needs to handle ++ FUSE_FORGET events and call support_fuse_no_reply. */ ++void support_fuse_filter_forget (struct support_fuse *f, bool filter_enabled) ++ __nonnull ((1)); ++ ++/* This function should be called from the callback function after ++ support_fuse_next returned a non-null pointer. It sends out a ++ response packet on the FUSE device with the supplied payload data. */ ++void support_fuse_reply (struct support_fuse *f, ++ const void *payload, size_t payload_size) ++ __nonnull ((1)) __attr_access ((__read_only__, 2, 3)); ++ ++/* This function should be called from the callback function. It ++ replies to a request with an error indicator. ERROR must be positive. */ ++void support_fuse_reply_error (struct support_fuse *f, uint32_t error) ++ __nonnull ((1)); ++ ++/* This function should be called from the callback function. It ++ sends out an empty (but success-indicating) reply packet. */ ++void support_fuse_reply_empty (struct support_fuse *f) __nonnull ((1)); ++ ++/* Do not send a reply. Only to be used after a support_fuse_next ++ call that returned a FUSE_FORGET event. */ ++void support_fuse_no_reply (struct support_fuse *f) __nonnull ((1)); ++ ++/* Specific reponse preparation functions. The returned object can be ++ updated as needed. If a NODEID argument is present, it will be ++ used to set the inode and FUSE nodeid fields. Without such an ++ argument, it is initialized from the current request (if the reply ++ requires this field). This function must be called after ++ support_fuse_next. The actual response must be sent using ++ support_fuse_reply_prepared (or a support_fuse_reply_error call can ++ be used to cancel the response). */ ++struct fuse_entry_out *support_fuse_prepare_entry (struct support_fuse *f, ++ uint64_t nodeid) ++ __nonnull ((1)); ++struct fuse_attr_out *support_fuse_prepare_attr (struct support_fuse *f) ++ __nonnull ((1)); ++ ++/* Similar to the other support_fuse_prepare_* functions, but it ++ prepares for two response packets. They can be updated through the ++ pointers written to *OUT_ENTRY and *OUT_OPEN prior to calling ++ support_fuse_reply_prepared. */ ++void support_fuse_prepare_create (struct support_fuse *f, ++ uint64_t nodeid, ++ struct fuse_entry_out **out_entry, ++ struct fuse_open_out **out_open) ++ __nonnull ((1, 3, 4)); ++ ++ ++/* Prepare sending a directory stream. Must be called after ++ support_fuse_next and before support_fuse_dirstream_add. */ ++struct support_fuse_dirstream; ++struct support_fuse_dirstream *support_fuse_prepare_readdir (struct ++ support_fuse *f); ++ ++/* Adds directory using D_INO, D_OFF, D_TYPE, D_NAME to the directory ++ stream D. Must be called after support_fuse_prepare_readdir. ++ ++ D_OFF is the offset of the next directory entry, not the current ++ one. The first entry has offset zero. The first requested offset ++ can be obtained from the READ payload (struct fuse_read_in) prior ++ to calling this function. ++ ++ Returns true if the entry could be added to the buffer, or false if ++ there was insufficient room. Sending the buffer is delayed until ++ support_fuse_reply_prepared is called. */ ++bool support_fuse_dirstream_add (struct support_fuse_dirstream *d, ++ uint64_t d_ino, uint64_t d_off, ++ uint32_t d_type, ++ const char *d_name); ++ ++/* Send a prepared response. Must be called after one of the ++ support_fuse_prepare_* functions and before the next ++ support_fuse_next call. */ ++void support_fuse_reply_prepared (struct support_fuse *f) __nonnull ((1)); ++ ++#endif /* SUPPORT_FUSE_H */ +diff --git a/support/support_fuse.c b/support/support_fuse.c +new file mode 100644 +index 0000000000..135dbf1198 +--- /dev/null ++++ b/support/support_fuse.c +@@ -0,0 +1,705 @@ ++/* Facilities for FUSE-backed file system tests. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __linux__ ++# include ++#else ++/* Fallback definitions that mark the test as unsupported. */ ++# define mount(...) ({ FAIL_UNSUPPORTED ("mount"); -1; }) ++# define umount(...) ({ FAIL_UNSUPPORTED ("mount"); -1; }) ++#endif ++ ++struct support_fuse ++{ ++ char *mountpoint; ++ void *buffer_start; /* Begin of allocation. */ ++ void *buffer_next; /* Next read position. */ ++ void *buffer_limit; /* End of buffered data. */ ++ void *buffer_end; /* End of allocation. */ ++ struct fuse_in_header *inh; /* Most recent request (support_fuse_next). */ ++ union /* Space for prepared responses. */ ++ { ++ struct fuse_attr_out attr; ++ struct fuse_entry_out entry; ++ struct ++ { ++ struct fuse_entry_out entry; ++ struct fuse_open_out open; ++ } create; ++ } prepared; ++ void *prepared_pointer; /* NULL if inactive. */ ++ size_t prepared_size; /* 0 if inactive. */ ++ ++ /* Used for preparing readdir responses. Already used-up area for ++ the current request is counted by prepared_size. */ ++ void *readdir_buffer; ++ size_t readdir_buffer_size; ++ ++ pthread_t handler; /* Thread handling requests. */ ++ uid_t uid; /* Cached value for the current process. */ ++ uid_t gid; /* Cached value for the current process. */ ++ int fd; /* FUSE file descriptor. */ ++ int connection; /* Entry under /sys/fs/fuse/connections. */ ++ bool filter_forget; /* Controls FUSE_FORGET event dropping. */ ++ _Atomic bool disconnected; ++}; ++ ++struct fuse_thread_wrapper_args ++{ ++ struct support_fuse *f; ++ support_fuse_callback callback; ++ void *closure; ++}; ++ ++/* Set by support_fuse_init to indicate that support_fuse_mount may be ++ called. */ ++static bool support_fuse_init_called; ++ ++/* Allocate the read buffer in F with SIZE bytes capacity. Does not ++ free the previously allocated buffer. */ ++static void support_fuse_allocate (struct support_fuse *f, size_t size) ++ __nonnull ((1)); ++ ++/* Internal mkdtemp replacement */ ++static char * support_fuse_mkdir (const char *prefix) __nonnull ((1)); ++ ++/* Low-level allocation function for support_fuse_mount. Does not ++ perform the mount. */ ++static struct support_fuse *support_fuse_open (void); ++ ++/* Thread wrapper function for use with pthread_create. Uses struct ++ fuse_thread_wrapper_args. */ ++static void *support_fuse_thread_wrapper (void *closure) __nonnull ((1)); ++ ++/* Initial step before preparing a reply. SIZE must be the size of ++ the F->prepared member that is going to be used. */ ++static void support_fuse_prepare_1 (struct support_fuse *f, size_t size); ++ ++/* Similar to support_fuse_reply_error, but not check that ERROR is ++ not zero. */ ++static void support_fuse_reply_error_1 (struct support_fuse *f, ++ uint32_t error) __nonnull ((1)); ++ ++/* Path to the directory containing mount points. Initialized by an ++ ELF constructor. All mountpoints are collected there so that the ++ test wrapper can clean them up without keeping track of them ++ individually. */ ++static char *support_fuse_mountpoints; ++ ++/* PID of the process that should clean up the mount points in the ELF ++ destructor. */ ++static pid_t support_fuse_cleanup_pid; ++ ++static void ++support_fuse_allocate (struct support_fuse *f, size_t size) ++{ ++ f->buffer_start = xmalloc (size); ++ f->buffer_end = f->buffer_start + size; ++ f->buffer_limit = f->buffer_start; ++ f->buffer_next = f->buffer_limit; ++} ++ ++void ++support_fuse_filter_forget (struct support_fuse *f, bool filter) ++{ ++ f->filter_forget = filter; ++} ++ ++void * ++support_fuse_cast_internal (struct fuse_in_header *p, uint32_t expected) ++{ ++ if (expected != p->opcode ++ && !(expected == FUSE_READ && p->opcode == FUSE_READDIR)) ++ { ++ char *expected1 = support_fuse_opcode (expected); ++ char *actual = support_fuse_opcode (p->opcode); ++ FAIL_EXIT1 ("attempt to cast %s to %s", actual, expected1); ++ } ++ return p + 1; ++} ++ ++void * ++support_fuse_cast_name_internal (struct fuse_in_header *p, uint32_t expected, ++ size_t skip, char **name) ++{ ++ char *result = support_fuse_cast_internal (p, expected); ++ *name = result + skip; ++ return result; ++} ++ ++bool ++support_fuse_dirstream_add (struct support_fuse_dirstream *d, ++ uint64_t d_ino, uint64_t d_off, ++ uint32_t d_type, const char *d_name) ++{ ++ struct support_fuse *f = (struct support_fuse *) d; ++ size_t structlen = offsetof (struct fuse_dirent, name); ++ size_t namelen = strlen (d_name); /* No null termination. */ ++ size_t required_size = FUSE_DIRENT_ALIGN (structlen + namelen); ++ if (f->readdir_buffer_size - f->prepared_size < required_size) ++ return false; ++ struct fuse_dirent entry = ++ { ++ .ino = d_ino, ++ .off = d_off, ++ .type = d_type, ++ .namelen = namelen, ++ }; ++ memcpy (f->readdir_buffer + f->prepared_size, &entry, structlen); ++ /* Use strncpy to write padding and avoid passing uninitialized ++ bytes to the read system call. */ ++ strncpy (f->readdir_buffer + f->prepared_size + structlen, d_name, ++ required_size - structlen); ++ f->prepared_size += required_size; ++ return true; ++} ++ ++bool ++support_fuse_handle_directory (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh != NULL); ++ switch (f->inh->opcode) ++ { ++ case FUSE_OPENDIR: ++ { ++ struct fuse_open_out out = ++ { ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ return true; ++ case FUSE_RELEASEDIR: ++ support_fuse_reply_empty (f); ++ return true; ++ case FUSE_GETATTR: ++ { ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFDIR | 0700; ++ support_fuse_reply_prepared (f); ++ } ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool ++support_fuse_handle_mountpoint (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh != NULL); ++ /* 1 is the root node. */ ++ if (f->inh->opcode == FUSE_GETATTR && f->inh->nodeid == 1) ++ return support_fuse_handle_directory (f); ++ return false; ++} ++ ++void ++support_fuse_init (void) ++{ ++ support_fuse_init_called = true; ++ ++ support_become_root (); ++ if (!support_enter_mount_namespace ()) ++ FAIL_UNSUPPORTED ("mount namespaces not supported"); ++} ++ ++void ++support_fuse_init_no_namespace (void) ++{ ++ support_fuse_init_called = true; ++} ++ ++static char * ++support_fuse_mkdir (const char *prefix) ++{ ++ /* Do not use mkdtemp to avoid interfering with its tests. */ ++ unsigned int counter = 1; ++ unsigned int pid = getpid (); ++ while (true) ++ { ++ char *path = xasprintf ("%s%u.%u/", prefix, pid, counter); ++ if (mkdir (path, 0700) == 0) ++ return path; ++ if (errno != EEXIST) ++ FAIL_EXIT1 ("mkdir (\"%s\"): %m", path); ++ free (path); ++ ++counter; ++ } ++} ++ ++struct support_fuse * ++support_fuse_mount (support_fuse_callback callback, void *closure) ++{ ++ TEST_VERIFY_EXIT (support_fuse_init_called); ++ ++ /* Request at least minor version 12 because it changed struct sizes. */ ++ enum { min_version = 12 }; ++ ++ struct support_fuse *f = support_fuse_open (); ++ char *mount_options ++ = xasprintf ("fd=%d,rootmode=040700,user_id=%u,group_id=%u", ++ f->fd, f->uid, f->gid); ++ if (mount ("fuse", f->mountpoint, "fuse.glibc", ++ MS_NOSUID|MS_NODEV, mount_options) ++ != 0) ++ FAIL_EXIT1 ("FUSE mount on %s: %m", f->mountpoint); ++ free (mount_options); ++ ++ /* Retry with an older FUSE version. */ ++ while (true) ++ { ++ struct fuse_in_header *inh = support_fuse_next (f); ++ struct fuse_init_in *init_in = support_fuse_cast (INIT, inh); ++ if (init_in->major < 7 ++ || (init_in->major == 7 && init_in->minor < min_version)) ++ FAIL_UNSUPPORTED ("kernel FUSE version is %u.%u, too old", ++ init_in->major, init_in->minor); ++ if (init_in->major > 7) ++ { ++ uint32_t major = 7; ++ support_fuse_reply (f, &major, sizeof (major)); ++ continue; ++ } ++ TEST_VERIFY (init_in->flags & FUSE_DONT_MASK); ++ struct fuse_init_out out = ++ { ++ .major = 7, ++ .minor = min_version, ++ /* Request that the kernel does not apply umask. */ ++ .flags = FUSE_DONT_MASK, ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ ++ { ++ struct fuse_thread_wrapper_args args = ++ { ++ .f = f, ++ .callback = callback, ++ .closure = closure, ++ }; ++ f->handler = xpthread_create (NULL, ++ support_fuse_thread_wrapper, &args); ++ struct stat64 st; ++ xstat64 (f->mountpoint, &st); ++ f->connection = minor (st.st_dev); ++ /* Got a reply from the thread, safe to deallocate args. */ ++ } ++ ++ return f; ++ } ++} ++ ++const char * ++support_fuse_mountpoint (struct support_fuse *f) ++{ ++ return f->mountpoint; ++} ++ ++void ++support_fuse_no_reply (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh != NULL); ++ TEST_COMPARE (f->inh->opcode, FUSE_FORGET); ++ f->inh = NULL; ++} ++ ++char * ++support_fuse_opcode (uint32_t op) ++{ ++ const char *result; ++ switch (op) ++ { ++#define X(n) case n: result = #n; break ++ X(FUSE_LOOKUP); ++ X(FUSE_FORGET); ++ X(FUSE_GETATTR); ++ X(FUSE_SETATTR); ++ X(FUSE_READLINK); ++ X(FUSE_SYMLINK); ++ X(FUSE_MKNOD); ++ X(FUSE_MKDIR); ++ X(FUSE_UNLINK); ++ X(FUSE_RMDIR); ++ X(FUSE_RENAME); ++ X(FUSE_LINK); ++ X(FUSE_OPEN); ++ X(FUSE_READ); ++ X(FUSE_WRITE); ++ X(FUSE_STATFS); ++ X(FUSE_RELEASE); ++ X(FUSE_FSYNC); ++ X(FUSE_SETXATTR); ++ X(FUSE_GETXATTR); ++ X(FUSE_LISTXATTR); ++ X(FUSE_REMOVEXATTR); ++ X(FUSE_FLUSH); ++ X(FUSE_INIT); ++ X(FUSE_OPENDIR); ++ X(FUSE_READDIR); ++ X(FUSE_RELEASEDIR); ++ X(FUSE_FSYNCDIR); ++ X(FUSE_GETLK); ++ X(FUSE_SETLK); ++ X(FUSE_SETLKW); ++ X(FUSE_ACCESS); ++ X(FUSE_CREATE); ++ X(FUSE_INTERRUPT); ++ X(FUSE_BMAP); ++ X(FUSE_DESTROY); ++ X(FUSE_IOCTL); ++ X(FUSE_POLL); ++ X(FUSE_NOTIFY_REPLY); ++ X(FUSE_BATCH_FORGET); ++ X(FUSE_FALLOCATE); ++ X(FUSE_READDIRPLUS); ++ X(FUSE_RENAME2); ++ X(FUSE_LSEEK); ++ X(FUSE_COPY_FILE_RANGE); ++ X(FUSE_SETUPMAPPING); ++ X(FUSE_REMOVEMAPPING); ++ X(FUSE_SYNCFS); ++ X(FUSE_TMPFILE); ++ X(FUSE_STATX); ++#undef X ++ default: ++ return xasprintf ("FUSE_unknown_%u", op); ++ } ++ return xstrdup (result); ++} ++ ++static struct support_fuse * ++support_fuse_open (void) ++{ ++ struct support_fuse *result = xmalloc (sizeof (*result)); ++ result->mountpoint = support_fuse_mkdir (support_fuse_mountpoints); ++ result->inh = NULL; ++ result->prepared_pointer = NULL; ++ result->prepared_size = 0; ++ result->readdir_buffer = NULL; ++ result->readdir_buffer_size = 0; ++ result->uid = getuid (); ++ result->gid = getgid (); ++ result->fd = open ("/dev/fuse", O_RDWR, 0); ++ if (result->fd < 0) ++ { ++ if (errno == ENOENT || errno == ENODEV || errno == EPERM ++ || errno == EACCES) ++ FAIL_UNSUPPORTED ("cannot open /dev/fuse: %m"); ++ else ++ FAIL_EXIT1 ("cannot open /dev/fuse: %m"); ++ } ++ result->connection = -1; ++ result->filter_forget = true; ++ result->disconnected = false; ++ support_fuse_allocate (result, FUSE_MIN_READ_BUFFER); ++ return result; ++} ++ ++static void ++support_fuse_prepare_1 (struct support_fuse *f, size_t size) ++{ ++ TEST_VERIFY (f->prepared_pointer == NULL); ++ f->prepared_size = size; ++ memset (&f->prepared, 0, size); ++ f->prepared_pointer = &f->prepared; ++} ++ ++struct fuse_attr_out * ++support_fuse_prepare_attr (struct support_fuse *f) ++{ ++ support_fuse_prepare_1 (f, sizeof (f->prepared.attr)); ++ f->prepared.attr.attr.uid = f->uid; ++ f->prepared.attr.attr.gid = f->gid; ++ f->prepared.attr.attr.ino = f->inh->nodeid; ++ return &f->prepared.attr; ++} ++ ++void ++support_fuse_prepare_create (struct support_fuse *f, ++ uint64_t nodeid, ++ struct fuse_entry_out **out_entry, ++ struct fuse_open_out **out_open) ++{ ++ support_fuse_prepare_1 (f, sizeof (f->prepared.create)); ++ f->prepared.create.entry.nodeid = nodeid; ++ f->prepared.create.entry.attr.uid = f->uid; ++ f->prepared.create.entry.attr.gid = f->gid; ++ f->prepared.create.entry.attr.ino = nodeid; ++ *out_entry = &f->prepared.create.entry; ++ *out_open = &f->prepared.create.open; ++} ++ ++struct fuse_entry_out * ++support_fuse_prepare_entry (struct support_fuse *f, uint64_t nodeid) ++{ ++ support_fuse_prepare_1 (f, sizeof (f->prepared.entry)); ++ f->prepared.entry.nodeid = nodeid; ++ f->prepared.entry.attr.uid = f->uid; ++ f->prepared.entry.attr.gid = f->gid; ++ f->prepared.entry.attr.ino = nodeid; ++ return &f->prepared.entry; ++} ++ ++struct support_fuse_dirstream * ++support_fuse_prepare_readdir (struct support_fuse *f) ++{ ++ support_fuse_prepare_1 (f, 0); ++ struct fuse_read_in *p = support_fuse_cast (READ, f->inh); ++ if (p->size > f->readdir_buffer_size) ++ { ++ free (f->readdir_buffer); ++ f->readdir_buffer = xmalloc (p->size); ++ f->readdir_buffer_size = p->size; ++ } ++ f->prepared_pointer = f->readdir_buffer; ++ return (struct support_fuse_dirstream *) f; ++} ++ ++struct fuse_in_header * ++support_fuse_next (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh == NULL); ++ while (true) ++ { ++ if (f->buffer_next < f->buffer_limit) ++ { ++ f->inh = f->buffer_next; ++ f->buffer_next = (void *) f->buffer_next + f->inh->len; ++ /* Suppress FUSE_FORGET responses if requested. */ ++ if (f->filter_forget && f->inh->opcode == FUSE_FORGET) ++ { ++ f->inh = NULL; ++ continue; ++ } ++ return f->inh; ++ } ++ ssize_t ret = read (f->fd, f->buffer_start, ++ f->buffer_end - f->buffer_start); ++ if (ret == 0) ++ FAIL_EXIT (1, "unexpected EOF on FUSE device"); ++ if (ret < 0 && errno == EINVAL) ++ { ++ /* Increase buffer size. */ ++ size_t new_size = 2 * (size_t) (f->buffer_end - f->buffer_start); ++ free (f->buffer_start); ++ support_fuse_allocate (f, new_size); ++ continue; ++ } ++ if (ret < 0) ++ { ++ if (f->disconnected) ++ /* Unmount detected. */ ++ return NULL; ++ FAIL_EXIT1 ("read error on FUSE device: %m"); ++ } ++ /* Read was successful, make [next, limit) the active buffer area. */ ++ f->buffer_next = f->buffer_start; ++ f->buffer_limit = (void *) f->buffer_start + ret; ++ } ++} ++ ++void ++support_fuse_reply (struct support_fuse *f, ++ const void *payload, size_t payload_size) ++{ ++ TEST_VERIFY_EXIT (f->inh != NULL); ++ TEST_VERIFY (f->prepared_pointer == NULL); ++ struct fuse_out_header outh = ++ { ++ .len = sizeof (outh) + payload_size, ++ .unique = f->inh->unique, ++ }; ++ struct iovec iov[] = ++ { ++ { &outh, sizeof (outh) }, ++ { (void *) payload, payload_size }, ++ }; ++ ssize_t ret = writev (f->fd, iov, array_length (iov)); ++ if (ret < 0) ++ { ++ if (!f->disconnected) ++ /* Some kernels produce write errors upon disconnect. */ ++ FAIL_EXIT1 ("FUSE write failed for %s response" ++ " (%zu bytes payload): %m", ++ support_fuse_opcode (f->inh->opcode), payload_size); ++ } ++ else if (ret != sizeof (outh) + payload_size) ++ FAIL_EXIT1 ("FUSE write short for %s response (%zu bytes payload):" ++ " %zd bytes", ++ support_fuse_opcode (f->inh->opcode), payload_size, ret); ++ f->inh = NULL; ++} ++ ++void ++support_fuse_reply_empty (struct support_fuse *f) ++{ ++ support_fuse_reply_error_1 (f, 0); ++} ++ ++static void ++support_fuse_reply_error_1 (struct support_fuse *f, uint32_t error) ++{ ++ TEST_VERIFY_EXIT (f->inh != NULL); ++ struct fuse_out_header outh = ++ { ++ .len = sizeof (outh), ++ .error = -error, ++ .unique = f->inh->unique, ++ }; ++ ssize_t ret = write (f->fd, &outh, sizeof (outh)); ++ if (ret < 0) ++ { ++ /* Some kernels produce write errors upon disconnect. */ ++ if (!f->disconnected) ++ FAIL_EXIT1 ("FUSE write failed for %s error response: %m", ++ support_fuse_opcode (f->inh->opcode)); ++ } ++ else if (ret != sizeof (outh)) ++ FAIL_EXIT1 ("FUSE write short for %s error response: %zd bytes", ++ support_fuse_opcode (f->inh->opcode), ret); ++ f->inh = NULL; ++ f->prepared_pointer = NULL; ++ f->prepared_size = 0; ++} ++ ++void ++support_fuse_reply_error (struct support_fuse *f, uint32_t error) ++{ ++ TEST_VERIFY (error > 0); ++ support_fuse_reply_error_1 (f, error); ++} ++ ++void ++support_fuse_reply_prepared (struct support_fuse *f) ++{ ++ TEST_VERIFY_EXIT (f->prepared_pointer != NULL); ++ /* Re-use the non-prepared reply function. It requires ++ f->prepared_* to be non-null, so reset the fields before the call. */ ++ void *prepared_pointer = f->prepared_pointer; ++ size_t prepared_size = f->prepared_size; ++ f->prepared_pointer = NULL; ++ f->prepared_size = 0; ++ support_fuse_reply (f, prepared_pointer, prepared_size); ++} ++ ++static void * ++support_fuse_thread_wrapper (void *closure) ++{ ++ struct fuse_thread_wrapper_args args ++ = *(struct fuse_thread_wrapper_args *) closure; ++ ++ /* Handle the initial stat call. */ ++ struct fuse_in_header *inh = support_fuse_next (args.f); ++ if (inh == NULL || !support_fuse_handle_mountpoint (args.f)) ++ { ++ support_fuse_reply_error (args.f, EIO); ++ return NULL; ++ } ++ ++ args.callback (args.f, args.closure); ++ return NULL; ++} ++ ++void ++support_fuse_unmount (struct support_fuse *f) ++{ ++ /* Signal the unmount to the handler thread. Some kernels report ++ not just ENODEV errors on read. */ ++ f->disconnected = true; ++ ++ { ++ char *path = xasprintf ("/sys/fs/fuse/connections/%d/abort", ++ f->connection); ++ /* Some kernels do not support these files under /sys. */ ++ int fd = open (path, O_RDWR | O_TRUNC); ++ if (fd >= 0) ++ { ++ TEST_COMPARE (write (fd, "1", 1), 1); ++ xclose (fd); ++ } ++ free (path); ++ } ++ if (umount (f->mountpoint) != 0) ++ FAIL ("FUSE: umount (\"%s\"): %m", f->mountpoint); ++ xpthread_join (f->handler); ++ if (rmdir (f->mountpoint) != 0) ++ FAIL ("FUSE: rmdir (\"%s\"): %m", f->mountpoint); ++ xclose (f->fd); ++ free (f->mountpoint); ++ free (f->readdir_buffer); ++ free (f); ++} ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ /* The test_dir test driver variable is not yet set at this point. */ ++ const char *tmpdir = getenv ("TMPDIR"); ++ if (tmpdir == NULL || tmpdir[0] == '\0') ++ tmpdir = "/tmp"; ++ ++ char *prefix = xasprintf ("%s/glibc-tst-fuse.", tmpdir); ++ support_fuse_mountpoints = support_fuse_mkdir (prefix); ++ free (prefix); ++ support_fuse_cleanup_pid = getpid (); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (support_fuse_cleanup_pid != getpid () ++ || support_fuse_mountpoints == NULL) ++ return; ++ DIR *dir = xopendir (support_fuse_mountpoints); ++ while (true) ++ { ++ struct dirent64 *e = readdir64 (dir); ++ if (e == NULL) ++ /* Ignore errors. */ ++ break; ++ if (*e->d_name == '.') ++ /* Skip "." and "..". No hidden files expected. */ ++ continue; ++ if (unlinkat (dirfd (dir), e->d_name, AT_REMOVEDIR) != 0) ++ break; ++ rewinddir (dir); ++ } ++ xclosedir (dir); ++ rmdir (support_fuse_mountpoints); ++ free (support_fuse_mountpoints); ++ support_fuse_mountpoints = NULL; ++} +diff --git a/support/tst-support_fuse.c b/support/tst-support_fuse.c +new file mode 100644 +index 0000000000..c4075a6608 +--- /dev/null ++++ b/support/tst-support_fuse.c +@@ -0,0 +1,348 @@ ++/* Facilities for FUSE-backed file system tests. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++fuse_thread (struct support_fuse *f, void *closure) ++{ ++ /* Turn on returning FUSE_FORGET responses. */ ++ support_fuse_filter_forget (f, false); ++ ++ /* Inode and nodeid for "file" and "new". */ ++ enum { NODE_FILE = 2, NODE_NEW, NODE_SUBDIR, NODE_SYMLINK }; ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ { ++ char *opcode = support_fuse_opcode (inh->opcode); ++ printf ("info: (T) event %s(%llu) len=%u nodeid=%llu\n", ++ opcode, (unsigned long long int) inh->unique, inh->len, ++ (unsigned long long int) inh->nodeid); ++ free (opcode); ++ } ++ ++ /* Handle mountpoint and basic directory operation for the root (1). */ ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ ++ switch (inh->opcode) ++ { ++ case FUSE_READDIR: ++ /* Implementation of getdents64. */ ++ if (inh->nodeid == 1) ++ { ++ struct support_fuse_dirstream *d ++ = support_fuse_prepare_readdir (f); ++ TEST_COMPARE (support_fuse_cast (READ, inh)->offset, 0); ++ TEST_VERIFY (support_fuse_dirstream_add (d, 1, 1, DT_DIR, ".")); ++ TEST_VERIFY (support_fuse_dirstream_add (d, 1, 2, DT_DIR, "..")); ++ TEST_VERIFY (support_fuse_dirstream_add (d, NODE_FILE, 3, DT_REG, ++ "file")); ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_LOOKUP: ++ /* Part of the implementation of open. */ ++ { ++ char *name = support_fuse_cast (LOOKUP, inh); ++ printf (" name: %s\n", name); ++ if (inh->nodeid == 1 && strcmp (name, "file") == 0) ++ { ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, NODE_FILE); ++ out->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ else if (inh->nodeid == 1 && strcmp (name, "symlink") == 0) ++ { ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, NODE_SYMLINK); ++ out->attr.mode = S_IFLNK | 0777; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, ENOENT); ++ } ++ break; ++ case FUSE_OPEN: ++ /* Implementation of open. */ ++ { ++ struct fuse_open_in *p = support_fuse_cast (OPEN, inh); ++ if (inh->nodeid == NODE_FILE) ++ { ++ TEST_VERIFY (!(p->flags & O_EXCL)); ++ struct fuse_open_out out = { 0, }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ else ++ support_fuse_reply_error (f, ENOENT); ++ } ++ break; ++ case FUSE_GETATTR: ++ /* Happens after open. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFREG | 0600; ++ out->attr.size = strlen ("Hello, world!"); ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, ENOENT); ++ break; ++ case FUSE_READ: ++ /* Implementation of read. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_read_in *p = support_fuse_cast (READ, inh); ++ TEST_COMPARE (p->offset, 0); ++ TEST_VERIFY (p->size >= strlen ("Hello, world!")); ++ support_fuse_reply (f, ++ "Hello, world!", strlen ("Hello, world!")); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_FLUSH: ++ /* Sent in response to close. */ ++ support_fuse_reply_empty (f); ++ break; ++ case FUSE_GETXATTR: ++ /* This happens as part of a open-for-write operation. ++ Signal no support for extended attributes. */ ++ support_fuse_reply_error (f, ENOSYS); ++ break; ++ case FUSE_SETATTR: ++ /* This happens as part of a open-for-write operation to ++ implement O_TRUNC. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_setattr_in *p = support_fuse_cast (SETATTR, inh); ++ /* FATTR_LOCKOWNER may also be set. */ ++ TEST_COMPARE ((p->valid) & ~ FATTR_LOCKOWNER, FATTR_SIZE); ++ TEST_COMPARE (p->size, 0); ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_WRITE: ++ /* Implementation of write. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_write_in *p = support_fuse_cast (WRITE, inh); ++ TEST_COMPARE (p->offset, 0); ++ /* Write payload follows after struct fuse_write_in. */ ++ TEST_COMPARE_BLOB (p + 1, p->size, ++ "Good day to you too.", ++ strlen ("Good day to you too.")); ++ struct fuse_write_out out = ++ { ++ .size = p->size, ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_CREATE: ++ /* Implementation of O_CREAT. */ ++ if (inh->nodeid == 1) ++ { ++ char *name; ++ struct fuse_create_in *p ++ = support_fuse_cast_name (CREATE, inh, &name); ++ TEST_VERIFY (S_ISREG (p->mode)); ++ TEST_COMPARE (p->mode & 07777, 0600); ++ TEST_COMPARE_STRING (name, "new"); ++ struct fuse_entry_out *out_entry; ++ struct fuse_open_out *out_open; ++ support_fuse_prepare_create (f, NODE_NEW, &out_entry, &out_open); ++ out_entry->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_MKDIR: ++ /* Implementation of mkdir. */ ++ { ++ if (inh->nodeid == 1) ++ { ++ char *name; ++ struct fuse_mkdir_in *p ++ = support_fuse_cast_name (MKDIR, inh, &name); ++ TEST_COMPARE (p->mode, 01234); ++ TEST_COMPARE_STRING (name, "subdir"); ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, NODE_SUBDIR); ++ out->attr.mode = S_IFDIR | p->mode; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ } ++ break; ++ case FUSE_READLINK: ++ /* Implementation of readlink. */ ++ TEST_COMPARE (inh->nodeid, NODE_SYMLINK); ++ if (inh->nodeid == NODE_SYMLINK) ++ support_fuse_reply (f, "target-of-symbolic-link", ++ strlen ("target-of-symbolic-link")); ++ else ++ support_fuse_reply_error (f, EINVAL); ++ break; ++ case FUSE_FORGET: ++ support_fuse_no_reply (f); ++ break; ++ default: ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ ++ printf ("info: Attributes of mountpoint/root directory %s\n", ++ support_fuse_mountpoint (f)); ++ { ++ struct statx st; ++ xstatx (AT_FDCWD, support_fuse_mountpoint (f), 0, STATX_BASIC_STATS, &st); ++ TEST_COMPARE (st.stx_uid, getuid ()); ++ TEST_COMPARE (st.stx_gid, getgid ()); ++ TEST_VERIFY (S_ISDIR (st.stx_mode)); ++ TEST_COMPARE (st.stx_mode & 07777, 0700); ++ } ++ ++ printf ("info: List directory %s\n", support_fuse_mountpoint (f)); ++ { ++ DIR *dir = xopendir (support_fuse_mountpoint (f)); ++ ++ struct dirent *e = xreaddir (dir); ++ TEST_COMPARE (e->d_ino, 1); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_COMPARE (e->d_off, 1); ++#endif ++ TEST_COMPARE (e->d_type, DT_DIR); ++ TEST_COMPARE_STRING (e->d_name, "."); ++ ++ e = xreaddir (dir); ++ TEST_COMPARE (e->d_ino, 1); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_COMPARE (e->d_off, 2); ++#endif ++ TEST_COMPARE (e->d_type, DT_DIR); ++ TEST_COMPARE_STRING (e->d_name, ".."); ++ ++ e = xreaddir (dir); ++ TEST_COMPARE (e->d_ino, 2); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_COMPARE (e->d_off, 3); ++#endif ++ TEST_COMPARE (e->d_type, DT_REG); ++ TEST_COMPARE_STRING (e->d_name, "file"); ++ ++ TEST_COMPARE (closedir (dir), 0); ++ } ++ ++ char *file_path = xasprintf ("%s/file", support_fuse_mountpoint (f)); ++ ++ printf ("info: Attributes of file %s\n", file_path); ++ { ++ struct statx st; ++ xstatx (AT_FDCWD, file_path, 0, STATX_BASIC_STATS, &st); ++ TEST_COMPARE (st.stx_uid, getuid ()); ++ TEST_COMPARE (st.stx_gid, getgid ()); ++ TEST_VERIFY (S_ISREG (st.stx_mode)); ++ TEST_COMPARE (st.stx_mode & 07777, 0600); ++ TEST_COMPARE (st.stx_size, strlen ("Hello, world!")); ++ } ++ ++ printf ("info: Read from %s\n", file_path); ++ { ++ int fd = xopen (file_path, O_RDONLY, 0); ++ char buf[64]; ++ ssize_t len = read (fd, buf, sizeof (buf)); ++ if (len < 0) ++ FAIL_EXIT1 ("read: %m"); ++ TEST_COMPARE_BLOB (buf, len, "Hello, world!", strlen ("Hello, world!")); ++ xclose (fd); ++ } ++ ++ printf ("info: Write to %s\n", file_path); ++ { ++ int fd = xopen (file_path, O_WRONLY | O_TRUNC, 0); ++ xwrite (fd, "Good day to you too.", strlen ("Good day to you too.")); ++ xclose (fd); ++ } ++ ++ printf ("info: Attempt O_EXCL creation of existing %s\n", file_path); ++ /* O_EXCL creation shall fail. */ ++ errno = 0; ++ TEST_COMPARE (open64 (file_path, O_RDWR | O_EXCL | O_CREAT, 0600), -1); ++ TEST_COMPARE (errno, EEXIST); ++ ++ free (file_path); ++ ++ { ++ char *new_path = xasprintf ("%s/new", support_fuse_mountpoint (f)); ++ printf ("info: Test successful O_EXCL creation at %s\n", new_path); ++ int fd = xopen (new_path, O_RDWR | O_EXCL | O_CREAT, 0600); ++ xclose (fd); ++ free (new_path); ++ } ++ ++ { ++ char *subdir_path = xasprintf ("%s/subdir", support_fuse_mountpoint (f)); ++ xmkdir (subdir_path, 01234); ++ } ++ ++ { ++ char *symlink_path = xasprintf ("%s/symlink", support_fuse_mountpoint (f)); ++ char *target = xreadlink (symlink_path); ++ TEST_COMPARE_STRING (target, "target-of-symbolic-link"); ++ free (target); ++ free (symlink_path); ++ } ++ ++ support_fuse_unmount (f); ++ return 0; ++} ++ ++#include +-- +2.43.5 + diff --git a/glibc-RHEL-50545-11.patch b/glibc-RHEL-50545-11.patch new file mode 100644 index 0000000..4681971 --- /dev/null +++ b/glibc-RHEL-50545-11.patch @@ -0,0 +1,501 @@ +From e3db0a699c639e97deddcb15939fd9c162801c77 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Sat, 21 Sep 2024 19:25:35 +0200 +Subject: [PATCH] misc: FUSE-based tests for mkstemp +Content-type: text/plain; charset=UTF-8 + +The tests check that O_EXCL is used properly, that 0600 is used +as the mode, that the characters used are as expected, and that +the distribution of names generated is reasonably random. + +The tests run very slowly on some kernel versions, so make them +xtests. + +Reviewed-by: DJ Delorie + +Conflicts + misc/Makefile + context +--- + misc/Makefile | 6 + + misc/tst-mkstemp-fuse-parallel.c | 219 +++++++++++++++++++++++++++++++ + misc/tst-mkstemp-fuse.c | 197 +++++++++++++++++++++++++++ + 3 files changed, 422 insertions(+) + create mode 100644 misc/tst-mkstemp-fuse-parallel.c + create mode 100644 misc/tst-mkstemp-fuse.c + +diff --git a/misc/Makefile b/misc/Makefile +index 7b7f8351bf..1422c95317 100644 +--- a/misc/Makefile ++++ b/misc/Makefile +@@ -109,6 +109,12 @@ tests-static := tst-empty + tests-internal += tst-fd_to_filename + tests-static += tst-fd_to_filename + ++# Tests with long run times. ++xtests += \ ++ tst-mkstemp-fuse \ ++ tst-mkstemp-fuse-parallel \ ++ # xtests ++ + ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-error1-mem.out \ + $(objpfx)tst-allocate_once-mem.out +diff --git a/misc/tst-mkstemp-fuse-parallel.c b/misc/tst-mkstemp-fuse-parallel.c +new file mode 100644 +index 0000000000..219f26cb3b +--- /dev/null ++++ b/misc/tst-mkstemp-fuse-parallel.c +@@ -0,0 +1,246 @@ ++/* FUSE-based test for mkstemp. Parallel collision statistics. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* The number of subprocesses that call mkstemp. */ ++static pid_t processes[4]; ++ ++/* Enough space to record the expected number of replies (62**3) for ++ each process. */ ++enum { results_allocated = array_length (processes) * 62 * 62 * 62 }; ++ ++/* The thread will store the results there. */ ++static uint64_t *results; ++ ++/* Currently used part of the results array. */ ++static size_t results_used; ++ ++ ++/* Copied from upstream's string/strlcpy.c . */ ++static size_t ++strlcpy (char *__restrict dest, const char *__restrict src, size_t size) ++{ ++ size_t src_length = strlen (src); ++ ++ if (__glibc_unlikely (src_length >= size)) ++ { ++ if (size > 0) ++ { ++ /* Copy the leading portion of the string. The last ++ character is subsequently overwritten with the NUL ++ terminator, but the destination size is usually a ++ multiple of a small power of two, so writing it twice ++ should be more efficient than copying an odd number of ++ bytes. */ ++ memcpy (dest, src, size); ++ dest[size - 1] = '\0'; ++ } ++ } ++ else ++ /* Copy the string and its terminating NUL character. */ ++ memcpy (dest, src, src_length + 1); ++ return src_length; ++} ++ ++/* Fail with EEXIST (so that mkstemp tries again). Record observed ++ names for later statistical analysis. */ ++static void ++fuse_thread (struct support_fuse *f, void *closure) ++{ ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ if (inh->opcode != FUSE_LOOKUP || results_used >= results_allocated) ++ { ++ support_fuse_reply_error (f, EIO); ++ continue; ++ } ++ ++ char *name = support_fuse_cast (LOOKUP, inh); ++ TEST_COMPARE_BLOB (name, 3, "new", 3); ++ TEST_COMPARE (strlen (name), 9); ++ /* Extract 8 bytes of the name: 'w', the X replacements, and the ++ null terminator. Treat it as an uint64_t for easy sorting ++ below. Endianess does not matter because the relative order ++ of the entries is not important; sorting is only used to find ++ duplicates. */ ++ TEST_VERIFY_EXIT (results_used < results_allocated); ++ memcpy (&results[results_used], name + 2, 8); ++ ++results_used; ++ struct fuse_entry_out *out = support_fuse_prepare_entry (f, 2); ++ out->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++} ++ ++/* Used to sort the results array, to find duplicates. */ ++static int ++results_sort (const void *a1, const void *b1) ++{ ++ const uint64_t *a = a1; ++ const uint64_t *b = b1; ++ if (*a < *b) ++ return -1; ++ if (*a == *b) ++ return 0; ++ return 1; ++} ++ ++/* Number of occurrences of certain streak lengths. */ ++static size_t streak_lengths[6]; ++ ++/* Called for every encountered streak. */ ++static inline void ++report_streak (uint64_t current, size_t length) ++{ ++ if (length > 1) ++ { ++ printf ("info: name \"ne%.8s\" repeats: %zu\n", ++ (char *) ¤t, length); ++ TEST_VERIFY_EXIT (length < array_length (streak_lengths)); ++ } ++ TEST_VERIFY_EXIT (length < array_length (streak_lengths)); ++ ++streak_lengths[length]; ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ results = xmalloc (results_allocated * sizeof (*results)); ++ ++ struct shared ++ { ++ /* Used to synchronize the start of all subprocesses, to make it ++ more likely to expose concurrency-related bugs. */ ++ pthread_barrier_t barrier1; ++ pthread_barrier_t barrier2; ++ ++ /* Filled in after fork. */ ++ char mountpoint[4096]; ++ }; ++ ++ /* Used to synchronize the start of all subprocesses, to make it ++ more likely to expose concurrency-related bugs. */ ++ struct shared *pshared = support_shared_allocate (sizeof (*pshared)); ++ { ++ pthread_barrierattr_t attr; ++ xpthread_barrierattr_init (&attr); ++ xpthread_barrierattr_setpshared (&attr, PTHREAD_PROCESS_SHARED); ++ xpthread_barrierattr_destroy (&attr); ++ xpthread_barrier_init (&pshared->barrier1, &attr, ++ array_length (processes) + 1); ++ xpthread_barrier_init (&pshared->barrier2, &attr, ++ array_length (processes) + 1); ++ xpthread_barrierattr_destroy (&attr); ++ } ++ ++ for (int i = 0; i < array_length (processes); ++i) ++ { ++ processes[i] = xfork (); ++ if (processes[i] == 0) ++ { ++ /* Wait for mountpoint initialization. */ ++ xpthread_barrier_wait (&pshared->barrier1); ++ char *path = xasprintf ("%s/newXXXXXX", pshared->mountpoint); ++ ++ /* Park this process until all processes have started. */ ++ xpthread_barrier_wait (&pshared->barrier2); ++ errno = 0; ++ TEST_COMPARE (mkstemp (path), -1); ++ TEST_COMPARE (errno, EEXIST); ++ free (path); ++ _exit (0); ++ } ++ } ++ ++ /* Do this after the forking, to minimize initialization inteference. */ ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ TEST_VERIFY (strlcpy (pshared->mountpoint, support_fuse_mountpoint (f), ++ sizeof (pshared->mountpoint)) ++ < sizeof (pshared->mountpoint)); ++ xpthread_barrier_wait (&pshared->barrier1); ++ ++ puts ("info: performing mkstemp calls"); ++ xpthread_barrier_wait (&pshared->barrier2); ++ ++ for (int i = 0; i < array_length (processes); ++i) ++ { ++ int status; ++ xwaitpid (processes[i], &status, 0); ++ TEST_COMPARE (status, 0); ++ } ++ ++ support_fuse_unmount (f); ++ xpthread_barrier_destroy (&pshared->barrier2); ++ xpthread_barrier_destroy (&pshared->barrier1); ++ ++ printf ("info: checking results (count %zu)\n", results_used); ++ qsort (results, results_used, sizeof (*results), results_sort); ++ ++ uint64_t current = -1; ++ size_t streak = 0; ++ for (size_t i = 0; i < results_used; ++i) ++ if (results[i] == current) ++ ++streak; ++ else ++ { ++ report_streak (current, streak); ++ current = results[i]; ++ streak = 1; ++ } ++ report_streak (current, streak); ++ ++ puts ("info: repetition count distribution:"); ++ for (int i = 1; i < array_length (streak_lengths); ++i) ++ printf (" length %d: %zu\n", i, streak_lengths[i]); ++ /* Some arbitrary threshold, hopefully unlikely enough. In over ++ 260,000 runs of a simulation of this test, at most 26 pairs were ++ observed, and only one three-way collisions. */ ++ if (streak_lengths[2] > 30) ++ FAIL ("unexpected repetition count 2: %zu", streak_lengths[2]); ++ if (streak_lengths[3] > 2) ++ FAIL ("unexpected repetition count 3: %zu", streak_lengths[3]); ++ for (int i = 4; i < array_length (streak_lengths); ++i) ++ if (streak_lengths[i] > 0) ++ FAIL ("too many repeats of count %d: %zu", i, streak_lengths[i]); ++ ++ free (results); ++ ++ return 0; ++} ++ ++#include +diff --git a/misc/tst-mkstemp-fuse.c b/misc/tst-mkstemp-fuse.c +new file mode 100644 +index 0000000000..5ac6a6872a +--- /dev/null ++++ b/misc/tst-mkstemp-fuse.c +@@ -0,0 +1,197 @@ ++/* FUSE-based test for mkstemp. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to true in do_test to cause the first FUSE_CREATE attempt to fail. */ ++static _Atomic bool simulate_creat_race; ++ ++/* Basic tests with eventually successful creation. */ ++static void ++fuse_thread_basic (struct support_fuse *f, void *closure) ++{ ++ char *previous_name = NULL; ++ int state = 0; ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ ++ switch (inh->opcode) ++ { ++ case FUSE_LOOKUP: ++ /* File does not exist initially. */ ++ TEST_COMPARE (inh->nodeid, 1); ++ if (simulate_creat_race) ++ { ++ if (state < 3) ++ ++state; ++ else ++ FAIL ("invalid state: %d", state); ++ } ++ else ++ { ++ TEST_COMPARE (state, 0); ++ state = 3; ++ } ++ support_fuse_reply_error (f, ENOENT); ++ break; ++ case FUSE_CREATE: ++ { ++ TEST_COMPARE (inh->nodeid, 1); ++ char *name; ++ struct fuse_create_in *p ++ = support_fuse_cast_name (CREATE, inh, &name); ++ /* Name follows after struct fuse_create_in. */ ++ TEST_COMPARE (p->flags & O_ACCMODE, O_RDWR); ++ TEST_VERIFY (p->flags & O_EXCL); ++ TEST_VERIFY (p->flags & O_CREAT); ++ TEST_COMPARE (p->mode & 07777, 0600); ++ TEST_VERIFY (S_ISREG (p->mode)); ++ TEST_COMPARE_BLOB (name, 3, "new", 3); ++ ++ if (state != 3 && simulate_creat_race) ++ { ++ ++state; ++ support_fuse_reply_error (f, EEXIST); ++ } ++ else ++ { ++ if (previous_name != NULL) ++ /* This test has a very small probability of failure ++ due to a harmless collision (one in 62**6 tests). */ ++ TEST_VERIFY (strcmp (name, previous_name) != 0); ++ TEST_COMPARE (state, 3); ++ ++state; ++ struct fuse_entry_out *entry; ++ struct fuse_open_out *open; ++ support_fuse_prepare_create (f, 2, &entry, &open); ++ entry->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ free (previous_name); ++ previous_name = xstrdup (name); ++ } ++ break; ++ case FUSE_FLUSH: ++ case FUSE_RELEASE: ++ TEST_COMPARE (state, 4); ++ TEST_COMPARE (inh->nodeid, 2); ++ support_fuse_reply_empty (f); ++ break; ++ default: ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++ free (previous_name); ++} ++ ++/* Reply that all files exist. */ ++static void ++fuse_thread_eexist (struct support_fuse *f, void *closure) ++{ ++ uint64_t counter = 0; ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ ++ switch (inh->opcode) ++ { ++ case FUSE_LOOKUP: ++ ++counter; ++ TEST_COMPARE (inh->nodeid, 1); ++ char *name = support_fuse_cast (LOOKUP, inh); ++ TEST_COMPARE_BLOB (name, 3, "new", 3); ++ TEST_COMPARE (strlen (name), 9); ++ for (int i = 3; i <= 8; ++i) ++ { ++ /* The glibc implementation uses letters and digits only. */ ++ char ch = name[i]; ++ TEST_VERIFY (('0' <= ch && ch <= '9') ++ || ('a' <= ch && ch <= 'z') ++ || ('A' <= ch && ch <= 'Z')); ++ } ++ struct fuse_entry_out out = ++ { ++ .nodeid = 2, ++ .attr = { ++ .mode = S_IFREG | 0600, ++ .ino = 2, ++ }, ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ break; ++ default: ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++ /* Verify that mkstemp has retried a lot. The current ++ implementation tries 62 * 62 * 62 times until it goves up. */ ++ TEST_VERIFY (counter >= 200000); ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ for (int do_simulate_creat_race = 0; do_simulate_creat_race < 2; ++ ++do_simulate_creat_race) ++ { ++ simulate_creat_race = do_simulate_creat_race; ++ printf ("info: testing with simulate_creat_race == %d\n", ++ (int) simulate_creat_race); ++ struct support_fuse *f = support_fuse_mount (fuse_thread_basic, NULL); ++ char *path = xasprintf ("%s/newXXXXXX", support_fuse_mountpoint (f)); ++ int fd = mkstemp (path); ++ TEST_VERIFY (fd > 2); ++ xclose (fd); ++ free (path); ++ support_fuse_unmount (f); ++ } ++ ++ puts ("info: testing EEXIST failure case for mkstemp"); ++ { ++ struct support_fuse *f = support_fuse_mount (fuse_thread_eexist, NULL); ++ char *path = xasprintf ("%s/newXXXXXX", support_fuse_mountpoint (f)); ++ errno = 0; ++ TEST_COMPARE (mkstemp (path), -1); ++ TEST_COMPARE (errno, EEXIST); ++ free (path); ++ support_fuse_unmount (f); ++ } ++ ++ return 0; ++} ++ ++#include +-- +2.43.5 + diff --git a/glibc-RHEL-50545-12.patch b/glibc-RHEL-50545-12.patch new file mode 100644 index 0000000..a54cff9 --- /dev/null +++ b/glibc-RHEL-50545-12.patch @@ -0,0 +1,40 @@ +From 455c7622835d16c79e49fe75b8d3a1ae59a3d0ee Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Sat, 21 Sep 2024 19:25:35 +0200 +Subject: [PATCH] support: Fix memory leaks in FUSE tests +Content-type: text/plain; charset=UTF-8 + +The internal read buffer (used by all FUSE tests) was not freed. +The support/tst-support_fuse test missed a deallocation. +--- + support/support_fuse.c | 1 + + support/tst-support_fuse.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/support/support_fuse.c b/support/support_fuse.c +index 135dbf1198..f6c063b549 100644 +--- a/support/support_fuse.c ++++ b/support/support_fuse.c +@@ -659,6 +659,7 @@ support_fuse_unmount (struct support_fuse *f) + if (rmdir (f->mountpoint) != 0) + FAIL ("FUSE: rmdir (\"%s\"): %m", f->mountpoint); + xclose (f->fd); ++ free (f->buffer_start); + free (f->mountpoint); + free (f->readdir_buffer); + free (f); +diff --git a/support/tst-support_fuse.c b/support/tst-support_fuse.c +index c4075a6608..9ee637cbab 100644 +--- a/support/tst-support_fuse.c ++++ b/support/tst-support_fuse.c +@@ -331,6 +331,7 @@ do_test (void) + { + char *subdir_path = xasprintf ("%s/subdir", support_fuse_mountpoint (f)); + xmkdir (subdir_path, 01234); ++ free (subdir_path); + } + + { +-- +2.43.5 + diff --git a/glibc-RHEL-50545-13.patch b/glibc-RHEL-50545-13.patch new file mode 100644 index 0000000..59b5f29 --- /dev/null +++ b/glibc-RHEL-50545-13.patch @@ -0,0 +1,32 @@ +From 366cce74d2aa2e5753d8787d415b745fd57fda04 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Sat, 21 Sep 2024 19:29:13 +0200 +Subject: [PATCH] support: Add valgrind instructions to +Content-type: text/plain; charset=UTF-8 + +Replacing an outdated comment (namespace setup is now handled by +support_fuse_init). +--- + support/fuse.h | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/support/fuse.h b/support/fuse.h +index 4c365fbc0c..1c862bedbe 100644 +--- a/support/fuse.h ++++ b/support/fuse.h +@@ -16,8 +16,10 @@ + License along with the GNU C Library; if not, see + . */ + +-/* Before using this functionality, use support_enter_mount_namespace +- to ensure that mounts do not impact the overall system. */ ++/* To run FUSE tests under valgrind, pass the ++ --sim-hints=fuse-compatible option to valgrind. This option tells ++ valgrind that additional system calls effectively call back into ++ the current program. */ + + #ifndef SUPPORT_FUSE_H + #define SUPPORT_FUSE_H +-- +2.43.5 + diff --git a/glibc-RHEL-50545-14.patch b/glibc-RHEL-50545-14.patch new file mode 100644 index 0000000..c2674d1 --- /dev/null +++ b/glibc-RHEL-50545-14.patch @@ -0,0 +1,24 @@ +From 3ef26b708725b528a1c69ab3eb523036c50b89d6 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Tue, 24 Sep 2024 13:05:48 +0200 +Subject: [PATCH] misc: Link tst-mkstemp-fuse-parallel with + $(shared-thread-library) +Content-type: text/plain; charset=UTF-8 + +The barrier functions require this on Hurd. +--- + misc/Makefile | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/misc/Makefile b/misc/Makefile +index 1422c95317..a932b1aab4 100644 +--- a/misc/Makefile ++++ b/misc/Makefile +@@ -178,3 +178,4 @@ $(objpfx)tst-select: $(librt) + $(objpfx)tst-select-time64: $(librt) + $(objpfx)tst-pselect: $(librt) + $(objpfx)tst-pselect-time64: $(librt) ++$(objpfx)tst-mkstemp-fuse-parallel: $(shared-thread-library) +-- +2.43.5 + diff --git a/glibc-RHEL-50545-2.patch b/glibc-RHEL-50545-2.patch new file mode 100644 index 0000000..b392625 --- /dev/null +++ b/glibc-RHEL-50545-2.patch @@ -0,0 +1,785 @@ +From 026a84a54d3b6c23b999b793e2a6f8ecd211e3b8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20B=C3=A9rat?= +Date: Thu, 1 Jun 2023 12:40:05 -0400 +Subject: [PATCH] tests: replace write by xwrite +Content-type: text/plain; charset=UTF-8 + +Using write without cheks leads to warn unused result when __wur is +enabled. + +Reviewed-by: Siddhesh Poyarekar +--- + dirent/tst-fdopendir.c | 4 +++- + io/tst-faccessat.c | 3 ++- + io/tst-fchmodat.c | 3 ++- + io/tst-fchownat.c | 3 ++- + io/tst-fstatat.c | 3 ++- + io/tst-futimesat.c | 3 ++- + io/tst-linkat.c | 3 ++- + io/tst-openat.c | 3 ++- + io/tst-renameat.c | 3 ++- + io/tst-symlinkat.c | 3 ++- + io/tst-unlinkat.c | 3 ++- + libio/bug-ungetc.c | 4 +++- + libio/bug-ungetc3.c | 4 +++- + libio/bug-ungetc4.c | 4 +++- + libio/bug-wfflush.c | 4 +++- + libio/bug-wsetpos.c | 4 +++- + nptl/tst-stackguard1.c | 4 +++- + nptl/tst-tls3.c | 2 ++ + nptl/tst-tls3mod.c | 5 +++-- + rt/tst-cpuclock2.c | 4 +++- + rt/tst-cputimer1.c | 4 +++- + rt/tst-cputimer2.c | 4 +++- + rt/tst-cputimer3.c | 4 +++- + support/test-container.c | 8 ++++---- + sysdeps/pthread/tst-cond18.c | 4 +++- + sysdeps/pthread/tst-flock1.c | 3 ++- + sysdeps/pthread/tst-flock2.c | 3 ++- + sysdeps/pthread/tst-key1.c | 11 ++++++----- + sysdeps/pthread/tst-signal1.c | 3 ++- + sysdeps/pthread/tst-signal2.c | 3 ++- + sysdeps/pthread/tst-timer.c | 3 ++- + time/tst-cpuclock1.c | 4 +++- + 32 files changed, 84 insertions(+), 39 deletions(-) + +diff --git a/dirent/tst-fdopendir.c b/dirent/tst-fdopendir.c +index 6321af1daa..2c9520574d 100644 +--- a/dirent/tst-fdopendir.c ++++ b/dirent/tst-fdopendir.c +@@ -7,6 +7,8 @@ + #include + #include + ++#include ++ + #ifndef O_NOATIME + # define O_NOATIME 0 + #endif +@@ -22,7 +24,7 @@ do_test (void) + return 1; + } + +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + close (fd); + + struct stat64 st; +diff --git a/io/tst-faccessat.c b/io/tst-faccessat.c +index 7bdeed008c..b90954e318 100644 +--- a/io/tst-faccessat.c ++++ b/io/tst-faccessat.c +@@ -8,6 +8,7 @@ + #include + #include + ++#include + + static void prepare (void); + #define PREPARE(argc, argv) prepare () +@@ -96,7 +97,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + puts ("file created"); + + /* Before closing the file, try using this file descriptor to open +diff --git a/io/tst-fchmodat.c b/io/tst-fchmodat.c +index 7d4a8717ff..83003e2f21 100644 +--- a/io/tst-fchmodat.c ++++ b/io/tst-fchmodat.c +@@ -8,6 +8,7 @@ + #include + #include + ++#include + + static void prepare (void); + #define PREPARE(argc, argv) prepare () +@@ -98,7 +99,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + puts ("file created"); + + struct stat64 st1; +diff --git a/io/tst-fchownat.c b/io/tst-fchownat.c +index e8adf6229f..c0b87cda8f 100644 +--- a/io/tst-fchownat.c ++++ b/io/tst-fchownat.c +@@ -6,6 +6,7 @@ + #include + #include + ++#include + + static void prepare (void); + #define PREPARE(argc, argv) prepare () +@@ -106,7 +107,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + puts ("file created"); + + struct stat64 st1; +diff --git a/io/tst-fstatat.c b/io/tst-fstatat.c +index 4766bb2e71..6a60024b63 100644 +--- a/io/tst-fstatat.c ++++ b/io/tst-fstatat.c +@@ -6,6 +6,7 @@ + #include + #include + ++#include + + static void prepare (void); + #define PREPARE(argc, argv) prepare () +@@ -94,7 +95,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + puts ("file created"); + + struct stat64 st1; +diff --git a/io/tst-futimesat.c b/io/tst-futimesat.c +index 3d41721f42..b7ef386e06 100644 +--- a/io/tst-futimesat.c ++++ b/io/tst-futimesat.c +@@ -28,6 +28,7 @@ + + #include + #include ++#include + + #ifndef struct_stat + # define struct_stat struct stat64 +@@ -114,7 +115,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + puts ("file created"); + + struct_stat st1; +diff --git a/io/tst-linkat.c b/io/tst-linkat.c +index 97445b7954..6b22a01c88 100644 +--- a/io/tst-linkat.c ++++ b/io/tst-linkat.c +@@ -6,6 +6,7 @@ + #include + #include + ++#include + + static void prepare (void); + #define PREPARE(argc, argv) prepare () +@@ -94,7 +95,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + puts ("file created"); + + struct stat64 st1; +diff --git a/io/tst-openat.c b/io/tst-openat.c +index 741b8d0ad2..2ce89e3db1 100644 +--- a/io/tst-openat.c ++++ b/io/tst-openat.c +@@ -6,6 +6,7 @@ + #include + #include + ++#include + + static void prepare (void); + #define PREPARE(argc, argv) prepare () +@@ -94,7 +95,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + + /* Before closing the file, try using this file descriptor to open + another file. This must fail. */ +diff --git a/io/tst-renameat.c b/io/tst-renameat.c +index 435302b52b..0b9da5fd6d 100644 +--- a/io/tst-renameat.c ++++ b/io/tst-renameat.c +@@ -6,6 +6,7 @@ + #include + #include + ++#include + + static void prepare (void); + #define PREPARE(argc, argv) prepare () +@@ -94,7 +95,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + puts ("file created"); + + struct stat64 st1; +diff --git a/io/tst-symlinkat.c b/io/tst-symlinkat.c +index 214a8e348e..4a34994df7 100644 +--- a/io/tst-symlinkat.c ++++ b/io/tst-symlinkat.c +@@ -6,6 +6,7 @@ + #include + #include + ++#include + + static void prepare (void); + #define PREPARE(argc, argv) prepare () +@@ -94,7 +95,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + puts ("file created"); + + struct stat64 st1; +diff --git a/io/tst-unlinkat.c b/io/tst-unlinkat.c +index e21d56f9f7..21a2dbaf57 100644 +--- a/io/tst-unlinkat.c ++++ b/io/tst-unlinkat.c +@@ -6,6 +6,7 @@ + #include + #include + ++#include + + static void prepare (void); + #define PREPARE(argc, argv) prepare () +@@ -94,7 +95,7 @@ do_test (void) + puts ("file creation failed"); + return 1; + } +- write (fd, "hello", 5); ++ xwrite (fd, "hello", 5); + close (fd); + puts ("file created"); + +diff --git a/libio/bug-ungetc.c b/libio/bug-ungetc.c +index 51940b68f5..4ea2d14ed6 100644 +--- a/libio/bug-ungetc.c ++++ b/libio/bug-ungetc.c +@@ -2,6 +2,8 @@ + + #include + ++#include ++ + static void do_prepare (void); + #define PREPARE(argc, argv) do_prepare () + static int do_test (void); +@@ -20,7 +22,7 @@ do_prepare (void) + printf ("cannot create temporary file: %m\n"); + exit (1); + } +- write (fd, pattern, sizeof (pattern)); ++ xwrite (fd, pattern, sizeof (pattern)); + close (fd); + } + +diff --git a/libio/bug-ungetc3.c b/libio/bug-ungetc3.c +index 0c83c1161e..6100d7a936 100644 +--- a/libio/bug-ungetc3.c ++++ b/libio/bug-ungetc3.c +@@ -2,6 +2,8 @@ + + #include + ++#include ++ + static void do_prepare (void); + #define PREPARE(argc, argv) do_prepare () + static int do_test (void); +@@ -20,7 +22,7 @@ do_prepare (void) + printf ("cannot create temporary file: %m\n"); + exit (1); + } +- write (fd, pattern, sizeof (pattern)); ++ xwrite (fd, pattern, sizeof (pattern)); + close (fd); + } + +diff --git a/libio/bug-ungetc4.c b/libio/bug-ungetc4.c +index 0bd02a570d..8a05def686 100644 +--- a/libio/bug-ungetc4.c ++++ b/libio/bug-ungetc4.c +@@ -19,6 +19,8 @@ + + #include + ++#include ++ + static void do_prepare (void); + #define PREPARE(argc, argv) do_prepare () + static int do_test (void); +@@ -37,7 +39,7 @@ do_prepare (void) + printf ("cannot create temporary file: %m\n"); + exit (1); + } +- write (fd, pattern, sizeof (pattern) - 1); ++ xwrite (fd, pattern, sizeof (pattern) - 1); + close (fd); + } + +diff --git a/libio/bug-wfflush.c b/libio/bug-wfflush.c +index a8fd61e997..d1b9d8e9de 100644 +--- a/libio/bug-wfflush.c ++++ b/libio/bug-wfflush.c +@@ -3,6 +3,8 @@ + #include + #include + ++#include ++ + static void do_prepare (void); + #define PREPARE(argc, argv) do_prepare () + static int do_test (void); +@@ -20,7 +22,7 @@ do_prepare (void) + printf ("cannot create temporary file: %m\n"); + exit (1); + } +- write (fd, "1!", 2); ++ xwrite (fd, "1!", 2); + close (fd); + } + +diff --git a/libio/bug-wsetpos.c b/libio/bug-wsetpos.c +index ccb22a4b62..0fc373ba49 100644 +--- a/libio/bug-wsetpos.c ++++ b/libio/bug-wsetpos.c +@@ -4,6 +4,8 @@ + #include + #include + ++#include ++ + static void do_prepare (void); + #define PREPARE(argc, argv) do_prepare () + static int do_test (void); +@@ -22,7 +24,7 @@ do_prepare (void) + printf ("cannot create temporary file: %m\n"); + exit (1); + } +- write (fd, pattern, sizeof (pattern)); ++ xwrite (fd, pattern, sizeof (pattern)); + close (fd); + } + +diff --git a/nptl/tst-stackguard1.c b/nptl/tst-stackguard1.c +index b9cf6844de..4ac57157e9 100644 +--- a/nptl/tst-stackguard1.c ++++ b/nptl/tst-stackguard1.c +@@ -28,6 +28,8 @@ + #include + #include + ++#include ++ + static const char *command; + static bool child; + static uintptr_t stack_chk_guard_copy; +@@ -97,7 +99,7 @@ do_test (void) + else if (ret != NULL) + return 1; + +- write (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy)); ++ xwrite (2, &stack_chk_guard_copy, sizeof (stack_chk_guard_copy)); + return 0; + } + +diff --git a/nptl/tst-tls3.c b/nptl/tst-tls3.c +index b1a40c624a..33d94c8cc5 100644 +--- a/nptl/tst-tls3.c ++++ b/nptl/tst-tls3.c +@@ -27,6 +27,8 @@ + #include + #include + ++#include ++ + #define THE_SIG SIGUSR1 + + /* The stack size can be overriden. With a sufficiently large stack +diff --git a/nptl/tst-tls3mod.c b/nptl/tst-tls3mod.c +index c6e8910b1e..345a48e1c7 100644 +--- a/nptl/tst-tls3mod.c ++++ b/nptl/tst-tls3mod.c +@@ -26,6 +26,7 @@ + #include + #include + ++#include + + extern pthread_barrier_t b; + +@@ -44,7 +45,7 @@ handler (int sig) + { + if (sig != THE_SIG) + { +- write (STDOUT_FILENO, "wrong signal\n", 13); ++ xwrite (STDOUT_FILENO, "wrong signal\n", 13); + _exit (1); + } + +@@ -52,7 +53,7 @@ handler (int sig) + + if (sem_post (&s) != 0) + { +- write (STDOUT_FILENO, "sem_post failed\n", 16); ++ xwrite (STDOUT_FILENO, "sem_post failed\n", 16); + _exit (1); + } + } +diff --git a/rt/tst-cpuclock2.c b/rt/tst-cpuclock2.c +index e4584d8791..8afd34ed9c 100644 +--- a/rt/tst-cpuclock2.c ++++ b/rt/tst-cpuclock2.c +@@ -37,6 +37,8 @@ do_test () + #include + #include + ++#include ++ + static pthread_barrier_t barrier; + + /* This function is intended to rack up both user and system time. */ +@@ -55,7 +57,7 @@ chew_cpu (void *arg) + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; +- write (nullfd, (char *) buf, sizeof buf); ++ xwrite (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + +diff --git a/rt/tst-cputimer1.c b/rt/tst-cputimer1.c +index 8f5dd76cf2..18d8b195a2 100644 +--- a/rt/tst-cputimer1.c ++++ b/rt/tst-cputimer1.c +@@ -11,6 +11,8 @@ + #include + #include + ++#include ++ + #define TEST_CLOCK CLOCK_PROCESS_CPUTIME_ID + #define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "process CPU clock timer support" : NULL) +@@ -29,7 +31,7 @@ chew_cpu (void *arg) + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; +- write (nullfd, (char *) buf, sizeof buf); ++ xwrite (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + +diff --git a/rt/tst-cputimer2.c b/rt/tst-cputimer2.c +index 397d7998c0..a5700d4bac 100644 +--- a/rt/tst-cputimer2.c ++++ b/rt/tst-cputimer2.c +@@ -12,6 +12,8 @@ + #include + #include + ++#include ++ + static clockid_t worker_thread_clock; + + #define TEST_CLOCK worker_thread_clock +@@ -32,7 +34,7 @@ chew_cpu (void *arg) + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; +- write (nullfd, (char *) buf, sizeof buf); ++ xwrite (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + +diff --git a/rt/tst-cputimer3.c b/rt/tst-cputimer3.c +index 056766a377..786de93a02 100644 +--- a/rt/tst-cputimer3.c ++++ b/rt/tst-cputimer3.c +@@ -13,6 +13,8 @@ + #include + #include + ++#include ++ + static clockid_t child_clock; + + #define TEST_CLOCK child_clock +@@ -33,7 +35,7 @@ chew_cpu (void) + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; +- write (nullfd, (char *) buf, sizeof buf); ++ xwrite (nullfd, (char *) buf, sizeof buf); + close (nullfd); + if (getppid () == 1) + _exit (2); +diff --git a/support/test-container.c b/support/test-container.c +index e68f16eecf..d4ca41fe7c 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -1177,7 +1177,7 @@ main (int argc, char **argv) + int status; + + /* Send the child's "outside" pid to it. */ +- write (pipes[1], &child, sizeof(child)); ++ xwrite (pipes[1], &child, sizeof(child)); + close (pipes[0]); + close (pipes[1]); + +@@ -1246,7 +1246,7 @@ main (int argc, char **argv) + + sprintf (tmp, "%lld %lld 1\n", + (long long) (be_su ? 0 : original_uid), (long long) original_uid); +- write (UMAP, tmp, strlen (tmp)); ++ xwrite (UMAP, tmp, strlen (tmp)); + xclose (UMAP); + + /* We must disable setgroups () before we can map our groups, else we +@@ -1255,7 +1255,7 @@ main (int argc, char **argv) + if (GMAP >= 0) + { + /* We support kernels old enough to not have this. */ +- write (GMAP, "deny\n", 5); ++ xwrite (GMAP, "deny\n", 5); + xclose (GMAP); + } + +@@ -1267,7 +1267,7 @@ main (int argc, char **argv) + + sprintf (tmp, "%lld %lld 1\n", + (long long) (be_su ? 0 : original_gid), (long long) original_gid); +- write (GMAP, tmp, strlen (tmp)); ++ xwrite (GMAP, tmp, strlen (tmp)); + xclose (GMAP); + } + +diff --git a/sysdeps/pthread/tst-cond18.c b/sysdeps/pthread/tst-cond18.c +index edac4fa4ff..ffae356c04 100644 +--- a/sysdeps/pthread/tst-cond18.c ++++ b/sysdeps/pthread/tst-cond18.c +@@ -25,6 +25,8 @@ + #include + #include + ++#include ++ + pthread_cond_t cv = PTHREAD_COND_INITIALIZER; + pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + bool exiting; +@@ -41,7 +43,7 @@ tf (void *id) + while (!exiting) + { + if ((spins++ % 1000) == 0) +- write (fd, ".", 1); ++ xwrite (fd, ".", 1); + pthread_mutex_unlock (&lock); + + pthread_mutex_lock (&lock); +diff --git a/sysdeps/pthread/tst-flock1.c b/sysdeps/pthread/tst-flock1.c +index 7eef9070ab..9de148afd3 100644 +--- a/sysdeps/pthread/tst-flock1.c ++++ b/sysdeps/pthread/tst-flock1.c +@@ -22,6 +22,7 @@ + #include + #include + ++#include + + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +@@ -57,7 +58,7 @@ do_test (void) + + unlink (tmp); + +- write (fd, "foobar xyzzy", 12); ++ xwrite (fd, "foobar xyzzy", 12); + + if (flock (fd, LOCK_EX | LOCK_NB) != 0) + { +diff --git a/sysdeps/pthread/tst-flock2.c b/sysdeps/pthread/tst-flock2.c +index 8762e93b52..952b79e5db 100644 +--- a/sysdeps/pthread/tst-flock2.c ++++ b/sysdeps/pthread/tst-flock2.c +@@ -25,6 +25,7 @@ + #include + #include + ++#include + + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + static pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER; +@@ -71,7 +72,7 @@ do_test (void) + + int i; + for (i = 0; i < 20; ++i) +- write (fd, "foobar xyzzy", 12); ++ xwrite (fd, "foobar xyzzy", 12); + + pthread_barrier_t *b; + b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, +diff --git a/sysdeps/pthread/tst-key1.c b/sysdeps/pthread/tst-key1.c +index 933edafef8..60245c4e47 100644 +--- a/sysdeps/pthread/tst-key1.c ++++ b/sysdeps/pthread/tst-key1.c +@@ -22,6 +22,7 @@ + #include + #include + ++#include + + static int do_test (void); + +@@ -52,7 +53,7 @@ do_test (void) + + if (pthread_setspecific (keys[i], (const void *) (i + 100l)) != 0) + { +- write (2, "setspecific failed\n", 19); ++ xwrite (2, "setspecific failed\n", 19); + _exit (1); + } + } +@@ -61,13 +62,13 @@ do_test (void) + { + if (pthread_getspecific (keys[i]) != (void *) (i + 100l)) + { +- write (2, "getspecific failed\n", 19); ++ xwrite (2, "getspecific failed\n", 19); + _exit (1); + } + + if (pthread_key_delete (keys[i]) != 0) + { +- write (2, "key_delete failed\n", 18); ++ xwrite (2, "key_delete failed\n", 18); + _exit (1); + } + } +@@ -75,13 +76,13 @@ do_test (void) + /* Now it must be once again possible to allocate keys. */ + if (pthread_key_create (&keys[0], NULL) != 0) + { +- write (2, "2nd key_create failed\n", 22); ++ xwrite (2, "2nd key_create failed\n", 22); + _exit (1); + } + + if (pthread_key_delete (keys[0]) != 0) + { +- write (2, "2nd key_delete failed\n", 22); ++ xwrite (2, "2nd key_delete failed\n", 22); + _exit (1); + } + +diff --git a/sysdeps/pthread/tst-signal1.c b/sysdeps/pthread/tst-signal1.c +index d1073e8459..d1082027ca 100644 +--- a/sysdeps/pthread/tst-signal1.c ++++ b/sysdeps/pthread/tst-signal1.c +@@ -26,6 +26,7 @@ + #include + #include + ++#include + + static sigset_t ss; + static pthread_barrier_t *b; +@@ -106,7 +107,7 @@ do_test (void) + + int i; + for (i = 0; i < 20; ++i) +- write (fd, "foobar xyzzy", 12); ++ xwrite (fd, "foobar xyzzy", 12); + + b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); +diff --git a/sysdeps/pthread/tst-signal2.c b/sysdeps/pthread/tst-signal2.c +index dfe7d9f64a..15b7747877 100644 +--- a/sysdeps/pthread/tst-signal2.c ++++ b/sysdeps/pthread/tst-signal2.c +@@ -26,6 +26,7 @@ + #include + #include + ++#include + + static sigset_t ss; + static pthread_barrier_t *b; +@@ -112,7 +113,7 @@ do_test (void) + + int i; + for (i = 0; i < 20; ++i) +- write (fd, "foobar xyzzy", 12); ++ xwrite (fd, "foobar xyzzy", 12); + + b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); +diff --git a/sysdeps/pthread/tst-timer.c b/sysdeps/pthread/tst-timer.c +index 47472ab8e1..4cfe0b67dc 100644 +--- a/sysdeps/pthread/tst-timer.c ++++ b/sysdeps/pthread/tst-timer.c +@@ -25,6 +25,7 @@ + #include + #include + ++#include + + static void + notify_func1 (union sigval sigval) +@@ -45,7 +46,7 @@ signal_func (int sig) + { + static const char text[] = "signal_func\n"; + signal (sig, signal_func); +- write (STDOUT_FILENO, text, sizeof text - 1); ++ xwrite (STDOUT_FILENO, text, sizeof text - 1); + } + + static void +diff --git a/time/tst-cpuclock1.c b/time/tst-cpuclock1.c +index 6f2e70a58a..6a793e06df 100644 +--- a/time/tst-cpuclock1.c ++++ b/time/tst-cpuclock1.c +@@ -27,6 +27,8 @@ + #include + #include + ++#include ++ + /* This function is intended to rack up both user and system time. */ + static void + chew_cpu (void) +@@ -41,7 +43,7 @@ chew_cpu (void) + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; +- write (nullfd, (char *) buf, sizeof buf); ++ xwrite (nullfd, (char *) buf, sizeof buf); + close (nullfd); + if (getppid () == 1) + _exit (2); +-- +2.43.5 + diff --git a/glibc-RHEL-50545-3.patch b/glibc-RHEL-50545-3.patch new file mode 100644 index 0000000..076b7f7 --- /dev/null +++ b/glibc-RHEL-50545-3.patch @@ -0,0 +1,30 @@ +From 34bb581e7713589d38c797c214f4c6bf2b14b702 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 16 Aug 2024 16:05:19 +0200 +Subject: [PATCH] support: Include for strcmp in + support_format_addrinfo.c +Content-type: text/plain; charset=UTF-8 + +This is currently implied by the internal headers, but it makes +sense not to rely on this. + +Reviewed-by: Adhemerval Zanella +--- + support/support_format_addrinfo.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c +index cbc72910a9..77f4db345c 100644 +--- a/support/support_format_addrinfo.c ++++ b/support/support_format_addrinfo.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + +-- +2.43.5 + diff --git a/glibc-RHEL-50545-4.patch b/glibc-RHEL-50545-4.patch new file mode 100644 index 0000000..612e0ec --- /dev/null +++ b/glibc-RHEL-50545-4.patch @@ -0,0 +1,91 @@ +From 921690512946d73bf66a8c495baff31316e4489f Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 16 Aug 2024 16:05:19 +0200 +Subject: [PATCH] support: Add the xstatx function +Content-type: text/plain; charset=UTF-8 + +Reviewed-by: Adhemerval Zanella + +Conflict: + support/Makefile + context +--- + support/Makefile | 1 + + support/xstatx.c | 32 ++++++++++++++++++++++++++++++++ + support/xunistd.h | 2 ++ + 3 files changed, 35 insertions(+) + create mode 100644 support/xstatx.c + +diff --git a/support/Makefile b/support/Makefile +index aa57207bdc..5b1c96a49e 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -200,6 +200,7 @@ libsupport-routines = \ + xsignal \ + xsigstack \ + xsocket \ ++ xstatx \ + xposix_spawn \ + xposix_spawn_file_actions_addclose \ + xposix_spawn_file_actions_adddup2 \ +diff --git a/support/xstatx.c b/support/xstatx.c +new file mode 100644 +index 0000000000..621f2440f8 +--- /dev/null ++++ b/support/xstatx.c +@@ -0,0 +1,32 @@ ++/* Error-checking wrapper for statx. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++ ++void ++xstatx (int fd, const char *path, int flags, unsigned int mask, ++ struct statx *stx) ++{ ++ if (statx (fd, path, flags, mask, stx) != 0) ++ FAIL_EXIT1 ("statx (AT_FDCWD, \"%s\", 0x%x, 0x%x): %m", ++ path, (unsigned int) flags, mask); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index 13be9a46a3..cc74c4fad0 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -30,6 +30,7 @@ + __BEGIN_DECLS + + struct stat64; ++struct statx; + + pid_t xfork (void); + pid_t xwaitpid (pid_t, int *status, int flags); +@@ -51,6 +52,7 @@ void __REDIRECT (xstat, (const char *path, struct stat *), xstat_time64); + void __REDIRECT (xlstat, (const char *path, struct stat *), xlstat_time64); + void __REDIRECT (xfstat, (int fd, struct stat *), xfstat_time64); + #endif ++void xstatx (int, const char *, int, unsigned int, struct statx *); + void xmkdir (const char *path, mode_t); + void xchroot (const char *path); + void xunlink (const char *path); +-- +2.43.5 + diff --git a/glibc-RHEL-50545-5.patch b/glibc-RHEL-50545-5.patch new file mode 100644 index 0000000..b1b9e6a --- /dev/null +++ b/glibc-RHEL-50545-5.patch @@ -0,0 +1,410 @@ +From bf2927484152e12996af60ea439cf94b66fcd81d Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 16 Aug 2024 16:05:20 +0200 +Subject: [PATCH] io: Use struct statx and xstatx in tests +Content-type: text/plain; charset=UTF-8 + +This avoids the need to define struct_statx to an appropriate +struct stat type variant because struct statx does not change +based on time/file offset flags. + +Reviewed-by: Adhemerval Zanella +--- + io/tst-futimens-time64.c | 1 - + io/tst-futimens.c | 13 +++++-------- + io/tst-futimes-time64.c | 1 - + io/tst-futimes.c | 13 +++++-------- + io/tst-futimesat-time64.c | 3 --- + io/tst-futimesat.c | 30 ++++++++---------------------- + io/tst-lutimes-time64.c | 1 - + io/tst-lutimes.c | 26 ++++++++++++-------------- + io/tst-utime-time64.c | 1 - + io/tst-utime.c | 13 +++++-------- + io/tst-utimensat-time64.c | 1 - + io/tst-utimensat.c | 35 +++++++++++++++++------------------ + io/tst-utimes-time64.c | 1 - + io/tst-utimes.c | 13 +++++-------- + 14 files changed, 57 insertions(+), 95 deletions(-) + +diff --git a/io/tst-futimens-time64.c b/io/tst-futimens-time64.c +index 88fcb38489..71204a6166 100644 +--- a/io/tst-futimens-time64.c ++++ b/io/tst-futimens-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-futimens.c" +diff --git a/io/tst-futimens.c b/io/tst-futimens.c +index 6204befedd..075ca42b93 100644 +--- a/io/tst-futimens.c ++++ b/io/tst-futimens.c +@@ -18,26 +18,23 @@ + + #include + #include ++#include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_futimens_helper (const char *file, int fd, const struct timespec *ts) + { + int result = futimens (fd, ts); + TEST_VERIFY_EXIT (result == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for atime match */ +- TEST_COMPARE (st.st_atime, ts[0].tv_sec); ++ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec); + + /* Check if seconds for mtime match */ +- TEST_COMPARE (st.st_mtime, ts[1].tv_sec); ++ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec); + + return 0; + } +diff --git a/io/tst-futimes-time64.c b/io/tst-futimes-time64.c +index d489c265d1..eeb4bed7c4 100644 +--- a/io/tst-futimes-time64.c ++++ b/io/tst-futimes-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-futimes.c" +diff --git a/io/tst-futimes.c b/io/tst-futimes.c +index d21acf6a24..612fe460cf 100644 +--- a/io/tst-futimes.c ++++ b/io/tst-futimes.c +@@ -18,27 +18,24 @@ + + #include + #include ++#include + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_futimens_helper (const char *file, int fd, const struct timeval *tv) + { + int r = futimes (fd, tv); + TEST_VERIFY_EXIT (r == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for atime match */ +- TEST_COMPARE (st.st_atime, tv[0].tv_sec); ++ TEST_COMPARE (st.stx_atime.tv_sec, tv[0].tv_sec); + + /* Check if seconds for mtime match */ +- TEST_COMPARE (st.st_mtime, tv[1].tv_sec); ++ TEST_COMPARE (st.stx_mtime.tv_sec, tv[1].tv_sec); + + return 0; + } +diff --git a/io/tst-futimesat-time64.c b/io/tst-futimesat-time64.c +index f6c0500eef..1585317579 100644 +--- a/io/tst-futimesat-time64.c ++++ b/io/tst-futimesat-time64.c +@@ -1,4 +1 @@ +-#define struct_stat struct stat +-#define fstat fstat +-#define fstatat fstatat + #include "io/tst-futimesat.c" +diff --git a/io/tst-futimesat.c b/io/tst-futimesat.c +index 67a8551beb..feae4e7aa7 100644 +--- a/io/tst-futimesat.c ++++ b/io/tst-futimesat.c +@@ -30,12 +30,6 @@ + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-# define fstat fstat64 +-# define fstatat fstatat64 +-#endif +- + static int dir_fd; + + static void +@@ -118,19 +112,15 @@ do_test (void) + xwrite (fd, "hello", 5); + puts ("file created"); + +- struct_stat st1; +- if (fstat (fd, &st1) != 0) +- { +- puts ("fstat64 failed"); +- return 1; +- } ++ struct statx st1; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st1); + + close (fd); + + struct timeval tv[2]; +- tv[0].tv_sec = st1.st_atime + 1; ++ tv[0].tv_sec = st1.stx_atime.tv_sec + 1; + tv[0].tv_usec = 0; +- tv[1].tv_sec = st1.st_mtime + 1; ++ tv[1].tv_sec = st1.stx_mtime.tv_sec + 1; + tv[1].tv_usec = 0; + if (futimesat (dir_fd, "some-file", tv) != 0) + { +@@ -138,16 +128,12 @@ do_test (void) + return 1; + } + +- struct_stat st2; +- if (fstatat (dir_fd, "some-file", &st2, 0) != 0) +- { +- puts ("fstatat64 failed"); +- return 1; +- } ++ struct statx st2; ++ xstatx (dir_fd, "some-file", 0, STATX_BASIC_STATS, &st2); + +- if (st2.st_mtime != tv[1].tv_sec ++ if (st2.stx_mtime.tv_sec != tv[1].tv_sec + #ifdef _STATBUF_ST_NSEC +- || st2.st_mtim.tv_nsec != 0 ++ || st2.stx_mtime.tv_nsec != 0 + #endif + ) + { +diff --git a/io/tst-lutimes-time64.c b/io/tst-lutimes-time64.c +index 06caec0a91..c5bea965da 100644 +--- a/io/tst-lutimes-time64.c ++++ b/io/tst-lutimes-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-lutimes.c" +diff --git a/io/tst-lutimes.c b/io/tst-lutimes.c +index edef5ab90e..78bcc58291 100644 +--- a/io/tst-lutimes.c ++++ b/io/tst-lutimes.c +@@ -18,34 +18,32 @@ + + #include + #include ++#include + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_lutimes_helper (const char *testfile, int fd, const char *testlink, + const struct timeval *tv) + { +- struct_stat stfile_orig; +- xlstat (testfile, &stfile_orig); ++ struct statx stfile_orig; ++ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, ++ &stfile_orig); + + TEST_VERIFY_EXIT (lutimes (testlink, tv) == 0); + +- struct_stat stlink; +- xlstat (testlink, &stlink); ++ struct statx stlink; ++ xstatx (AT_FDCWD, testlink, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, &stlink); + +- TEST_COMPARE (stlink.st_atime, tv[0].tv_sec); +- TEST_COMPARE (stlink.st_mtime, tv[1].tv_sec); ++ TEST_COMPARE (stlink.stx_atime.tv_sec, tv[0].tv_sec); ++ TEST_COMPARE (stlink.stx_mtime.tv_sec, tv[1].tv_sec); + + /* Check if the timestamp from original file is not changed. */ +- struct_stat stfile; +- xlstat (testfile, &stfile); ++ struct statx stfile; ++ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, &stfile); + +- TEST_COMPARE (stfile_orig.st_atime, stfile.st_atime); +- TEST_COMPARE (stfile_orig.st_mtime, stfile.st_mtime); ++ TEST_COMPARE (stfile_orig.stx_atime.tv_sec, stfile.stx_atime.tv_sec); ++ TEST_COMPARE (stfile_orig.stx_mtime.tv_sec, stfile.stx_mtime.tv_sec); + + return 0; + } +diff --git a/io/tst-utime-time64.c b/io/tst-utime-time64.c +index eb62f59126..8894592a15 100644 +--- a/io/tst-utime-time64.c ++++ b/io/tst-utime-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-utime.c" +diff --git a/io/tst-utime.c b/io/tst-utime.c +index e2e6dcd04c..f329358289 100644 +--- a/io/tst-utime.c ++++ b/io/tst-utime.c +@@ -19,26 +19,23 @@ + #include + #include + #include ++#include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_utime_helper (const char *file, int fd, const struct utimbuf *ut) + { + int result = utime (file, ut); + TEST_VERIFY_EXIT (result == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for actime match */ +- TEST_COMPARE (st.st_atime, ut->actime); ++ TEST_COMPARE (st.stx_atime.tv_sec, ut->actime); + + /* Check if seconds for modtime match */ +- TEST_COMPARE (st.st_mtime, ut->modtime); ++ TEST_COMPARE (st.stx_mtime.tv_sec, ut->modtime); + + return 0; + } +diff --git a/io/tst-utimensat-time64.c b/io/tst-utimensat-time64.c +index 7ac7d8df1d..5d60fce881 100644 +--- a/io/tst-utimensat-time64.c ++++ b/io/tst-utimensat-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-utimensat.c" +diff --git a/io/tst-utimensat.c b/io/tst-utimensat.c +index 3d9a72c471..2a756d7b07 100644 +--- a/io/tst-utimensat.c ++++ b/io/tst-utimensat.c +@@ -22,10 +22,6 @@ + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_utimesat_helper (const char *testfile, int fd, const char *testlink, + const struct timespec *ts) +@@ -33,35 +29,38 @@ test_utimesat_helper (const char *testfile, int fd, const char *testlink, + { + TEST_VERIFY_EXIT (utimensat (fd, testfile, ts, 0) == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for atime match */ +- TEST_COMPARE (st.st_atime, ts[0].tv_sec); ++ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec); + + /* Check if seconds for mtime match */ +- TEST_COMPARE (st.st_mtime, ts[1].tv_sec); ++ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec); + } + + { +- struct_stat stfile_orig; +- xlstat (testfile, &stfile_orig); ++ struct statx stfile_orig; ++ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, ++ &stfile_orig); + + TEST_VERIFY_EXIT (utimensat (0 /* ignored */, testlink, ts, + AT_SYMLINK_NOFOLLOW) + == 0); +- struct_stat stlink; +- xlstat (testlink, &stlink); ++ struct statx stlink; ++ xstatx (AT_FDCWD, testlink, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, ++ &stlink); + +- TEST_COMPARE (stlink.st_atime, ts[0].tv_sec); +- TEST_COMPARE (stlink.st_mtime, ts[1].tv_sec); ++ TEST_COMPARE (stlink.stx_atime.tv_sec, ts[0].tv_sec); ++ TEST_COMPARE (stlink.stx_mtime.tv_sec, ts[1].tv_sec); + + /* Check if the timestamp from original file is not changed. */ +- struct_stat stfile; +- xlstat (testfile, &stfile); ++ struct statx stfile; ++ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, ++ &stfile); + +- TEST_COMPARE (stfile_orig.st_atime, stfile.st_atime); +- TEST_COMPARE (stfile_orig.st_mtime, stfile.st_mtime); ++ TEST_COMPARE (stfile_orig.stx_atime.tv_sec, stfile.stx_atime.tv_sec); ++ TEST_COMPARE (stfile_orig.stx_mtime.tv_sec, stfile.stx_mtime.tv_sec); + } + + return 0; +diff --git a/io/tst-utimes-time64.c b/io/tst-utimes-time64.c +index 234ec02541..026ef5f78d 100644 +--- a/io/tst-utimes-time64.c ++++ b/io/tst-utimes-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-utimes.c" +diff --git a/io/tst-utimes.c b/io/tst-utimes.c +index 8edcfabebf..6cd436c5a0 100644 +--- a/io/tst-utimes.c ++++ b/io/tst-utimes.c +@@ -18,28 +18,25 @@ + + #include + #include ++#include + #include + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_utimes_helper (const char *file, int fd, const struct timeval *tv) + { + int result = utimes (file, tv); + TEST_VERIFY_EXIT (result == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for atime match */ +- TEST_COMPARE (st.st_atime, tv[0].tv_sec); ++ TEST_COMPARE (st.stx_atime.tv_sec, tv[0].tv_sec); + + /* Check if seconds for mtime match */ +- TEST_COMPARE (st.st_mtime, tv[1].tv_sec); ++ TEST_COMPARE (st.stx_mtime.tv_sec, tv[1].tv_sec); + + return 0; + } +-- +2.43.5 + diff --git a/glibc-RHEL-50545-6.patch b/glibc-RHEL-50545-6.patch new file mode 100644 index 0000000..ea404be --- /dev/null +++ b/glibc-RHEL-50545-6.patch @@ -0,0 +1,452 @@ +From e7c14e542d8d858b824b5df4f4e3dc93695e6171 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 16 Aug 2024 16:05:20 +0200 +Subject: [PATCH] support: Use macros for *stat wrappers +Content-type: text/plain; charset=UTF-8 + +Macros will automatically use the correct types, without +having to fiddle with internal glibc macros. It's also +impossible to get the types wrong due to aliasing because +support_check_stat_fd and support_check_stat_path do not +depend on the struct stat* types. + +The changes reveal some inconsistencies in tests. + +Reviewed-by: Adhemerval Zanella + +Conflicts + locale/tst-localedef-path-norm.c + context + support/Makefile + context + support/xunistd.h + context + all + copyright years +--- + elf/tst-ldconfig-bad-aux-cache.c | 2 +- + io/tst-copy_file_range.c | 2 +- + io/tst-statx.c | 4 +-- + locale/tst-localedef-path-norm.c | 2 +- + localedata/tst-localedef-hardlinks.c | 2 +- + posix/tst-execveat.c | 2 +- + stdio-common/tst-renameat2.c | 2 +- + stdlib/tst-system.c | 2 +- + support/Makefile | 8 ++--- + support/support-xfstat-time64.c | 32 ------------------- + support/support-xstat-time64.c | 32 ------------------- + support/support-xstat.c | 30 ----------------- + support/{xlstat.c => support_check_stat_fd.c} | 11 +++---- + ...ort-xfstat.c => support_check_stat_path.c} | 9 +++--- + support/xlstat-time64.c | 32 ------------------- + support/xunistd.h | 30 ++++++++--------- + 16 files changed, 34 insertions(+), 168 deletions(-) + delete mode 100644 support/support-xfstat-time64.c + delete mode 100644 support/support-xstat-time64.c + delete mode 100644 support/support-xstat.c + rename support/{xlstat.c => support_check_stat_fd.c} (76%) + rename support/{support-xfstat.c => support_check_stat_path.c} (81%) + delete mode 100644 support/xlstat-time64.c + +diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c +index 7f1fbb5252..8c2e62ecc2 100644 +--- a/elf/tst-ldconfig-bad-aux-cache.c ++++ b/elf/tst-ldconfig-bad-aux-cache.c +@@ -85,7 +85,7 @@ do_test (void) + support_capture_subprocess_check (&result, "execv", 0, sc_allow_none); + support_capture_subprocess_free (&result); + +- xstat (path, &fs); ++ xstat64 (path, &fs); + + size = fs.st_size; + /* Run 3 tests, each truncating aux-cache shorter and shorter. */ +diff --git a/io/tst-copy_file_range.c b/io/tst-copy_file_range.c +index 9837b7c339..3d7b0aa901 100644 +--- a/io/tst-copy_file_range.c ++++ b/io/tst-copy_file_range.c +@@ -117,7 +117,7 @@ simple_file_copy (void) + TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 6 + length); + + struct stat64 st; +- xfstat (outfd, &st); ++ xfstat64 (outfd, &st); + if (length > 0) + TEST_COMPARE (st.st_size, out_skipped + length); + else +diff --git a/io/tst-statx.c b/io/tst-statx.c +index d84568859e..685924ae76 100644 +--- a/io/tst-statx.c ++++ b/io/tst-statx.c +@@ -78,7 +78,7 @@ both_implementations_tests (statx_function impl, const char *path, int fd) + struct statx stx = { 0, }; + TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &stx), 0); + struct stat64 st; +- xfstat (fd, &st); ++ xfstat64 (fd, &st); + TEST_COMPARE (stx.stx_mode, st.st_mode); + TEST_COMPARE (stx.stx_dev_major, major (st.st_dev)); + TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev)); +@@ -88,7 +88,7 @@ both_implementations_tests (statx_function impl, const char *path, int fd) + TEST_COMPARE (statx (AT_FDCWD, "/dev/null", 0, STATX_BASIC_STATS, &stx), + 0); + struct stat64 st; +- xstat ("/dev/null", &st); ++ xstat64 ("/dev/null", &st); + TEST_COMPARE (stx.stx_mode, st.st_mode); + TEST_COMPARE (stx.stx_dev_major, major (st.st_dev)); + TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev)); +diff --git a/locale/tst-localedef-path-norm.c b/locale/tst-localedef-path-norm.c +index ffe8cbd467..f592b9a960 100644 +--- a/locale/tst-localedef-path-norm.c ++++ b/locale/tst-localedef-path-norm.c +@@ -81,7 +81,7 @@ run_test (struct test_closure data) + support_capture_subprocess_free (&result); + + /* Verify path is present and is a directory. */ +- xstat (path, &fs); ++ xstat64 (path, &fs); + TEST_VERIFY_EXIT (S_ISDIR (fs.st_mode)); + printf ("info: Directory '%s' exists.\n", path); + } +diff --git a/localedata/tst-localedef-hardlinks.c b/localedata/tst-localedef-hardlinks.c +index e88215a150..23927b462f 100644 +--- a/localedata/tst-localedef-hardlinks.c ++++ b/localedata/tst-localedef-hardlinks.c +@@ -62,7 +62,7 @@ check_link (struct test_data step) + char *output; + + output = xasprintf ("%s/%s", support_complocaledir_prefix, step.output); +- xstat (output, &locale); ++ xstat64 (output, &locale); + free (output); + TEST_COMPARE (locale.st_nlink, step.st_nlink); + } +diff --git a/posix/tst-execveat.c b/posix/tst-execveat.c +index 4565d6b19f..dde034a9f1 100644 +--- a/posix/tst-execveat.c ++++ b/posix/tst-execveat.c +@@ -155,7 +155,7 @@ do_test (void) + tmp_sh = xasprintf ("%s/tmp_sh", tmp_dir); + add_temp_file (tmp_sh); + fd_out = xopen (symlink_name, O_CREAT | O_WRONLY, 0); +- xstat ("/bin/sh", &st); ++ xstat64 ("/bin/sh", &st); + fd = xopen ("/bin/sh", O_RDONLY, 0); + xcopy_file_range (fd, 0, fd_out, 0, st.st_size, 0); + xfchmod (fd_out, 0700); +diff --git a/stdio-common/tst-renameat2.c b/stdio-common/tst-renameat2.c +index b65afed75e..7f4345f716 100644 +--- a/stdio-common/tst-renameat2.c ++++ b/stdio-common/tst-renameat2.c +@@ -82,7 +82,7 @@ static void + check_size (const char *path, off64_t expected_size) + { + struct stat64 st; +- xstat (path, &st); ++ xstat64 (path, &st); + if (st.st_size != expected_size) + FAIL_EXIT1 ("file \"%s\": expected size %lld, actual size %lld", + path, (unsigned long long int) expected_size, +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index 47c742f963..b5b630a41b 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -156,7 +156,7 @@ do_test (void) + + { + struct stat64 st; +- xstat (_PATH_BSHELL, &st); ++ xstat64 (_PATH_BSHELL, &st); + mode_t mode = st.st_mode; + xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH)); + +diff --git a/support/Makefile b/support/Makefile +index 5b1c96a49e..6e3c55394f 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -42,14 +42,12 @@ libsupport-routines = \ + resolv_test \ + set_fortify_handler \ + support_stack_alloc \ +- support-xfstat \ +- support-xfstat-time64 \ +- support-xstat \ +- support-xstat-time64 \ + support_become_root \ + support_can_chroot \ + support_capture_subprocess \ + support_capture_subprocess_check \ ++ support_check_stat_fd \ ++ support_check_stat_path \ + support_chroot \ + support_copy_file \ + support_copy_file_range \ +@@ -130,8 +128,6 @@ libsupport-routines = \ + xgetsockname \ + xlisten \ + xlseek \ +- xlstat \ +- xlstat-time64 \ + xmalloc \ + xmemstream \ + xmkdir \ +diff --git a/support/support-xfstat-time64.c b/support/support-xfstat-time64.c +deleted file mode 100644 +index 589a69bb3e..0000000000 +--- a/support/support-xfstat-time64.c ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* 64-bit time_t stat with error checking. +- Copyright (C) 2021 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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-#if __TIMESIZE != 64 +-void +-xfstat_time64 (int fd, struct __stat64_t64 *result) +-{ +- if (__fstat64_time64 (fd, result) != 0) +- FAIL_EXIT1 ("__fstat64_time64 (%d): %m", fd); +-} +-#endif +diff --git a/support/support-xstat-time64.c b/support/support-xstat-time64.c +deleted file mode 100644 +index 451948734a..0000000000 +--- a/support/support-xstat-time64.c ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* 64-bit time_t stat with error checking. +- Copyright (C) 2021 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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-#if __TIMESIZE != 64 +-void +-xstat_time64 (const char *path, struct __stat64_t64 *result) +-{ +- if (__stat64_time64 (path, result) != 0) +- FAIL_EXIT1 ("__stat64_time64 (\"%s\"): %m", path); +-} +-#endif +diff --git a/support/support-xstat.c b/support/support-xstat.c +deleted file mode 100644 +index ce866f74d2..0000000000 +--- a/support/support-xstat.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* stat64 with error checking. +- Copyright (C) 2017-2021 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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-void +-xstat (const char *path, struct stat64 *result) +-{ +- if (stat64 (path, result) != 0) +- FAIL_EXIT1 ("stat64 (\"%s\"): %m", path); +-} +diff --git a/support/xlstat.c b/support/support_check_stat_fd.c +similarity index 76% +rename from support/xlstat.c +rename to support/support_check_stat_fd.c +index 87df988879..4c12adf6b7 100644 +--- a/support/xlstat.c ++++ b/support/support_check_stat_fd.c +@@ -1,5 +1,5 @@ +-/* lstat64 with error checking. +- Copyright (C) 2017-2021 Free Software Foundation, Inc. ++/* Error checking for descriptor-based stat functions. ++ Copyright (C) 2024 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 +@@ -18,11 +18,10 @@ + + #include + #include +-#include + + void +-xlstat (const char *path, struct stat64 *result) ++support_check_stat_fd (const char *name, int fd, int result) + { +- if (lstat64 (path, result) != 0) +- FAIL_EXIT1 ("lstat64 (\"%s\"): %m", path); ++ if (result != 0) ++ FAIL_EXIT1 ("%s (%d): %m", name, fd); + } +diff --git a/support/support-xfstat.c b/support/support_check_stat_path.c +similarity index 81% +rename from support/support-xfstat.c +rename to support/support_check_stat_path.c +index ab4b01c97d..3cf72afe59 100644 +--- a/support/support-xfstat.c ++++ b/support/support_check_stat_path.c +@@ -1,4 +1,4 @@ +-/* fstat64 with error checking. ++/* Error checking for path-based stat functions. + Copyright (C) 2017-2021 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -18,11 +18,10 @@ + + #include + #include +-#include + + void +-xfstat (int fd, struct stat64 *result) ++support_check_stat_path (const char *name, const char *path, int result) + { +- if (fstat64 (fd, result) != 0) +- FAIL_EXIT1 ("fstat64 (%d): %m", fd); ++ if (result != 0) ++ FAIL_EXIT1 ("%s (\"%s\"): %m", name, path); + } +diff --git a/support/xlstat-time64.c b/support/xlstat-time64.c +deleted file mode 100644 +index 2bc3ca6593..0000000000 +--- a/support/xlstat-time64.c ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* 64-bit time_t stat with error checking. +- Copyright (C) 2021 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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-#if __TIMESIZE != 64 +-void +-xlstat_time64 (const char *path, struct __stat64_t64 *result) +-{ +- if (__lstat64_time64 (path, result) != 0) +- FAIL_EXIT1 ("__lstat64_time64 (\"%s\"): %m", path); +-} +-#endif +diff --git a/support/xunistd.h b/support/xunistd.h +index cc74c4fad0..204951bce7 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -29,7 +29,6 @@ + + __BEGIN_DECLS + +-struct stat64; + struct statx; + + pid_t xfork (void); +@@ -37,21 +36,20 @@ pid_t xwaitpid (pid_t, int *status, int + void xpipe (int[2]); + void xdup2 (int, int); + int xopen (const char *path, int flags, mode_t); +-#ifndef __USE_TIME_BITS64 +-# ifdef __USE_FILE_OFFSET64 +-void xstat (const char *path, struct stat *); +-void xlstat (const char *path, struct stat *); +-void xfstat (int fd, struct stat *); +-# else +-void xstat (const char *path, struct stat64 *); +-void xlstat (const char *path, struct stat64 *); +-void xfstat (int fd, struct stat64 *); +-# endif +-#else +-void __REDIRECT (xstat, (const char *path, struct stat *), xstat_time64); +-void __REDIRECT (xlstat, (const char *path, struct stat *), xlstat_time64); +-void __REDIRECT (xfstat, (int fd, struct stat *), xfstat_time64); +-#endif ++void support_check_stat_fd (const char *name, int fd, int result); ++void support_check_stat_path (const char *name, const char *path, int result); ++#define xstat(path, st) \ ++ (support_check_stat_path ("stat", (path), stat ((path), (st)))) ++#define xfstat(fd, st) \ ++ (support_check_stat_fd ("fstat", (fd), fstat ((fd), (st)))) ++#define xlstat(path, st) \ ++ (support_check_stat_path ("lstat", (path), lstat ((path), (st)))) ++#define xstat64(path, st) \ ++ (support_check_stat_path ("stat64", (path), stat64 ((path), (st)))) ++#define xfstat64(fd, st) \ ++ (support_check_stat_fd ("fstat64", (fd), fstat64 ((fd), (st)))) ++#define xlstat64(path, st) \ ++ (support_check_stat_path ("lstat64", (path), lstat64 ((path), (st)))) + void xstatx (int, const char *, int, unsigned int, struct statx *); + void xmkdir (const char *path, mode_t); + void xchroot (const char *path); +-- +2.43.5 + diff --git a/glibc-RHEL-50545-7.patch b/glibc-RHEL-50545-7.patch new file mode 100644 index 0000000..b07088e --- /dev/null +++ b/glibc-RHEL-50545-7.patch @@ -0,0 +1,47 @@ +From 34e52acd55d69964d14fb3188c5538442b8b32be Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 22 Aug 2024 16:14:17 +0200 +Subject: [PATCH] support: Report errno constants in TEST_COMPARE failures +Content-type: text/plain; charset=UTF-8 + +If the expression is errno, decode it as an errno constant +using strerrorname_np. + +Reviewed-by: Arjun Shankar +--- + support/support_test_compare_failure.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/support/support_test_compare_failure.c b/support/support_test_compare_failure.c +index ae73d200cd..dba79e413f 100644 +--- a/support/support_test_compare_failure.c ++++ b/support/support_test_compare_failure.c +@@ -17,7 +17,9 @@ + . */ + + #include ++#include + #include ++#include + #include + + static void +@@ -31,7 +33,14 @@ report (const char *which, const char *expr, long long value, int positive, + printf ("%lld", value); + unsigned long long mask + = (~0ULL) >> (8 * (sizeof (unsigned long long) - size)); +- printf (" (0x%llx); from: %s\n", (unsigned long long) value & mask, expr); ++ const char *errno_constant = NULL; ++ if (strcmp (expr, "errno") == 0 ++ && positive && (unsigned long long int) value <= INT_MAX) ++ errno_constant = strerrorname_np (value); ++ printf (" (0x%llx", (unsigned long long) value & mask); ++ if (errno_constant != NULL) ++ printf (", %s", errno_constant); ++ printf ("); from: %s\n", expr); + } + + void +-- +2.43.5 + diff --git a/glibc-RHEL-50545-8.patch b/glibc-RHEL-50545-8.patch new file mode 100644 index 0000000..e6d036a --- /dev/null +++ b/glibc-RHEL-50545-8.patch @@ -0,0 +1,1661 @@ +From b09a520bb6d98d465818aadfd0641751ce824053 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 30 Aug 2024 21:51:46 +0200 +Subject: [PATCH] Bundle userspace header from Linux 6.10 +Content-type: text/plain; charset=UTF-8 + +And include the required licensing information. The only +change is a removed trailing empty line in +LICENSES/exceptions/Linux-syscall-note. + +Bundling is the recommended way to deal with +the evolution of the FUSE userspace interface because +structs change sizes over time. The kernel maintains +compatibility, but source-level compatibility on recompilation +may require additional code that is aware of older struct sizes. + +Signed-off-by: Florian Weimer +Reviewed-by: DJ Delorie +--- + support/bundled/README | 5 + + support/bundled/linux/COPYING | 20 + + .../LICENSES/exceptions/Linux-syscall-note | 24 + + .../bundled/linux/LICENSES/preferred/GPL-2.0 | 359 +++++ + .../bundled/linux/include/uapi/linux/fuse.h | 1189 +++++++++++++++++ + 5 files changed, 1597 insertions(+) + create mode 100644 support/bundled/README + create mode 100644 support/bundled/linux/COPYING + create mode 100644 support/bundled/linux/LICENSES/exceptions/Linux-syscall-note + create mode 100644 support/bundled/linux/LICENSES/preferred/GPL-2.0 + create mode 100644 support/bundled/linux/include/uapi/linux/fuse.h + +diff --git a/support/bundled/README b/support/bundled/README +new file mode 100644 +index 0000000000..e861b3d40a +--- /dev/null ++++ b/support/bundled/README +@@ -0,0 +1,5 @@ ++This subtree contains bundled files included verbatim from other ++sources. They are used for building the support/ infrastructure. ++ ++linux/ ++ Select files from the Linux 6.10 source tree. +diff --git a/support/bundled/linux/COPYING b/support/bundled/linux/COPYING +new file mode 100644 +index 0000000000..a635a38ef9 +--- /dev/null ++++ b/support/bundled/linux/COPYING +@@ -0,0 +1,20 @@ ++The Linux Kernel is provided under: ++ ++ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note ++ ++Being under the terms of the GNU General Public License version 2 only, ++according with: ++ ++ LICENSES/preferred/GPL-2.0 ++ ++With an explicit syscall exception, as stated at: ++ ++ LICENSES/exceptions/Linux-syscall-note ++ ++In addition, other licenses may also apply. Please see: ++ ++ Documentation/process/license-rules.rst ++ ++for more details. ++ ++All contributions to the Linux Kernel are subject to this COPYING file. +diff --git a/support/bundled/linux/LICENSES/exceptions/Linux-syscall-note b/support/bundled/linux/LICENSES/exceptions/Linux-syscall-note +new file mode 100644 +index 0000000000..adbe756a05 +--- /dev/null ++++ b/support/bundled/linux/LICENSES/exceptions/Linux-syscall-note +@@ -0,0 +1,24 @@ ++SPDX-Exception-Identifier: Linux-syscall-note ++SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html ++SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+, GPL-2.0-only, GPL-2.0-or-later ++Usage-Guide: ++ This exception is used together with one of the above SPDX-Licenses ++ to mark user space API (uapi) header files so they can be included ++ into non GPL compliant user space application code. ++ To use this exception add it with the keyword WITH to one of the ++ identifiers in the SPDX-Licenses tag: ++ SPDX-License-Identifier: WITH Linux-syscall-note ++License-Text: ++ ++ NOTE! This copyright does *not* cover user programs that use kernel ++ services by normal system calls - this is merely considered normal use ++ of the kernel, and does *not* fall under the heading of "derived work". ++ Also note that the GPL below is copyrighted by the Free Software ++ Foundation, but the instance of code that it refers to (the Linux ++ kernel) is copyrighted by me and others who actually wrote it. ++ ++ Also note that the only valid version of the GPL as far as the kernel ++ is concerned is _this_ particular version of the license (ie v2, not ++ v2.2 or v3.x or whatever), unless explicitly otherwise stated. ++ ++ Linus Torvalds +diff --git a/support/bundled/linux/LICENSES/preferred/GPL-2.0 b/support/bundled/linux/LICENSES/preferred/GPL-2.0 +new file mode 100644 +index 0000000000..ff0812fd89 +--- /dev/null ++++ b/support/bundled/linux/LICENSES/preferred/GPL-2.0 +@@ -0,0 +1,359 @@ ++Valid-License-Identifier: GPL-2.0 ++Valid-License-Identifier: GPL-2.0-only ++Valid-License-Identifier: GPL-2.0+ ++Valid-License-Identifier: GPL-2.0-or-later ++SPDX-URL: https://spdx.org/licenses/GPL-2.0.html ++Usage-Guide: ++ To use this license in source code, put one of the following SPDX ++ tag/value pairs into a comment according to the placement ++ guidelines in the licensing rules documentation. ++ For 'GNU General Public License (GPL) version 2 only' use: ++ SPDX-License-Identifier: GPL-2.0 ++ or ++ SPDX-License-Identifier: GPL-2.0-only ++ For 'GNU General Public License (GPL) version 2 or any later version' use: ++ SPDX-License-Identifier: GPL-2.0+ ++ or ++ SPDX-License-Identifier: GPL-2.0-or-later ++License-Text: ++ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Library General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) ++ ++ This program 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 2 of the License, or ++ (at your option) any later version. ++ ++ This program 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, write to the Free Software ++ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) year name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General ++Public License instead of this License. +diff --git a/support/bundled/linux/include/uapi/linux/fuse.h b/support/bundled/linux/include/uapi/linux/fuse.h +new file mode 100644 +index 0000000000..d08b99d60f +--- /dev/null ++++ b/support/bundled/linux/include/uapi/linux/fuse.h +@@ -0,0 +1,1189 @@ ++/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */ ++/* ++ This file defines the kernel interface of FUSE ++ Copyright (C) 2001-2008 Miklos Szeredi ++ ++ This program can be distributed under the terms of the GNU GPL. ++ See the file COPYING. ++ ++ This -- and only this -- header file may also be distributed under ++ the terms of the BSD Licence as follows: ++ ++ Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. ++ ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions ++ are met: ++ 1. Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in the ++ documentation and/or other materials provided with the distribution. ++ ++ THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE ++ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ SUCH DAMAGE. ++*/ ++ ++/* ++ * This file defines the kernel interface of FUSE ++ * ++ * Protocol changelog: ++ * ++ * 7.1: ++ * - add the following messages: ++ * FUSE_SETATTR, FUSE_SYMLINK, FUSE_MKNOD, FUSE_MKDIR, FUSE_UNLINK, ++ * FUSE_RMDIR, FUSE_RENAME, FUSE_LINK, FUSE_OPEN, FUSE_READ, FUSE_WRITE, ++ * FUSE_RELEASE, FUSE_FSYNC, FUSE_FLUSH, FUSE_SETXATTR, FUSE_GETXATTR, ++ * FUSE_LISTXATTR, FUSE_REMOVEXATTR, FUSE_OPENDIR, FUSE_READDIR, ++ * FUSE_RELEASEDIR ++ * - add padding to messages to accommodate 32-bit servers on 64-bit kernels ++ * ++ * 7.2: ++ * - add FOPEN_DIRECT_IO and FOPEN_KEEP_CACHE flags ++ * - add FUSE_FSYNCDIR message ++ * ++ * 7.3: ++ * - add FUSE_ACCESS message ++ * - add FUSE_CREATE message ++ * - add filehandle to fuse_setattr_in ++ * ++ * 7.4: ++ * - add frsize to fuse_kstatfs ++ * - clean up request size limit checking ++ * ++ * 7.5: ++ * - add flags and max_write to fuse_init_out ++ * ++ * 7.6: ++ * - add max_readahead to fuse_init_in and fuse_init_out ++ * ++ * 7.7: ++ * - add FUSE_INTERRUPT message ++ * - add POSIX file lock support ++ * ++ * 7.8: ++ * - add lock_owner and flags fields to fuse_release_in ++ * - add FUSE_BMAP message ++ * - add FUSE_DESTROY message ++ * ++ * 7.9: ++ * - new fuse_getattr_in input argument of GETATTR ++ * - add lk_flags in fuse_lk_in ++ * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in ++ * - add blksize field to fuse_attr ++ * - add file flags field to fuse_read_in and fuse_write_in ++ * - Add ATIME_NOW and MTIME_NOW flags to fuse_setattr_in ++ * ++ * 7.10 ++ * - add nonseekable open flag ++ * ++ * 7.11 ++ * - add IOCTL message ++ * - add unsolicited notification support ++ * - add POLL message and NOTIFY_POLL notification ++ * ++ * 7.12 ++ * - add umask flag to input argument of create, mknod and mkdir ++ * - add notification messages for invalidation of inodes and ++ * directory entries ++ * ++ * 7.13 ++ * - make max number of background requests and congestion threshold ++ * tunables ++ * ++ * 7.14 ++ * - add splice support to fuse device ++ * ++ * 7.15 ++ * - add store notify ++ * - add retrieve notify ++ * ++ * 7.16 ++ * - add BATCH_FORGET request ++ * - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct ++ * fuse_ioctl_iovec' instead of ambiguous 'struct iovec' ++ * - add FUSE_IOCTL_32BIT flag ++ * ++ * 7.17 ++ * - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK ++ * ++ * 7.18 ++ * - add FUSE_IOCTL_DIR flag ++ * - add FUSE_NOTIFY_DELETE ++ * ++ * 7.19 ++ * - add FUSE_FALLOCATE ++ * ++ * 7.20 ++ * - add FUSE_AUTO_INVAL_DATA ++ * ++ * 7.21 ++ * - add FUSE_READDIRPLUS ++ * - send the requested events in POLL request ++ * ++ * 7.22 ++ * - add FUSE_ASYNC_DIO ++ * ++ * 7.23 ++ * - add FUSE_WRITEBACK_CACHE ++ * - add time_gran to fuse_init_out ++ * - add reserved space to fuse_init_out ++ * - add FATTR_CTIME ++ * - add ctime and ctimensec to fuse_setattr_in ++ * - add FUSE_RENAME2 request ++ * - add FUSE_NO_OPEN_SUPPORT flag ++ * ++ * 7.24 ++ * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support ++ * ++ * 7.25 ++ * - add FUSE_PARALLEL_DIROPS ++ * ++ * 7.26 ++ * - add FUSE_HANDLE_KILLPRIV ++ * - add FUSE_POSIX_ACL ++ * ++ * 7.27 ++ * - add FUSE_ABORT_ERROR ++ * ++ * 7.28 ++ * - add FUSE_COPY_FILE_RANGE ++ * - add FOPEN_CACHE_DIR ++ * - add FUSE_MAX_PAGES, add max_pages to init_out ++ * - add FUSE_CACHE_SYMLINKS ++ * ++ * 7.29 ++ * - add FUSE_NO_OPENDIR_SUPPORT flag ++ * ++ * 7.30 ++ * - add FUSE_EXPLICIT_INVAL_DATA ++ * - add FUSE_IOCTL_COMPAT_X32 ++ * ++ * 7.31 ++ * - add FUSE_WRITE_KILL_PRIV flag ++ * - add FUSE_SETUPMAPPING and FUSE_REMOVEMAPPING ++ * - add map_alignment to fuse_init_out, add FUSE_MAP_ALIGNMENT flag ++ * ++ * 7.32 ++ * - add flags to fuse_attr, add FUSE_ATTR_SUBMOUNT, add FUSE_SUBMOUNTS ++ * ++ * 7.33 ++ * - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID ++ * - add FUSE_OPEN_KILL_SUIDGID ++ * - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT ++ * - add FUSE_SETXATTR_ACL_KILL_SGID ++ * ++ * 7.34 ++ * - add FUSE_SYNCFS ++ * ++ * 7.35 ++ * - add FOPEN_NOFLUSH ++ * ++ * 7.36 ++ * - extend fuse_init_in with reserved fields, add FUSE_INIT_EXT init flag ++ * - add flags2 to fuse_init_in and fuse_init_out ++ * - add FUSE_SECURITY_CTX init flag ++ * - add security context to create, mkdir, symlink, and mknod requests ++ * - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX ++ * ++ * 7.37 ++ * - add FUSE_TMPFILE ++ * ++ * 7.38 ++ * - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry ++ * - add FOPEN_PARALLEL_DIRECT_WRITES ++ * - add total_extlen to fuse_in_header ++ * - add FUSE_MAX_NR_SECCTX ++ * - add extension header ++ * - add FUSE_EXT_GROUPS ++ * - add FUSE_CREATE_SUPP_GROUP ++ * - add FUSE_HAS_EXPIRE_ONLY ++ * ++ * 7.39 ++ * - add FUSE_DIRECT_IO_ALLOW_MMAP ++ * - add FUSE_STATX and related structures ++ * ++ * 7.40 ++ * - add max_stack_depth to fuse_init_out, add FUSE_PASSTHROUGH init flag ++ * - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag ++ * - add FUSE_NO_EXPORT_SUPPORT init flag ++ * - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag ++ */ ++ ++#ifndef _LINUX_FUSE_H ++#define _LINUX_FUSE_H ++ ++#ifdef __KERNEL__ ++#include ++#else ++#include ++#endif ++ ++/* ++ * Version negotiation: ++ * ++ * Both the kernel and userspace send the version they support in the ++ * INIT request and reply respectively. ++ * ++ * If the major versions match then both shall use the smallest ++ * of the two minor versions for communication. ++ * ++ * If the kernel supports a larger major version, then userspace shall ++ * reply with the major version it supports, ignore the rest of the ++ * INIT message and expect a new INIT message from the kernel with a ++ * matching major version. ++ * ++ * If the library supports a larger major version, then it shall fall ++ * back to the major protocol version sent by the kernel for ++ * communication and reply with that major version (and an arbitrary ++ * supported minor version). ++ */ ++ ++/** Version number of this interface */ ++#define FUSE_KERNEL_VERSION 7 ++ ++/** Minor version number of this interface */ ++#define FUSE_KERNEL_MINOR_VERSION 40 ++ ++/** The node ID of the root inode */ ++#define FUSE_ROOT_ID 1 ++ ++/* Make sure all structures are padded to 64bit boundary, so 32bit ++ userspace works under 64bit kernels */ ++ ++struct fuse_attr { ++ uint64_t ino; ++ uint64_t size; ++ uint64_t blocks; ++ uint64_t atime; ++ uint64_t mtime; ++ uint64_t ctime; ++ uint32_t atimensec; ++ uint32_t mtimensec; ++ uint32_t ctimensec; ++ uint32_t mode; ++ uint32_t nlink; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t rdev; ++ uint32_t blksize; ++ uint32_t flags; ++}; ++ ++/* ++ * The following structures are bit-for-bit compatible with the statx(2) ABI in ++ * Linux. ++ */ ++struct fuse_sx_time { ++ int64_t tv_sec; ++ uint32_t tv_nsec; ++ int32_t __reserved; ++}; ++ ++struct fuse_statx { ++ uint32_t mask; ++ uint32_t blksize; ++ uint64_t attributes; ++ uint32_t nlink; ++ uint32_t uid; ++ uint32_t gid; ++ uint16_t mode; ++ uint16_t __spare0[1]; ++ uint64_t ino; ++ uint64_t size; ++ uint64_t blocks; ++ uint64_t attributes_mask; ++ struct fuse_sx_time atime; ++ struct fuse_sx_time btime; ++ struct fuse_sx_time ctime; ++ struct fuse_sx_time mtime; ++ uint32_t rdev_major; ++ uint32_t rdev_minor; ++ uint32_t dev_major; ++ uint32_t dev_minor; ++ uint64_t __spare2[14]; ++}; ++ ++struct fuse_kstatfs { ++ uint64_t blocks; ++ uint64_t bfree; ++ uint64_t bavail; ++ uint64_t files; ++ uint64_t ffree; ++ uint32_t bsize; ++ uint32_t namelen; ++ uint32_t frsize; ++ uint32_t padding; ++ uint32_t spare[6]; ++}; ++ ++struct fuse_file_lock { ++ uint64_t start; ++ uint64_t end; ++ uint32_t type; ++ uint32_t pid; /* tgid */ ++}; ++ ++/** ++ * Bitmasks for fuse_setattr_in.valid ++ */ ++#define FATTR_MODE (1 << 0) ++#define FATTR_UID (1 << 1) ++#define FATTR_GID (1 << 2) ++#define FATTR_SIZE (1 << 3) ++#define FATTR_ATIME (1 << 4) ++#define FATTR_MTIME (1 << 5) ++#define FATTR_FH (1 << 6) ++#define FATTR_ATIME_NOW (1 << 7) ++#define FATTR_MTIME_NOW (1 << 8) ++#define FATTR_LOCKOWNER (1 << 9) ++#define FATTR_CTIME (1 << 10) ++#define FATTR_KILL_SUIDGID (1 << 11) ++ ++/** ++ * Flags returned by the OPEN request ++ * ++ * FOPEN_DIRECT_IO: bypass page cache for this open file ++ * FOPEN_KEEP_CACHE: don't invalidate the data cache on open ++ * FOPEN_NONSEEKABLE: the file is not seekable ++ * FOPEN_CACHE_DIR: allow caching this directory ++ * FOPEN_STREAM: the file is stream-like (no file position at all) ++ * FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE) ++ * FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode ++ * FOPEN_PASSTHROUGH: passthrough read/write io for this open file ++ */ ++#define FOPEN_DIRECT_IO (1 << 0) ++#define FOPEN_KEEP_CACHE (1 << 1) ++#define FOPEN_NONSEEKABLE (1 << 2) ++#define FOPEN_CACHE_DIR (1 << 3) ++#define FOPEN_STREAM (1 << 4) ++#define FOPEN_NOFLUSH (1 << 5) ++#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6) ++#define FOPEN_PASSTHROUGH (1 << 7) ++ ++/** ++ * INIT request/reply flags ++ * ++ * FUSE_ASYNC_READ: asynchronous read requests ++ * FUSE_POSIX_LOCKS: remote locking for POSIX file locks ++ * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported) ++ * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem ++ * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." ++ * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB ++ * FUSE_DONT_MASK: don't apply umask to file mode on create operations ++ * FUSE_SPLICE_WRITE: kernel supports splice write on the device ++ * FUSE_SPLICE_MOVE: kernel supports splice move on the device ++ * FUSE_SPLICE_READ: kernel supports splice read on the device ++ * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks ++ * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories ++ * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages ++ * FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one) ++ * FUSE_READDIRPLUS_AUTO: adaptive readdirplus ++ * FUSE_ASYNC_DIO: asynchronous direct I/O submission ++ * FUSE_WRITEBACK_CACHE: use writeback cache for buffered writes ++ * FUSE_NO_OPEN_SUPPORT: kernel supports zero-message opens ++ * FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir ++ * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc ++ * FUSE_POSIX_ACL: filesystem supports posix acls ++ * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED ++ * FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages ++ * FUSE_CACHE_SYMLINKS: cache READLINK responses ++ * FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir ++ * FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request ++ * FUSE_MAP_ALIGNMENT: init_out.map_alignment contains log2(byte alignment) for ++ * foffset and moffset fields in struct ++ * fuse_setupmapping_out and fuse_removemapping_one. ++ * FUSE_SUBMOUNTS: kernel supports auto-mounting directory submounts ++ * FUSE_HANDLE_KILLPRIV_V2: fs kills suid/sgid/cap on write/chown/trunc. ++ * Upon write/truncate suid/sgid is only killed if caller ++ * does not have CAP_FSETID. Additionally upon ++ * write/truncate sgid is killed only if file has group ++ * execute permission. (Same as Linux VFS behavior). ++ * FUSE_SETXATTR_EXT: Server supports extended struct fuse_setxattr_in ++ * FUSE_INIT_EXT: extended fuse_init_in request ++ * FUSE_INIT_RESERVED: reserved, do not use ++ * FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and ++ * mknod ++ * FUSE_HAS_INODE_DAX: use per inode DAX ++ * FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir, ++ * symlink and mknod (single group that matches parent) ++ * FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation ++ * FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode. ++ * FUSE_NO_EXPORT_SUPPORT: explicitly disable export support ++ * FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit ++ * of the request ID indicates resend requests ++ */ ++#define FUSE_ASYNC_READ (1 << 0) ++#define FUSE_POSIX_LOCKS (1 << 1) ++#define FUSE_FILE_OPS (1 << 2) ++#define FUSE_ATOMIC_O_TRUNC (1 << 3) ++#define FUSE_EXPORT_SUPPORT (1 << 4) ++#define FUSE_BIG_WRITES (1 << 5) ++#define FUSE_DONT_MASK (1 << 6) ++#define FUSE_SPLICE_WRITE (1 << 7) ++#define FUSE_SPLICE_MOVE (1 << 8) ++#define FUSE_SPLICE_READ (1 << 9) ++#define FUSE_FLOCK_LOCKS (1 << 10) ++#define FUSE_HAS_IOCTL_DIR (1 << 11) ++#define FUSE_AUTO_INVAL_DATA (1 << 12) ++#define FUSE_DO_READDIRPLUS (1 << 13) ++#define FUSE_READDIRPLUS_AUTO (1 << 14) ++#define FUSE_ASYNC_DIO (1 << 15) ++#define FUSE_WRITEBACK_CACHE (1 << 16) ++#define FUSE_NO_OPEN_SUPPORT (1 << 17) ++#define FUSE_PARALLEL_DIROPS (1 << 18) ++#define FUSE_HANDLE_KILLPRIV (1 << 19) ++#define FUSE_POSIX_ACL (1 << 20) ++#define FUSE_ABORT_ERROR (1 << 21) ++#define FUSE_MAX_PAGES (1 << 22) ++#define FUSE_CACHE_SYMLINKS (1 << 23) ++#define FUSE_NO_OPENDIR_SUPPORT (1 << 24) ++#define FUSE_EXPLICIT_INVAL_DATA (1 << 25) ++#define FUSE_MAP_ALIGNMENT (1 << 26) ++#define FUSE_SUBMOUNTS (1 << 27) ++#define FUSE_HANDLE_KILLPRIV_V2 (1 << 28) ++#define FUSE_SETXATTR_EXT (1 << 29) ++#define FUSE_INIT_EXT (1 << 30) ++#define FUSE_INIT_RESERVED (1 << 31) ++/* bits 32..63 get shifted down 32 bits into the flags2 field */ ++#define FUSE_SECURITY_CTX (1ULL << 32) ++#define FUSE_HAS_INODE_DAX (1ULL << 33) ++#define FUSE_CREATE_SUPP_GROUP (1ULL << 34) ++#define FUSE_HAS_EXPIRE_ONLY (1ULL << 35) ++#define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36) ++#define FUSE_PASSTHROUGH (1ULL << 37) ++#define FUSE_NO_EXPORT_SUPPORT (1ULL << 38) ++#define FUSE_HAS_RESEND (1ULL << 39) ++ ++/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */ ++#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP ++ ++/** ++ * CUSE INIT request/reply flags ++ * ++ * CUSE_UNRESTRICTED_IOCTL: use unrestricted ioctl ++ */ ++#define CUSE_UNRESTRICTED_IOCTL (1 << 0) ++ ++/** ++ * Release flags ++ */ ++#define FUSE_RELEASE_FLUSH (1 << 0) ++#define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1) ++ ++/** ++ * Getattr flags ++ */ ++#define FUSE_GETATTR_FH (1 << 0) ++ ++/** ++ * Lock flags ++ */ ++#define FUSE_LK_FLOCK (1 << 0) ++ ++/** ++ * WRITE flags ++ * ++ * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed ++ * FUSE_WRITE_LOCKOWNER: lock_owner field is valid ++ * FUSE_WRITE_KILL_SUIDGID: kill suid and sgid bits ++ */ ++#define FUSE_WRITE_CACHE (1 << 0) ++#define FUSE_WRITE_LOCKOWNER (1 << 1) ++#define FUSE_WRITE_KILL_SUIDGID (1 << 2) ++ ++/* Obsolete alias; this flag implies killing suid/sgid only. */ ++#define FUSE_WRITE_KILL_PRIV FUSE_WRITE_KILL_SUIDGID ++ ++/** ++ * Read flags ++ */ ++#define FUSE_READ_LOCKOWNER (1 << 1) ++ ++/** ++ * Ioctl flags ++ * ++ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine ++ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed ++ * FUSE_IOCTL_RETRY: retry with new iovecs ++ * FUSE_IOCTL_32BIT: 32bit ioctl ++ * FUSE_IOCTL_DIR: is a directory ++ * FUSE_IOCTL_COMPAT_X32: x32 compat ioctl on 64bit machine (64bit time_t) ++ * ++ * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs ++ */ ++#define FUSE_IOCTL_COMPAT (1 << 0) ++#define FUSE_IOCTL_UNRESTRICTED (1 << 1) ++#define FUSE_IOCTL_RETRY (1 << 2) ++#define FUSE_IOCTL_32BIT (1 << 3) ++#define FUSE_IOCTL_DIR (1 << 4) ++#define FUSE_IOCTL_COMPAT_X32 (1 << 5) ++ ++#define FUSE_IOCTL_MAX_IOV 256 ++ ++/** ++ * Poll flags ++ * ++ * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify ++ */ ++#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0) ++ ++/** ++ * Fsync flags ++ * ++ * FUSE_FSYNC_FDATASYNC: Sync data only, not metadata ++ */ ++#define FUSE_FSYNC_FDATASYNC (1 << 0) ++ ++/** ++ * fuse_attr flags ++ * ++ * FUSE_ATTR_SUBMOUNT: Object is a submount root ++ * FUSE_ATTR_DAX: Enable DAX for this file in per inode DAX mode ++ */ ++#define FUSE_ATTR_SUBMOUNT (1 << 0) ++#define FUSE_ATTR_DAX (1 << 1) ++ ++/** ++ * Open flags ++ * FUSE_OPEN_KILL_SUIDGID: Kill suid and sgid if executable ++ */ ++#define FUSE_OPEN_KILL_SUIDGID (1 << 0) ++ ++/** ++ * setxattr flags ++ * FUSE_SETXATTR_ACL_KILL_SGID: Clear SGID when system.posix_acl_access is set ++ */ ++#define FUSE_SETXATTR_ACL_KILL_SGID (1 << 0) ++ ++/** ++ * notify_inval_entry flags ++ * FUSE_EXPIRE_ONLY ++ */ ++#define FUSE_EXPIRE_ONLY (1 << 0) ++ ++/** ++ * extension type ++ * FUSE_MAX_NR_SECCTX: maximum value of &fuse_secctx_header.nr_secctx ++ * FUSE_EXT_GROUPS: &fuse_supp_groups extension ++ */ ++enum fuse_ext_type { ++ /* Types 0..31 are reserved for fuse_secctx_header */ ++ FUSE_MAX_NR_SECCTX = 31, ++ FUSE_EXT_GROUPS = 32, ++}; ++ ++enum fuse_opcode { ++ FUSE_LOOKUP = 1, ++ FUSE_FORGET = 2, /* no reply */ ++ FUSE_GETATTR = 3, ++ FUSE_SETATTR = 4, ++ FUSE_READLINK = 5, ++ FUSE_SYMLINK = 6, ++ FUSE_MKNOD = 8, ++ FUSE_MKDIR = 9, ++ FUSE_UNLINK = 10, ++ FUSE_RMDIR = 11, ++ FUSE_RENAME = 12, ++ FUSE_LINK = 13, ++ FUSE_OPEN = 14, ++ FUSE_READ = 15, ++ FUSE_WRITE = 16, ++ FUSE_STATFS = 17, ++ FUSE_RELEASE = 18, ++ FUSE_FSYNC = 20, ++ FUSE_SETXATTR = 21, ++ FUSE_GETXATTR = 22, ++ FUSE_LISTXATTR = 23, ++ FUSE_REMOVEXATTR = 24, ++ FUSE_FLUSH = 25, ++ FUSE_INIT = 26, ++ FUSE_OPENDIR = 27, ++ FUSE_READDIR = 28, ++ FUSE_RELEASEDIR = 29, ++ FUSE_FSYNCDIR = 30, ++ FUSE_GETLK = 31, ++ FUSE_SETLK = 32, ++ FUSE_SETLKW = 33, ++ FUSE_ACCESS = 34, ++ FUSE_CREATE = 35, ++ FUSE_INTERRUPT = 36, ++ FUSE_BMAP = 37, ++ FUSE_DESTROY = 38, ++ FUSE_IOCTL = 39, ++ FUSE_POLL = 40, ++ FUSE_NOTIFY_REPLY = 41, ++ FUSE_BATCH_FORGET = 42, ++ FUSE_FALLOCATE = 43, ++ FUSE_READDIRPLUS = 44, ++ FUSE_RENAME2 = 45, ++ FUSE_LSEEK = 46, ++ FUSE_COPY_FILE_RANGE = 47, ++ FUSE_SETUPMAPPING = 48, ++ FUSE_REMOVEMAPPING = 49, ++ FUSE_SYNCFS = 50, ++ FUSE_TMPFILE = 51, ++ FUSE_STATX = 52, ++ ++ /* CUSE specific operations */ ++ CUSE_INIT = 4096, ++ ++ /* Reserved opcodes: helpful to detect structure endian-ness */ ++ CUSE_INIT_BSWAP_RESERVED = 1048576, /* CUSE_INIT << 8 */ ++ FUSE_INIT_BSWAP_RESERVED = 436207616, /* FUSE_INIT << 24 */ ++}; ++ ++enum fuse_notify_code { ++ FUSE_NOTIFY_POLL = 1, ++ FUSE_NOTIFY_INVAL_INODE = 2, ++ FUSE_NOTIFY_INVAL_ENTRY = 3, ++ FUSE_NOTIFY_STORE = 4, ++ FUSE_NOTIFY_RETRIEVE = 5, ++ FUSE_NOTIFY_DELETE = 6, ++ FUSE_NOTIFY_RESEND = 7, ++ FUSE_NOTIFY_CODE_MAX, ++}; ++ ++/* The read buffer is required to be at least 8k, but may be much larger */ ++#define FUSE_MIN_READ_BUFFER 8192 ++ ++#define FUSE_COMPAT_ENTRY_OUT_SIZE 120 ++ ++struct fuse_entry_out { ++ uint64_t nodeid; /* Inode ID */ ++ uint64_t generation; /* Inode generation: nodeid:gen must ++ be unique for the fs's lifetime */ ++ uint64_t entry_valid; /* Cache timeout for the name */ ++ uint64_t attr_valid; /* Cache timeout for the attributes */ ++ uint32_t entry_valid_nsec; ++ uint32_t attr_valid_nsec; ++ struct fuse_attr attr; ++}; ++ ++struct fuse_forget_in { ++ uint64_t nlookup; ++}; ++ ++struct fuse_forget_one { ++ uint64_t nodeid; ++ uint64_t nlookup; ++}; ++ ++struct fuse_batch_forget_in { ++ uint32_t count; ++ uint32_t dummy; ++}; ++ ++struct fuse_getattr_in { ++ uint32_t getattr_flags; ++ uint32_t dummy; ++ uint64_t fh; ++}; ++ ++#define FUSE_COMPAT_ATTR_OUT_SIZE 96 ++ ++struct fuse_attr_out { ++ uint64_t attr_valid; /* Cache timeout for the attributes */ ++ uint32_t attr_valid_nsec; ++ uint32_t dummy; ++ struct fuse_attr attr; ++}; ++ ++struct fuse_statx_in { ++ uint32_t getattr_flags; ++ uint32_t reserved; ++ uint64_t fh; ++ uint32_t sx_flags; ++ uint32_t sx_mask; ++}; ++ ++struct fuse_statx_out { ++ uint64_t attr_valid; /* Cache timeout for the attributes */ ++ uint32_t attr_valid_nsec; ++ uint32_t flags; ++ uint64_t spare[2]; ++ struct fuse_statx stat; ++}; ++ ++#define FUSE_COMPAT_MKNOD_IN_SIZE 8 ++ ++struct fuse_mknod_in { ++ uint32_t mode; ++ uint32_t rdev; ++ uint32_t umask; ++ uint32_t padding; ++}; ++ ++struct fuse_mkdir_in { ++ uint32_t mode; ++ uint32_t umask; ++}; ++ ++struct fuse_rename_in { ++ uint64_t newdir; ++}; ++ ++struct fuse_rename2_in { ++ uint64_t newdir; ++ uint32_t flags; ++ uint32_t padding; ++}; ++ ++struct fuse_link_in { ++ uint64_t oldnodeid; ++}; ++ ++struct fuse_setattr_in { ++ uint32_t valid; ++ uint32_t padding; ++ uint64_t fh; ++ uint64_t size; ++ uint64_t lock_owner; ++ uint64_t atime; ++ uint64_t mtime; ++ uint64_t ctime; ++ uint32_t atimensec; ++ uint32_t mtimensec; ++ uint32_t ctimensec; ++ uint32_t mode; ++ uint32_t unused4; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t unused5; ++}; ++ ++struct fuse_open_in { ++ uint32_t flags; ++ uint32_t open_flags; /* FUSE_OPEN_... */ ++}; ++ ++struct fuse_create_in { ++ uint32_t flags; ++ uint32_t mode; ++ uint32_t umask; ++ uint32_t open_flags; /* FUSE_OPEN_... */ ++}; ++ ++struct fuse_open_out { ++ uint64_t fh; ++ uint32_t open_flags; ++ int32_t backing_id; ++}; ++ ++struct fuse_release_in { ++ uint64_t fh; ++ uint32_t flags; ++ uint32_t release_flags; ++ uint64_t lock_owner; ++}; ++ ++struct fuse_flush_in { ++ uint64_t fh; ++ uint32_t unused; ++ uint32_t padding; ++ uint64_t lock_owner; ++}; ++ ++struct fuse_read_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t read_flags; ++ uint64_t lock_owner; ++ uint32_t flags; ++ uint32_t padding; ++}; ++ ++#define FUSE_COMPAT_WRITE_IN_SIZE 24 ++ ++struct fuse_write_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t write_flags; ++ uint64_t lock_owner; ++ uint32_t flags; ++ uint32_t padding; ++}; ++ ++struct fuse_write_out { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++#define FUSE_COMPAT_STATFS_SIZE 48 ++ ++struct fuse_statfs_out { ++ struct fuse_kstatfs st; ++}; ++ ++struct fuse_fsync_in { ++ uint64_t fh; ++ uint32_t fsync_flags; ++ uint32_t padding; ++}; ++ ++#define FUSE_COMPAT_SETXATTR_IN_SIZE 8 ++ ++struct fuse_setxattr_in { ++ uint32_t size; ++ uint32_t flags; ++ uint32_t setxattr_flags; ++ uint32_t padding; ++}; ++ ++struct fuse_getxattr_in { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++struct fuse_getxattr_out { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++struct fuse_lk_in { ++ uint64_t fh; ++ uint64_t owner; ++ struct fuse_file_lock lk; ++ uint32_t lk_flags; ++ uint32_t padding; ++}; ++ ++struct fuse_lk_out { ++ struct fuse_file_lock lk; ++}; ++ ++struct fuse_access_in { ++ uint32_t mask; ++ uint32_t padding; ++}; ++ ++struct fuse_init_in { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t max_readahead; ++ uint32_t flags; ++ uint32_t flags2; ++ uint32_t unused[11]; ++}; ++ ++#define FUSE_COMPAT_INIT_OUT_SIZE 8 ++#define FUSE_COMPAT_22_INIT_OUT_SIZE 24 ++ ++struct fuse_init_out { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t max_readahead; ++ uint32_t flags; ++ uint16_t max_background; ++ uint16_t congestion_threshold; ++ uint32_t max_write; ++ uint32_t time_gran; ++ uint16_t max_pages; ++ uint16_t map_alignment; ++ uint32_t flags2; ++ uint32_t max_stack_depth; ++ uint32_t unused[6]; ++}; ++ ++#define CUSE_INIT_INFO_MAX 4096 ++ ++struct cuse_init_in { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t unused; ++ uint32_t flags; ++}; ++ ++struct cuse_init_out { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t unused; ++ uint32_t flags; ++ uint32_t max_read; ++ uint32_t max_write; ++ uint32_t dev_major; /* chardev major */ ++ uint32_t dev_minor; /* chardev minor */ ++ uint32_t spare[10]; ++}; ++ ++struct fuse_interrupt_in { ++ uint64_t unique; ++}; ++ ++struct fuse_bmap_in { ++ uint64_t block; ++ uint32_t blocksize; ++ uint32_t padding; ++}; ++ ++struct fuse_bmap_out { ++ uint64_t block; ++}; ++ ++struct fuse_ioctl_in { ++ uint64_t fh; ++ uint32_t flags; ++ uint32_t cmd; ++ uint64_t arg; ++ uint32_t in_size; ++ uint32_t out_size; ++}; ++ ++struct fuse_ioctl_iovec { ++ uint64_t base; ++ uint64_t len; ++}; ++ ++struct fuse_ioctl_out { ++ int32_t result; ++ uint32_t flags; ++ uint32_t in_iovs; ++ uint32_t out_iovs; ++}; ++ ++struct fuse_poll_in { ++ uint64_t fh; ++ uint64_t kh; ++ uint32_t flags; ++ uint32_t events; ++}; ++ ++struct fuse_poll_out { ++ uint32_t revents; ++ uint32_t padding; ++}; ++ ++struct fuse_notify_poll_wakeup_out { ++ uint64_t kh; ++}; ++ ++struct fuse_fallocate_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint64_t length; ++ uint32_t mode; ++ uint32_t padding; ++}; ++ ++/** ++ * FUSE request unique ID flag ++ * ++ * Indicates whether this is a resend request. The receiver should handle this ++ * request accordingly. ++ */ ++#define FUSE_UNIQUE_RESEND (1ULL << 63) ++ ++struct fuse_in_header { ++ uint32_t len; ++ uint32_t opcode; ++ uint64_t unique; ++ uint64_t nodeid; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t pid; ++ uint16_t total_extlen; /* length of extensions in 8byte units */ ++ uint16_t padding; ++}; ++ ++struct fuse_out_header { ++ uint32_t len; ++ int32_t error; ++ uint64_t unique; ++}; ++ ++struct fuse_dirent { ++ uint64_t ino; ++ uint64_t off; ++ uint32_t namelen; ++ uint32_t type; ++ char name[]; ++}; ++ ++/* Align variable length records to 64bit boundary */ ++#define FUSE_REC_ALIGN(x) \ ++ (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) ++ ++#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) ++#define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x) ++#define FUSE_DIRENT_SIZE(d) \ ++ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) ++ ++struct fuse_direntplus { ++ struct fuse_entry_out entry_out; ++ struct fuse_dirent dirent; ++}; ++ ++#define FUSE_NAME_OFFSET_DIRENTPLUS \ ++ offsetof(struct fuse_direntplus, dirent.name) ++#define FUSE_DIRENTPLUS_SIZE(d) \ ++ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen) ++ ++struct fuse_notify_inval_inode_out { ++ uint64_t ino; ++ int64_t off; ++ int64_t len; ++}; ++ ++struct fuse_notify_inval_entry_out { ++ uint64_t parent; ++ uint32_t namelen; ++ uint32_t flags; ++}; ++ ++struct fuse_notify_delete_out { ++ uint64_t parent; ++ uint64_t child; ++ uint32_t namelen; ++ uint32_t padding; ++}; ++ ++struct fuse_notify_store_out { ++ uint64_t nodeid; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++struct fuse_notify_retrieve_out { ++ uint64_t notify_unique; ++ uint64_t nodeid; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++/* Matches the size of fuse_write_in */ ++struct fuse_notify_retrieve_in { ++ uint64_t dummy1; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t dummy2; ++ uint64_t dummy3; ++ uint64_t dummy4; ++}; ++ ++struct fuse_backing_map { ++ int32_t fd; ++ uint32_t flags; ++ uint64_t padding; ++}; ++ ++/* Device ioctls: */ ++#define FUSE_DEV_IOC_MAGIC 229 ++#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t) ++#define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \ ++ struct fuse_backing_map) ++#define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t) ++ ++struct fuse_lseek_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint32_t whence; ++ uint32_t padding; ++}; ++ ++struct fuse_lseek_out { ++ uint64_t offset; ++}; ++ ++struct fuse_copy_file_range_in { ++ uint64_t fh_in; ++ uint64_t off_in; ++ uint64_t nodeid_out; ++ uint64_t fh_out; ++ uint64_t off_out; ++ uint64_t len; ++ uint64_t flags; ++}; ++ ++#define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0) ++#define FUSE_SETUPMAPPING_FLAG_READ (1ull << 1) ++struct fuse_setupmapping_in { ++ /* An already open handle */ ++ uint64_t fh; ++ /* Offset into the file to start the mapping */ ++ uint64_t foffset; ++ /* Length of mapping required */ ++ uint64_t len; ++ /* Flags, FUSE_SETUPMAPPING_FLAG_* */ ++ uint64_t flags; ++ /* Offset in Memory Window */ ++ uint64_t moffset; ++}; ++ ++struct fuse_removemapping_in { ++ /* number of fuse_removemapping_one follows */ ++ uint32_t count; ++}; ++ ++struct fuse_removemapping_one { ++ /* Offset into the dax window start the unmapping */ ++ uint64_t moffset; ++ /* Length of mapping required */ ++ uint64_t len; ++}; ++ ++#define FUSE_REMOVEMAPPING_MAX_ENTRY \ ++ (PAGE_SIZE / sizeof(struct fuse_removemapping_one)) ++ ++struct fuse_syncfs_in { ++ uint64_t padding; ++}; ++ ++/* ++ * For each security context, send fuse_secctx with size of security context ++ * fuse_secctx will be followed by security context name and this in turn ++ * will be followed by actual context label. ++ * fuse_secctx, name, context ++ */ ++struct fuse_secctx { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++/* ++ * Contains the information about how many fuse_secctx structures are being ++ * sent and what's the total size of all security contexts (including ++ * size of fuse_secctx_header). ++ * ++ */ ++struct fuse_secctx_header { ++ uint32_t size; ++ uint32_t nr_secctx; ++}; ++ ++/** ++ * struct fuse_ext_header - extension header ++ * @size: total size of this extension including this header ++ * @type: type of extension ++ * ++ * This is made compatible with fuse_secctx_header by using type values > ++ * FUSE_MAX_NR_SECCTX ++ */ ++struct fuse_ext_header { ++ uint32_t size; ++ uint32_t type; ++}; ++ ++/** ++ * struct fuse_supp_groups - Supplementary group extension ++ * @nr_groups: number of supplementary groups ++ * @groups: flexible array of group IDs ++ */ ++struct fuse_supp_groups { ++ uint32_t nr_groups; ++ uint32_t groups[]; ++}; ++ ++#endif /* _LINUX_FUSE_H */ +-- +2.43.5 + diff --git a/glibc-RHEL-50545-9.patch b/glibc-RHEL-50545-9.patch new file mode 100644 index 0000000..4127da1 --- /dev/null +++ b/glibc-RHEL-50545-9.patch @@ -0,0 +1,438 @@ +From 3b1d32177635023e37bec7fbfd77c3cfb2659eb1 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 30 Aug 2024 21:52:10 +0200 +Subject: [PATCH] support: Add +Content-type: text/plain; charset=UTF-8 + +Use static functions for readdir/readdir_r, so that +-D_FILE_OFFSET_BITS=64 does not improperly redirect calls to the wrong +implementation. + +Reviewed-by: DJ Delorie + +Conflicts + support/Makefile + context +--- + support/Makefile | 6 +++ + support/support_readdir_check.c | 30 +++++++++++ + support/support_readdir_r_check.c | 35 +++++++++++++ + support/tst-xdirent.c | 76 +++++++++++++++++++++++++++ + support/xclosedir.c | 28 ++++++++++ + support/xdirent.h | 86 +++++++++++++++++++++++++++++++ + support/xfdopendir.c | 30 +++++++++++ + support/xopendir.c | 30 +++++++++++ + 8 files changed, 321 insertions(+) + create mode 100644 support/support_readdir_check.c + create mode 100644 support/support_readdir_r_check.c + create mode 100644 support/tst-xdirent.c + create mode 100644 support/xclosedir.c + create mode 100644 support/xdirent.h + create mode 100644 support/xfdopendir.c + create mode 100644 support/xopendir.c + +diff --git a/support/Makefile b/support/Makefile +index 26bd3d38e4..8fb4d2c500 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -73,6 +73,8 @@ libsupport-routines = \ + support_quote_blob \ + support_quote_blob_wide \ + support_quote_string \ ++ support_readdir_check \ ++ support_readdir_r_check \ + support_record_failure \ + support_run_diff \ + support_select_modifies_timeout \ +@@ -112,6 +114,7 @@ libsupport-routines = \ + xclock_settime_time64 \ + xclone \ + xclose \ ++ xclosedir \ + xchmod \ + xconnect \ + xcopy_file_range \ +@@ -120,6 +123,7 @@ libsupport-routines = \ + xdup2 \ + xfchmod \ + xfclose \ ++ xfdopendir \ + xfopen \ + xfork \ + xftruncate \ +@@ -137,6 +141,7 @@ libsupport-routines = \ + xmunmap \ + xnewlocale \ + xopen \ ++ xopendir \ + xpipe \ + xpoll \ + xposix_memalign \ +@@ -306,6 +311,7 @@ tests = \ + tst-test_compare_string \ + tst-test_compare_string_wide \ + tst-timespec \ ++ tst-xdirent \ + tst-xreadlink \ + tst-xsigstack \ + +diff --git a/support/support_readdir_check.c b/support/support_readdir_check.c +new file mode 100644 +index 0000000000..5687004276 +--- /dev/null ++++ b/support/support_readdir_check.c +@@ -0,0 +1,30 @@ ++/* Error-checking helper for xreaddir, xreaddir64. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++void * ++support_readdir_check (const char *name, void *result, int saved_errno) ++{ ++ if (result == NULL && errno != 0) ++ FAIL_EXIT1 ("%s: %m", name); ++ errno = saved_errno; ++ return result; ++} +diff --git a/support/support_readdir_r_check.c b/support/support_readdir_r_check.c +new file mode 100644 +index 0000000000..6bbb0d0b32 +--- /dev/null ++++ b/support/support_readdir_r_check.c +@@ -0,0 +1,35 @@ ++/* Error-checking helper for xreaddir_r, xreaddir64_r. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++int ++support_readdir_r_check (const char *name, int result, void *buf, void *ptr) ++{ ++ if (result != 0) ++ { ++ errno = result; ++ FAIL_EXIT1 ("%s: %m", name); ++ } ++ if (buf != ptr) ++ FAIL_EXIT1 ("%s: buffer pointer and returned pointer differ: %p != %p", ++ name, buf, ptr); ++ return result; ++} +diff --git a/support/tst-xdirent.c b/support/tst-xdirent.c +new file mode 100644 +index 0000000000..642483165a +--- /dev/null ++++ b/support/tst-xdirent.c +@@ -0,0 +1,76 @@ ++/* Compile test for error-checking wrappers for ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ { ++ DIR *d = xopendir ("."); ++ struct dirent *e = xreaddir (d); ++ /* Assume that the "." special entry always comes first. */ ++ TEST_COMPARE_STRING (e->d_name, "."); ++ while (xreaddir (d) != NULL) ++ ; ++ xclosedir (d); ++ } ++ ++ { ++ DIR *d = xopendir ("."); ++ struct dirent64 *e = xreaddir64 (d); ++ TEST_COMPARE_STRING (e->d_name, "."); ++ while (xreaddir64 (d) != NULL) ++ ; ++ xclosedir (d); ++ } ++ ++ /* The functions readdir_r, readdir64_r were deprecated in glibc 2.24. */ ++ DIAG_PUSH_NEEDS_COMMENT; ++ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations"); ++ ++ { ++ DIR *d = xopendir ("."); ++ struct dirent buf = { 0, }; ++ TEST_VERIFY (xreaddir_r (d, &buf)); ++ TEST_COMPARE_STRING (buf.d_name, "."); ++ while (xreaddir_r (d, &buf)) ++ ; ++ xclosedir (d); ++ } ++ ++ { ++ DIR *d = xopendir ("."); ++ struct dirent64 buf = { 0, }; ++ TEST_VERIFY (xreaddir64_r (d, &buf)); ++ TEST_COMPARE_STRING (buf.d_name, "."); ++ while (xreaddir64_r (d, &buf)) ++ ; ++ xclosedir (d); ++ } ++ ++ DIAG_POP_NEEDS_COMMENT; ++ ++ return 0; ++} ++ ++#include +diff --git a/support/xclosedir.c b/support/xclosedir.c +new file mode 100644 +index 0000000000..b490df5598 +--- /dev/null ++++ b/support/xclosedir.c +@@ -0,0 +1,28 @@ ++/* Error-checking wrapper for closedir. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++void ++xclosedir (DIR *dir) ++{ ++ if (closedir (dir) != 0) ++ FAIL_EXIT1 ("closedir: %m"); ++} +diff --git a/support/xdirent.h b/support/xdirent.h +new file mode 100644 +index 0000000000..8465d70ec1 +--- /dev/null ++++ b/support/xdirent.h +@@ -0,0 +1,86 @@ ++/* Error-checking wrappers for ++ Copyright (C) 2024 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 ++ . */ ++ ++#ifndef SUPPORT_XDIRENT_H ++#define SUPPORT_XDIRENT_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++__BEGIN_DECLS ++ ++DIR *xopendir (const char *path); ++DIR *xfdopendir (int fd); ++void xclosedir (DIR *); ++ ++void *support_readdir_check (const char *, void *, int); ++ ++static __attribute__ ((unused)) struct dirent * ++xreaddir (DIR *stream) ++{ ++ int saved_errno = errno; ++ errno = 0; ++ struct dirent *result = readdir (stream); ++ return support_readdir_check ("readdir", result, saved_errno); ++} ++ ++static __attribute__ ((unused)) struct dirent64 * ++xreaddir64 (DIR *stream) ++{ ++ int saved_errno = errno; ++ errno = 0; ++ struct dirent64 *result = readdir64 (stream); ++ return support_readdir_check ("readdir64", result, saved_errno); ++} ++ ++/* The functions readdir_r, readdir64_r were deprecated in glibc 2.24. */ ++DIAG_PUSH_NEEDS_COMMENT; ++DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations"); ++ ++int support_readdir_r_check (const char *, int, void *, void *); ++ ++static __attribute__ ((unused)) bool ++xreaddir_r (DIR *stream, struct dirent *buf) ++{ ++ struct dirent *ptr; ++ int ret = readdir_r (stream, buf, &ptr); ++ if (ret == 0 && ptr == NULL) ++ return false; ++ support_readdir_r_check ("readdir_r", ret, buf, ptr); ++ return true; ++} ++ ++static __attribute__ ((unused)) bool ++xreaddir64_r (DIR *stream, struct dirent64 *buf) ++{ ++ struct dirent64 *ptr; ++ int ret = readdir64_r (stream, buf, &ptr); ++ if (ret == 0 && ptr == NULL) ++ return false; ++ support_readdir_r_check ("readdir64_r", ret, buf, ptr); ++ return true; ++} ++ ++DIAG_POP_NEEDS_COMMENT; ++ ++__END_DECLS ++ ++#endif /* SUPPORT_XDIRENT_H */ +diff --git a/support/xfdopendir.c b/support/xfdopendir.c +new file mode 100644 +index 0000000000..d881d28c73 +--- /dev/null ++++ b/support/xfdopendir.c +@@ -0,0 +1,30 @@ ++/* Error-checking wrapper for fdopendir. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++DIR * ++xfdopendir (int fd) ++{ ++ DIR *result = fdopendir (fd); ++ if (result == NULL) ++ FAIL_EXIT1 ("fdopendir (%d): %m", fd); ++ return result; ++} +diff --git a/support/xopendir.c b/support/xopendir.c +new file mode 100644 +index 0000000000..e4aee07fee +--- /dev/null ++++ b/support/xopendir.c +@@ -0,0 +1,30 @@ ++/* Error-checking wrapper for opendir. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++DIR * ++xopendir (const char *path) ++{ ++ DIR *result = opendir (path); ++ if (result == NULL) ++ FAIL_EXIT1 ("opendir (\"%s\"): %m", path); ++ return result; ++} +-- +2.43.5 + diff --git a/glibc.spec b/glibc.spec index 5c907a1..e4a15ad 100644 --- a/glibc.spec +++ b/glibc.spec @@ -157,7 +157,7 @@ end \ Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: 133%{?dist} +Release: 134%{?dist} # In general, GPLv2+ is used by programs, LGPLv2+ is used for # libraries. @@ -889,6 +889,20 @@ Patch650: glibc-RHEL-46739-8.patch Patch651: glibc-RHEL-46739-9.patch Patch652: glibc-RHEL-46739-10.patch Patch653: glibc-RHEL-46739-11.patch +Patch654: glibc-RHEL-50545-1.patch +Patch655: glibc-RHEL-50545-2.patch +Patch656: glibc-RHEL-50545-3.patch +Patch657: glibc-RHEL-50545-4.patch +Patch658: glibc-RHEL-50545-5.patch +Patch659: glibc-RHEL-50545-6.patch +Patch660: glibc-RHEL-50545-7.patch +Patch661: glibc-RHEL-50545-8.patch +Patch662: glibc-RHEL-50545-9.patch +Patch663: glibc-RHEL-50545-10.patch +Patch664: glibc-RHEL-50545-11.patch +Patch665: glibc-RHEL-50545-12.patch +Patch666: glibc-RHEL-50545-13.patch +Patch667: glibc-RHEL-50545-14.patch ############################################################################## # Continued list of core "glibc" package information: @@ -3048,6 +3062,10 @@ update_gconv_modules_cache () %endif %changelog +* Wed Oct 23 2024 DJ Delorie - 2.34-134 +- Test Implementation to verify mkstemp behavior, + with FUSE support (RHEL-50545) + * Mon Sep 30 2024 Arjun Shankar - 2.34-133 - strtod: Fix subnormal rounding; do not set errno upon overflowing payload; and add several new tests (RHEL-46739)