1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #define _GNU_SOURCE 4 #define __SANE_USERSPACE_TYPES__ 5 #include <fcntl.h> 6 #include <unistd.h> 7 #include <errno.h> 8 #include <string.h> 9 #include <sys/stat.h> 10 11 #include "kselftest_harness.h" 12 13 #ifndef O_EMPTYPATH 14 #define O_EMPTYPATH (1 << 26) 15 #endif 16 17 #define EMPTYPATH_TEST_FILE "/tmp/emptypath_test" 18 19 FIXTURE(emptypath) { 20 int opath_fd; 21 }; 22 23 FIXTURE_SETUP(emptypath) 24 { 25 int fd; 26 27 self->opath_fd = -1; 28 29 fd = open(EMPTYPATH_TEST_FILE, O_CREAT | O_WRONLY, S_IRWXU); 30 ASSERT_GE(fd, 0) { 31 TH_LOG("create %s: %s", EMPTYPATH_TEST_FILE, strerror(errno)); 32 } 33 close(fd); 34 35 self->opath_fd = open(EMPTYPATH_TEST_FILE, O_PATH); 36 ASSERT_GE(self->opath_fd, 0) { 37 TH_LOG("open %s O_PATH: %s", EMPTYPATH_TEST_FILE, strerror(errno)); 38 } 39 } 40 41 FIXTURE_TEARDOWN(emptypath) 42 { 43 if (self->opath_fd >= 0) 44 close(self->opath_fd); 45 unlink(EMPTYPATH_TEST_FILE); 46 } 47 48 /* An empty path is rejected with ENOENT unless O_EMPTYPATH is set. */ 49 TEST_F(emptypath, without_flag_returns_enoent) 50 { 51 int fd = openat(self->opath_fd, "", O_RDONLY); 52 53 if (fd >= 0) 54 close(fd); 55 ASSERT_LT(fd, 0) { 56 TH_LOG("empty path without O_EMPTYPATH unexpectedly succeeded"); 57 } 58 EXPECT_EQ(errno, ENOENT) { 59 TH_LOG("expected ENOENT, got %s", strerror(errno)); 60 } 61 } 62 63 /* O_EMPTYPATH reopens the O_PATH fd through an empty path. */ 64 TEST_F(emptypath, reopens_opath_fd) 65 { 66 int fd = openat(self->opath_fd, "", O_RDONLY | O_EMPTYPATH); 67 68 if (fd < 0 && errno == EINVAL) 69 SKIP(return, "O_EMPTYPATH not supported"); 70 71 ASSERT_GE(fd, 0) { 72 TH_LOG("O_EMPTYPATH failed: %s", strerror(errno)); 73 } 74 close(fd); 75 } 76 77 TEST_HARNESS_MAIN 78