]> sourceware.org Git - glibc.git/blobdiff - io/tst-open-tmpfile.c
support: Use macros for *stat wrappers
[glibc.git] / io / tst-open-tmpfile.c
index 9af1875ba2a7fdd0f88195646154d6576243d550..a2e4bb90df4813bb7bcb52541bbbcf1d19048716 100644 (file)
@@ -1,5 +1,5 @@
 /* Test open and openat with O_TMPFILE.
-   Copyright (C) 2016 Free Software Foundation, Inc.
+   Copyright (C) 2016-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
@@ -14,7 +14,7 @@
 
    You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
+   <https://www.gnu.org/licenses/>.  */
 
 /* This test verifies that open and openat work as expected, i.e. they
    create a deleted file with the requested file mode.  */
 #include <sys/stat.h>
 #include <unistd.h>
 
-static int do_test (void);
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/support.h>
 
 #ifdef O_TMPFILE
 typedef int (*wrapper_func) (const char *, int, mode_t);
@@ -64,10 +61,38 @@ wrap_openat (const char *path, int flags, mode_t mode)
   return ret;
 }
 
+/* Error-checking wrapper for the open64 function, compatible with the
+   wrapper_func type.  */
+static int
+wrap_open64 (const char *path, int flags, mode_t mode)
+{
+  int ret = open64 (path, flags, mode);
+  if (ret < 0)
+    {
+      printf ("error: open64 (\"%s\", 0x%x, 0%03o): %m\n", path, flags, mode);
+      exit (1);
+    }
+  return ret;
+}
+
+/* Error-checking wrapper for the openat64 function, compatible with the
+   wrapper_func type.  */
+static int
+wrap_openat64 (const char *path, int flags, mode_t mode)
+{
+  int ret = openat64 (AT_FDCWD, path, flags, mode);
+  if (ret < 0)
+    {
+      printf ("error: openat64 (\"%s\", 0x%x, 0%03o): %m\n", path, flags, mode);
+      exit (1);
+    }
+  return ret;
+}
+
 /* Return true if FD is flagged as deleted in /proc/self/fd, false if
    not.  */
 static bool
-is_file_deteted (int fd)
+is_file_deleted (int fd)
 {
   char *proc_fd_path = xasprintf ("/proc/self/fd/%d", fd);
   char file_path[4096];
@@ -97,6 +122,32 @@ is_file_deteted (int fd)
               deleted, strlen (deleted)) == 0;
 }
 
+/* Obtain a file name which is difficult to guess.  */
+static char *
+get_random_name (void)
+{
+  unsigned long long bytes[2];
+  int random_device = open ("/dev/urandom", O_RDONLY);
+  if (random_device < 0)
+    {
+      printf ("error: open (\"/dev/urandom\"): %m\n");
+      exit (1);
+    }
+  ssize_t ret = read (random_device, bytes, sizeof (bytes));
+  if (ret < 0)
+    {
+      printf ("error: read (\"/dev/urandom\"): %m\n");
+      exit (1);
+    }
+  if (ret != sizeof (bytes))
+    {
+      printf ("error: short read from /dev/urandom: %zd\n", ret);
+      exit (1);
+    }
+  close (random_device);
+  return xasprintf ("tst-open-tmpfile-%08llx%08llx.tmp", bytes[0], bytes[1]);
+}
+
 /* Check open/openat (as specified by OP and WRAPPER) with a specific
    PATH/FLAGS/MODE combination.  */
 static void
@@ -121,12 +172,59 @@ check_wrapper_flags_mode (const char *op, wrapper_func wrapper,
     }
 
   /* Check that the file is marked as deleted in /proc.  */
-  if (!is_file_deteted (fd))
+  if (!is_file_deleted (fd))
     {
       printf ("error: path in /proc is not marked as deleted\n");
       exit (1);
     }
 
+  /* Check that the file can be turned into a regular file with
+     linkat.  Open a file descriptor for the directory at PATH.  Use
+     AT_FDCWD if PATH is ".", to exercise that functionality as
+     well.  */
+  int path_fd;
+  if (strcmp (path, ".") == 0)
+    path_fd = AT_FDCWD;
+  else
+    {
+      path_fd = open (path, O_RDONLY | O_DIRECTORY);
+      if (path_fd < 0)
+        {
+          printf ("error: open (\"%s\"): %m\n", path);
+          exit (1);
+        }
+    }
+
+  /* Use a hard-to-guess name for the new directory entry.  */
+  char *new_name = get_random_name ();
+
+  /* linkat does not require privileges if the path in /proc/self/fd
+     is used.  */
+  char *proc_fd_path = xasprintf ("/proc/self/fd/%d", fd);
+  if (linkat (AT_FDCWD, proc_fd_path, path_fd, new_name,
+              AT_SYMLINK_FOLLOW) == 0)
+    {
+      if (unlinkat (path_fd, new_name, 0) != 0 && errno != ENOENT)
+        {
+          printf ("error: unlinkat (\"%s/%s\"): %m\n", path, new_name);
+          exit (1);
+        }
+    }
+  else
+    {
+      /* linkat failed.  This is expected if O_EXCL was specified.  */
+      if ((flags & O_EXCL) == 0)
+        {
+          printf ("error: linkat failed after %s (\"%s\", 0x%x, 0%03o): %m\n",
+                  op, path, flags, mode);
+          exit (1);
+        }
+    }
+
+  free (proc_fd_path);
+  free (new_name);
+  if (path_fd != AT_FDCWD)
+    close (path_fd);
   close (fd);
 }
 
@@ -197,6 +295,8 @@ do_test (void)
         supported = true;
         check_wrapper ("open", wrap_open, paths[i]);
         check_wrapper ("openat", wrap_openat, paths[i]);
+        check_wrapper ("open64", wrap_open64, paths[i]);
+        check_wrapper ("openat64", wrap_openat64, paths[i]);
       }
 
   if (!supported)
@@ -214,3 +314,5 @@ do_test (void)
 }
 
 #endif  /* O_TMPFILE */
+
+#include <support/test-driver.c>
This page took 0.031632 seconds and 5 git commands to generate.