1 /* Basic test of statx system call.
2    Copyright (C) 2018-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <stdbool.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <support/check.h>
25 #include <support/support.h>
26 #include <support/temp_file.h>
27 #include <support/xunistd.h>
28 #include <sys/stat.h>
29 #include <sys/syscall.h>
30 #include <sys/sysmacros.h>
31 #include <unistd.h>
32 
33 /* Ensure that the types have the kernel-expected layout.  */
34 _Static_assert (sizeof (struct statx_timestamp) == 16, "statx_timestamp size");
35 _Static_assert (sizeof (struct statx) == 256, "statx size");
36 _Static_assert (offsetof (struct statx, stx_nlink) == 16, "statx nlink");
37 _Static_assert (offsetof (struct statx, stx_ino) == 32, "statx ino");
38 _Static_assert (offsetof (struct statx, stx_atime) == 64, "statx atime");
39 _Static_assert (offsetof (struct statx, stx_rdev_major) == 128, "statx rdev");
40 _Static_assert (offsetof (struct statx, __statx_pad2) == 144, "statx pad2");
41 
42 #include "statx_generic.c"
43 
44 typedef int (*statx_function) (int, const char *, int, unsigned int,
45                                struct statx *);
46 
47 /* Return true if we have a real implementation of statx.  */
48 static bool
kernel_supports_statx(void)49 kernel_supports_statx (void)
50 {
51 #ifdef __NR_statx
52   struct statx buf;
53   return syscall (__NR_statx, 0, "", AT_EMPTY_PATH, 0, &buf) == 0
54     || errno != ENOSYS;
55 #else
56   return false;
57 #endif
58 }
59 
60 /* Tests which apply to both implementations.  */
61 static void
both_implementations_tests(statx_function impl,const char * path,int fd)62 both_implementations_tests (statx_function impl, const char *path, int fd)
63 {
64   uint64_t ino;
65   {
66     struct statx buf = { 0, };
67     TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &buf), 0);
68     TEST_COMPARE (buf.stx_size, 3);
69     ino = buf.stx_ino;
70   }
71   {
72     struct statx buf = { 0, };
73     TEST_COMPARE (statx (AT_FDCWD, path, 0, STATX_BASIC_STATS, &buf), 0);
74     TEST_COMPARE (buf.stx_size, 3);
75     TEST_COMPARE (buf.stx_ino, ino);
76   }
77   {
78     struct statx stx = { 0, };
79     TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &stx), 0);
80     struct stat64 st;
81     xfstat (fd, &st);
82     TEST_COMPARE (stx.stx_mode, st.st_mode);
83     TEST_COMPARE (stx.stx_dev_major, major (st.st_dev));
84     TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev));
85   }
86   {
87     struct statx stx = { 0, };
88     TEST_COMPARE (statx (AT_FDCWD, "/dev/null", 0, STATX_BASIC_STATS, &stx),
89                   0);
90     struct stat64 st;
91     xstat ("/dev/null", &st);
92     TEST_COMPARE (stx.stx_mode, st.st_mode);
93     TEST_COMPARE (stx.stx_dev_major, major (st.st_dev));
94     TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev));
95     TEST_COMPARE (stx.stx_rdev_major, major (st.st_rdev));
96     TEST_COMPARE (stx.stx_rdev_minor, minor (st.st_rdev));
97   }
98 }
99 
100 /* Tests which apply only to the non-kernel (generic)
101    implementation.  */
102 static void
non_kernel_tests(statx_function impl,int fd)103 non_kernel_tests (statx_function impl, int fd)
104 {
105   /* The non-kernel implementation must always fail for explicit sync
106      flags.  */
107   struct statx buf;
108   errno = 0;
109   TEST_COMPARE (impl (fd, "", AT_EMPTY_PATH | AT_STATX_FORCE_SYNC,
110                       STATX_BASIC_STATS, &buf), -1);
111   TEST_COMPARE (errno, EINVAL);
112   errno = 0;
113   TEST_COMPARE (impl (fd, "", AT_EMPTY_PATH | AT_STATX_DONT_SYNC,
114                       STATX_BASIC_STATS, &buf), -1);
115   TEST_COMPARE (errno, EINVAL);
116 }
117 
118 static int
do_test(void)119 do_test (void)
120 {
121   char *path;
122   int fd = create_temp_file ("tst-statx-", &path);
123   TEST_VERIFY_EXIT (fd >= 0);
124   support_write_file_string (path, "abc");
125 
126   both_implementations_tests (&statx, path, fd);
127   both_implementations_tests (&statx_generic, path, fd);
128 
129   if (kernel_supports_statx ())
130     {
131       puts ("info: kernel supports statx");
132       struct statx buf;
133       buf.stx_size = 0;
134       TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH | AT_STATX_FORCE_SYNC,
135                            STATX_BASIC_STATS, &buf),
136                     0);
137       TEST_COMPARE (buf.stx_size, 3);
138       buf.stx_size = 0;
139       TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH | AT_STATX_DONT_SYNC,
140                            STATX_BASIC_STATS, &buf),
141                     0);
142       TEST_COMPARE (buf.stx_size, 3);
143     }
144   else
145     {
146       puts ("info: kernel does not support statx");
147       non_kernel_tests (&statx, fd);
148     }
149   non_kernel_tests (&statx_generic, fd);
150 
151   xclose (fd);
152   free (path);
153 
154   return 0;
155 }
156 
157 #include <support/test-driver.c>
158