about summary refs log tree commit diff
path: root/io
diff options
context:
space:
mode:
Diffstat (limited to 'io')
-rw-r--r--io/Makefile6
-rw-r--r--io/bits/statx-generic.h3
-rw-r--r--io/tst-copy_file_range.c2
-rw-r--r--io/tst-fchmod-errors.c63
-rw-r--r--io/tst-fchmod-fuse.c114
-rw-r--r--io/tst-futimens-time64.c1
-rw-r--r--io/tst-futimens.c13
-rw-r--r--io/tst-futimes-time64.c1
-rw-r--r--io/tst-futimes.c13
-rw-r--r--io/tst-futimesat-time64.c3
-rw-r--r--io/tst-futimesat.c30
-rw-r--r--io/tst-lstat-nofollow-time64.c1
-rw-r--r--io/tst-lstat-nofollow.c98
-rw-r--r--io/tst-lutimes-time64.c1
-rw-r--r--io/tst-lutimes.c26
-rw-r--r--io/tst-mkdirat.c42
-rw-r--r--io/tst-statx.c4
-rw-r--r--io/tst-utime-time64.c1
-rw-r--r--io/tst-utime.c13
-rw-r--r--io/tst-utimensat-time64.c1
-rw-r--r--io/tst-utimensat.c35
-rw-r--r--io/tst-utimes-time64.c1
-rw-r--r--io/tst-utimes.c13
23 files changed, 386 insertions, 99 deletions
diff --git a/io/Makefile b/io/Makefile
index 19932d50f7..a8d575e9ce 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -188,6 +188,8 @@ tests := \
   tst-closefrom \
   tst-copy_file_range \
   tst-faccessat \
+  tst-fchmod-errors \
+  tst-fchmod-fuse \
   tst-fchmodat \
   tst-fchownat \
   tst-fcntl \
@@ -207,6 +209,7 @@ tests := \
   tst-lchmod \
   tst-linkat \
   tst-lockf \
+  tst-lstat-nofollow \
   tst-lutimes \
   tst-mkdirat \
   tst-mkfifoat \
@@ -236,6 +239,7 @@ tests-time64 := \
   tst-futimes-time64\
   tst-futimesat-time64 \
   tst-lchmod-time64 \
+  tst-lstat-nofollow-time64 \
   tst-lutimes-time64 \
   tst-stat-time64 \
   tst-utime-time64 \
@@ -291,7 +295,7 @@ CFLAGS-read.c += -fexceptions -fasynchronous-unwind-tables $(config-cflags-wno-i
 CFLAGS-write.c += -fexceptions -fasynchronous-unwind-tables $(config-cflags-wno-ignored-attributes)
 CFLAGS-close.c += -fexceptions -fasynchronous-unwind-tables
 CFLAGS-lseek64.c += $(config-cflags-wno-ignored-attributes)
-CFLAGS-tst-read-zero.c += $(no-fortify-source),-D_FORTIFY_SOURCE=$(supported-fortify)
+CFLAGS-tst-read-zero.c += $(no-fortify-source) -D_FORTIFY_SOURCE=$(supported-fortify)
 
 CFLAGS-test-stat.c += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
 CFLAGS-test-lfs.c += -D_LARGEFILE64_SOURCE
diff --git a/io/bits/statx-generic.h b/io/bits/statx-generic.h
index 30a24765dc..da199ddaa1 100644
--- a/io/bits/statx-generic.h
+++ b/io/bits/statx-generic.h
@@ -43,6 +43,8 @@
 # define STATX_MNT_ID 0x1000U
 # define STATX_DIOALIGN 0x2000U
 # define STATX_MNT_ID_UNIQUE 0x4000U
+# define STATX_SUBVOL 0x8000U
+# define STATX_WRITE_ATOMIC 0x00010000U
 # define STATX__RESERVED 0x80000000U
 
 # define STATX_ATTR_COMPRESSED 0x0004
@@ -54,6 +56,7 @@
 # define STATX_ATTR_MOUNT_ROOT 0x2000
 # define STATX_ATTR_VERITY 0x100000
 # define STATX_ATTR_DAX 0x200000
+# define STATX_ATTR_WRITE_ATOMIC 0x00400000
 #endif /* !STATX_TYPE */
 
 __BEGIN_DECLS
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-fchmod-errors.c b/io/tst-fchmod-errors.c
new file mode 100644
index 0000000000..bf2a4c568e
--- /dev/null
+++ b/io/tst-fchmod-errors.c
@@ -0,0 +1,63 @@
+/* Test various fchmod error cases.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+  {
+    /* Permissions on /dev/null (the opened descriptor) cannot be changed.  */
+    int fd = xopen ("/dev/null", O_RDWR, 0);
+    if (getuid () == 0)
+      puts ("info: /dev/null fchmod test skipped because of root privileges");
+    else
+      {
+        errno = 0;
+        TEST_COMPARE (fchmod (fd, 0), -1);
+        TEST_COMPARE (errno, EPERM);
+      }
+    xclose (fd);
+
+    /* Now testing an invalid file descriptor.   */
+    errno = 0;
+    TEST_COMPARE (fchmod (fd, 0600), -1);
+    TEST_COMPARE (errno, EBADF);
+  }
+
+  errno = 0;
+  TEST_COMPARE (fchmod (-1, 0600), -1);
+  TEST_COMPARE (errno, EBADF);
+
+  errno = 0;
+  TEST_COMPARE (fchmod (AT_FDCWD, 0600), -1);
+  TEST_COMPARE (errno, EBADF);
+
+  /* Linux supports fchmod on pretty much all file descriptors, so
+     there is no check for failure on specific types of descriptors
+     here.  */
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/io/tst-fchmod-fuse.c b/io/tst-fchmod-fuse.c
new file mode 100644
index 0000000000..fbd3309963
--- /dev/null
+++ b/io/tst-fchmod-fuse.c
@@ -0,0 +1,114 @@
+/* FUSE-based test for fchmod.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/fuse.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+
+/* Set from do_test to indicate the expected incoming mode change request.  */
+static _Atomic int expected_mode;
+
+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;
+      switch (inh->opcode)
+        {
+        case FUSE_LOOKUP:
+          {
+            char *name = support_fuse_cast (LOOKUP, inh);
+            TEST_COMPARE_STRING (name, "file");
+            struct fuse_entry_out *out
+              = support_fuse_prepare_entry (f, 2);
+            out->attr.mode = S_IFREG | 0600;
+            support_fuse_reply_prepared (f);
+          }
+          break;
+        case FUSE_OPEN:
+          {
+            TEST_COMPARE (inh->nodeid, 2);
+            struct fuse_open_in *p = support_fuse_cast (OPEN, inh);
+            TEST_COMPARE (p->flags & O_ACCMODE, O_RDWR);
+            struct fuse_open_out out = { 0, };
+            support_fuse_reply (f, &out, sizeof (out));
+          }
+          break;
+        case FUSE_SETATTR:
+          {
+            TEST_COMPARE (inh->nodeid, 2);
+            struct fuse_setattr_in *p = support_fuse_cast (SETATTR, inh);
+            TEST_COMPARE (p->valid , FATTR_MODE);
+            TEST_COMPARE (p->mode, S_IFREG | expected_mode);
+            struct fuse_attr_out *out = support_fuse_prepare_attr (f);
+            out->attr.mode = S_IFREG | p->mode;
+            support_fuse_reply_prepared (f);
+          }
+          break;
+        case FUSE_FLUSH:
+          support_fuse_reply_empty (f);
+          break;
+        default:
+          support_fuse_reply_error (f, EIO);
+        }
+    }
+}
+
+/* Test all mode values with the specified extra bits.  */
+static void
+test_with_bits (int fd, unsigned int extra_bits)
+{
+  for (int do_mode = 0; do_mode <= 07777; ++do_mode)
+    {
+      expected_mode = do_mode;
+      TEST_COMPARE (fchmod (fd, extra_bits | do_mode), 0);
+    }
+}
+
+static int
+do_test (void)
+{
+  support_fuse_init ();
+
+  struct support_fuse *f = support_fuse_mount (fuse_thread, NULL);
+  char *path = xasprintf ("%s/file", support_fuse_mountpoint (f));
+  int fd = xopen (path, O_RDWR, 0600);
+  free (path);
+
+  test_with_bits (fd, 0);
+  /* POSIX requires that the extra bits are ignored.  */
+  test_with_bits (fd, S_IFREG);
+  test_with_bits (fd, S_IFDIR);
+  test_with_bits (fd, ~07777);
+
+  xclose (fd);
+  support_fuse_unmount (f);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
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 <support/check.h>
 #include <support/xunistd.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 
-#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 <support/check.h>
 #include <support/xunistd.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 
-#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 <support/temp_file.h>
 #include <support/xunistd.h>
 
-#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-lstat-nofollow-time64.c b/io/tst-lstat-nofollow-time64.c
new file mode 100644
index 0000000000..45feb3f130
--- /dev/null
+++ b/io/tst-lstat-nofollow-time64.c
@@ -0,0 +1 @@
+#include "tst-lstat-nofollow.c"
diff --git a/io/tst-lstat-nofollow.c b/io/tst-lstat-nofollow.c
new file mode 100644
index 0000000000..5bbb557c72
--- /dev/null
+++ b/io/tst-lstat-nofollow.c
@@ -0,0 +1,98 @@
+/* Test that lstat does not follow symbolic links.
+   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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <string.h>
+#include <support/check.h>
+#include <support/fuse.h>
+#include <support/support.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+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;
+      switch (inh->opcode)
+        {
+        case FUSE_LOOKUP:
+          {
+            TEST_COMPARE (inh->nodeid, 1);
+            TEST_COMPARE_STRING (support_fuse_cast (LOOKUP, inh), "symlink");
+            struct fuse_entry_out *out = support_fuse_prepare_entry (f, 2);
+            out->attr.mode = S_IFLNK | 0777;
+            out->attr.size = strlen ("target");
+            support_fuse_reply_prepared (f);
+          }
+          break;
+        case FUSE_GETATTR:
+          {
+            TEST_COMPARE (inh->nodeid, 2);
+            struct fuse_attr_out *out = support_fuse_prepare_attr (f);
+            out->attr.mode = S_IFLNK | 0777;
+            out->attr.size = strlen ("target");
+            support_fuse_reply_prepared (f);
+          }
+          break;
+        case FUSE_READLINK:
+          /* The lstat operation must not attempt to look at the
+             symbolic link target.  */
+          FAIL ("attempt to obtain target of symblic link for node %llu",
+                (unsigned long long int) inh->nodeid);
+          break;
+        default:
+          FAIL ("unexpected event %s", support_fuse_opcode (inh->opcode));
+        }
+    }
+}
+
+static int
+do_test (void)
+{
+  support_fuse_init ();
+  struct support_fuse *f = support_fuse_mount (fuse_thread, NULL);
+  char *symlink_path = xasprintf ("%s/symlink", support_fuse_mountpoint (f));
+
+  {
+    struct stat st = { 0, };
+    TEST_COMPARE (lstat (symlink_path, &st), 0);
+    TEST_COMPARE (st.st_uid, getuid ());
+    TEST_COMPARE (st.st_gid, getgid ());
+    TEST_COMPARE (st.st_size, 6);
+    TEST_COMPARE (st.st_mode, S_IFLNK | 0777);
+  }
+
+  {
+    struct stat64 st = { 0, };
+    TEST_COMPARE (lstat64 (symlink_path, &st), 0);
+    TEST_COMPARE (st.st_uid, getuid ());
+    TEST_COMPARE (st.st_gid, getgid ());
+    TEST_COMPARE (st.st_size, 6);
+    TEST_COMPARE (st.st_mode, S_IFLNK | 0777);
+  }
+
+  free (symlink_path);
+  support_fuse_unmount (f);
+  return 0;
+}
+
+#include <support/test-driver.c>
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 <support/check.h>
 #include <support/xunistd.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 
-#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-mkdirat.c b/io/tst-mkdirat.c
index 605e51ef1e..b97bc3ca6d 100644
--- a/io/tst-mkdirat.c
+++ b/io/tst-mkdirat.c
@@ -53,6 +53,10 @@ prepare (void)
 static int
 do_test (void)
 {
+  /* Find the current umask.  */
+  mode_t mask = umask (022);
+  umask (mask);
+
   /* fdopendir takes over the descriptor, make a copy.  */
   int dupfd = dup (dir_fd);
   if (dupfd == -1)
@@ -107,6 +111,13 @@ do_test (void)
       puts ("mkdirat did not create a directory");
       return 1;
     }
+  if ((st1.st_mode & 01777) != (~mask & 0777))
+    {
+      printf ("mkdirat created directory with wrong mode %o, expected %o\n",
+	      (unsigned int) (st1.st_mode & 01777),
+	      (unsigned int) (~mask & 0777));
+      return 1;
+    }
 
   dupfd = dup (dir_fd);
   if (dupfd == -1)
@@ -156,6 +167,37 @@ do_test (void)
       return 1;
     }
 
+  /* Test again with a different mode.  */
+  umask (0);
+  e = mkdirat (dir_fd, "some-dir", 01755);
+  umask (mask);
+  if (e == -1)
+    {
+      puts ("directory creation (different mode) failed");
+      return 1;
+    }
+  if (fstatat64 (dir_fd, "some-dir", &st1, 0) != 0)
+    {
+      puts ("fstat64 (different mode) failed");
+      return 1;
+    }
+  if (!S_ISDIR (st1.st_mode))
+    {
+      puts ("mkdirat (different mode) did not create a directory");
+      return 1;
+    }
+  if ((st1.st_mode & 01777) != 01755)
+    {
+      printf ("mkdirat (different mode) created directory with wrong mode %o\n",
+	      (unsigned int) (st1.st_mode & 01777));
+      return 1;
+    }
+  if (unlinkat (dir_fd, "some-dir", AT_REMOVEDIR) != 0)
+    {
+      puts ("unlinkat (different mode) failed");
+      return 1;
+    }
+
   close (dir_fd);
 
   return 0;
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/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 <utime.h>
 #include <support/check.h>
 #include <support/xunistd.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 
-#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 <sys/stat.h>
 #include <sys/time.h>
 
-#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 <support/check.h>
 #include <support/xunistd.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <time.h>
 
-#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;
 }