diff options
Diffstat (limited to 'io/tst-statx.c')
-rw-r--r-- | io/tst-statx.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/io/tst-statx.c b/io/tst-statx.c new file mode 100644 index 0000000000..61bf31d177 --- /dev/null +++ b/io/tst-statx.c @@ -0,0 +1,157 @@ +/* Basic test of statx system call. + Copyright (C) 2018 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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <support/check.h> +#include <support/support.h> +#include <support/temp_file.h> +#include <support/xunistd.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/sysmacros.h> +#include <unistd.h> + +/* Ensure that the types have the kernel-expected layout. */ +_Static_assert (sizeof (struct statx_timestamp) == 16, "statx_timestamp size"); +_Static_assert (sizeof (struct statx) == 256, "statx size"); +_Static_assert (offsetof (struct statx, stx_nlink) == 16, "statx nlink"); +_Static_assert (offsetof (struct statx, stx_ino) == 32, "statx ino"); +_Static_assert (offsetof (struct statx, stx_atime) == 64, "statx atime"); +_Static_assert (offsetof (struct statx, stx_rdev_major) == 128, "statx rdev"); +_Static_assert (offsetof (struct statx, __statx_pad2) == 144, "statx pad2"); + +#include "statx_generic.c" + +typedef int (*statx_function) (int, const char *, int, unsigned int, + struct statx *); + +/* Return true if we have a real implementation of statx. */ +static bool +kernel_supports_statx (void) +{ +#ifdef __NR_statx + struct statx buf; + return syscall (__NR_statx, 0, "", AT_EMPTY_PATH, 0, &buf) == 0 + || errno != ENOSYS; +#else + return false; +#endif +} + +/* Tests which apply to both implementations. */ +static void +both_implementations_tests (statx_function impl, const char *path, int fd) +{ + uint64_t ino; + { + struct statx buf = { 0, }; + TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &buf), 0); + TEST_COMPARE (buf.stx_size, 3); + ino = buf.stx_ino; + } + { + struct statx buf = { 0, }; + TEST_COMPARE (statx (AT_FDCWD, path, 0, STATX_BASIC_STATS, &buf), 0); + TEST_COMPARE (buf.stx_size, 3); + TEST_COMPARE (buf.stx_ino, ino); + } + { + struct statx stx = { 0, }; + TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &stx), 0); + struct stat64 st; + xfstat (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)); + } + { + struct statx stx = { 0, }; + TEST_COMPARE (statx (AT_FDCWD, "/dev/null", 0, STATX_BASIC_STATS, &stx), + 0); + struct stat64 st; + xstat ("/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)); + TEST_COMPARE (stx.stx_rdev_major, major (st.st_rdev)); + TEST_COMPARE (stx.stx_rdev_minor, minor (st.st_rdev)); + } +} + +/* Tests which apply only to the non-kernel (generic) + implementation. */ +static void +non_kernel_tests (statx_function impl, int fd) +{ + /* The non-kernel implementation must always fail for explicit sync + flags. */ + struct statx buf; + errno = 0; + TEST_COMPARE (impl (fd, "", AT_EMPTY_PATH | AT_STATX_FORCE_SYNC, + STATX_BASIC_STATS, &buf), -1); + TEST_COMPARE (errno, EINVAL); + errno = 0; + TEST_COMPARE (impl (fd, "", AT_EMPTY_PATH | AT_STATX_DONT_SYNC, + STATX_BASIC_STATS, &buf), -1); + TEST_COMPARE (errno, EINVAL); +} + +static int +do_test (void) +{ + char *path; + int fd = create_temp_file ("tst-statx-", &path); + TEST_VERIFY_EXIT (fd >= 0); + support_write_file_string (path, "abc"); + + both_implementations_tests (&statx, path, fd); + both_implementations_tests (&statx_generic, path, fd); + + if (kernel_supports_statx ()) + { + puts ("info: kernel supports statx"); + struct statx buf; + buf.stx_size = 0; + TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH | AT_STATX_FORCE_SYNC, + STATX_BASIC_STATS, &buf), + 0); + TEST_COMPARE (buf.stx_size, 3); + buf.stx_size = 0; + TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH | AT_STATX_DONT_SYNC, + STATX_BASIC_STATS, &buf), + 0); + TEST_COMPARE (buf.stx_size, 3); + } + else + { + puts ("info: kernel does not support statx"); + non_kernel_tests (&statx, fd); + } + non_kernel_tests (&statx_generic, fd); + + xclose (fd); + free (path); + + return 0; +} + +#include <support/test-driver.c> |