1+ // ===-- Unittests for faccessat -------------------------------------------===//
2+ //
3+ // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+ // See https://llvm.org/LICENSE.txt for license information.
5+ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+ //
7+ // ===----------------------------------------------------------------------===//
8+
9+ #include " src/fcntl/open.h"
10+ #include " src/__support/CPP/string.h"
11+ #include " src/sys/stat/mkdir.h"
12+ #include " src/unistd/faccessat.h"
13+ #include " src/unistd/close.h"
14+ #include " src/unistd/unlink.h"
15+ #include " src/unistd/unlinkat.h"
16+ #include " src/unistd/symlink.h"
17+ #include " src/unistd/rmdir.h"
18+ #include " src/unistd/symlink.h"
19+ #include " test/UnitTest/ErrnoCheckingTest.h"
20+ #include " test/UnitTest/ErrnoSetterMatcher.h"
21+ #include " test/UnitTest/Test.h"
22+
23+ #include < fcntl.h> // For AT_FDCWD, AT_EACCESS, AT_SYMLINK_NOFOLLOW
24+ #include < sys/stat.h> // For S_IRWXU, S_IXUSR, etc.
25+ #include < unistd.h> // For F_OK, R_OK, W_OK, X_OK
26+
27+
28+ namespace {
29+
30+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
31+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
32+
33+
34+ class LlvmLibcFaccessatTest : public LIBC_NAMESPACE ::testing::ErrnoCheckingTest {
35+ public:
36+ void create_test_dir (const char * dirname, int & dir_fd) {
37+ auto TEST_DIR = libc_make_test_file_path (dirname);
38+ ASSERT_THAT (LIBC_NAMESPACE::mkdir (TEST_DIR, S_IRWXU), Succeeds (0 ));
39+
40+ dir_fd = LIBC_NAMESPACE::open (TEST_DIR, O_RDONLY | O_DIRECTORY);
41+ ASSERT_ERRNO_SUCCESS ();
42+ ASSERT_GT (dir_fd, 0 );
43+ }
44+
45+ void cleanup_test_dir (const char * dirname, int dir_fd) {
46+ auto TEST_DIR = libc_make_test_file_path (dirname);
47+ ASSERT_THAT (LIBC_NAMESPACE::close (dir_fd), Succeeds (0 ));
48+ ASSERT_THAT (LIBC_NAMESPACE::rmdir (TEST_DIR), Succeeds (0 ));
49+ }
50+ };
51+
52+
53+ TEST_F (LlvmLibcFaccessatTest, CreateAndTest_AT_FDCWD) {
54+ // Test access checks on a file with AT_FDCWD, equivalent to access().
55+ constexpr const char *FILENAME = " faccessat_basic3.test" ;
56+ auto TEST_FILE = libc_make_test_file_path (FILENAME);
57+
58+ // Create file with full permissions
59+ int fd = LIBC_NAMESPACE::open (TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
60+ ASSERT_ERRNO_SUCCESS ();
61+ ASSERT_GT (fd, 0 );
62+ ASSERT_THAT (LIBC_NAMESPACE::close (fd), Succeeds (0 ));
63+
64+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, TEST_FILE, F_OK, 0 ), Succeeds (0 ));
65+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, TEST_FILE, X_OK | W_OK | R_OK, 0 ),
66+ Succeeds (0 ));
67+ ASSERT_THAT (LIBC_NAMESPACE::unlink (TEST_FILE), Succeeds (0 ));
68+
69+ // Create file with execute-only permission
70+ fd = LIBC_NAMESPACE::open (TEST_FILE, O_WRONLY | O_CREAT, S_IXUSR);
71+ ASSERT_ERRNO_SUCCESS ();
72+ ASSERT_GT (fd, 0 );
73+ ASSERT_THAT (LIBC_NAMESPACE::close (fd), Succeeds (0 ));
74+
75+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, TEST_FILE, F_OK, 0 ), Succeeds (0 ));
76+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, TEST_FILE, X_OK, 0 ), Succeeds (0 ));
77+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, TEST_FILE, R_OK, 0 ), Fails (EACCES));
78+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, TEST_FILE, W_OK, 0 ), Fails (EACCES));
79+ ASSERT_THAT (LIBC_NAMESPACE::unlink (TEST_FILE), Succeeds (0 ));
80+ }
81+
82+ TEST_F (LlvmLibcFaccessatTest, RelativePathWithDirFD) {
83+ LIBC_NAMESPACE::cpp::string DIRNAME =" faccessat_dir3" ;
84+ LIBC_NAMESPACE::cpp::string FILENAME = " relative_file3.txt" ;
85+
86+ int dir_fd;
87+ create_test_dir (DIRNAME.data (), dir_fd);
88+
89+ auto FULL_FILE_PATH = libc_make_test_file_path ((DIRNAME + " /" + FILENAME).data ());
90+ int fd = LIBC_NAMESPACE::open (FULL_FILE_PATH, O_WRONLY | O_CREAT, S_IRWXU);
91+ ASSERT_ERRNO_SUCCESS ();
92+ ASSERT_GT (fd, 0 );
93+ ASSERT_THAT (LIBC_NAMESPACE::close (fd), Succeeds (0 ));
94+
95+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (dir_fd, FILENAME.data (), R_OK | W_OK, 0 ), Succeeds (0 ));
96+
97+ ASSERT_THAT (LIBC_NAMESPACE::unlinkat (dir_fd, FILENAME.data (), 0 ), Succeeds (0 ));
98+ cleanup_test_dir (DIRNAME.data (), dir_fd);
99+ }
100+
101+ TEST_F (LlvmLibcFaccessatTest, SymlinkNoFollow) {
102+ constexpr const char *TARGET = " faccessat_target2" ;
103+ constexpr const char *SYMLINK = " faccessat_link2" ;
104+ auto TEST_TARGET = libc_make_test_file_path (TARGET);
105+ auto TEST_SYMLINK = libc_make_test_file_path (SYMLINK);
106+
107+ int fd = LIBC_NAMESPACE::open (TEST_TARGET, O_WRONLY | O_CREAT, 0 );
108+ ASSERT_ERRNO_SUCCESS ();
109+ ASSERT_GT (fd, 0 );
110+ ASSERT_THAT (LIBC_NAMESPACE::close (fd), Succeeds (0 ));
111+
112+ ASSERT_THAT (LIBC_NAMESPACE::symlink (TARGET, TEST_SYMLINK), Succeeds (0 ));
113+
114+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, TEST_SYMLINK, R_OK, 0 ), Fails (EACCES));
115+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, TEST_SYMLINK, F_OK, AT_SYMLINK_NOFOLLOW), Succeeds (0 ));
116+
117+ ASSERT_THAT (LIBC_NAMESPACE::unlink (TEST_SYMLINK), Succeeds (0 ));
118+ ASSERT_THAT (LIBC_NAMESPACE::unlink (TEST_TARGET), Succeeds (0 ));
119+ }
120+
121+ TEST_F (LlvmLibcFaccessatTest, AtEaccess) {
122+ // With AT_EACCESS, faccessat checks permissions using the effective user ID,
123+ // but the effective and real user ID will be the same here and changing that is not feasible in a test,
124+ // so this is just a basic sanity check.
125+ constexpr const char *FILENAME = " faccessat_eaccess.test" ;
126+ auto TEST_FILE = libc_make_test_file_path (FILENAME);
127+
128+ int fd = LIBC_NAMESPACE::open (TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
129+ ASSERT_ERRNO_SUCCESS ();
130+ ASSERT_GT (fd, 0 );
131+ ASSERT_THAT (LIBC_NAMESPACE::close (fd), Succeeds (0 ));
132+
133+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, TEST_FILE, X_OK | W_OK | R_OK, AT_EACCESS),
134+ Succeeds (0 ));
135+
136+ ASSERT_THAT (LIBC_NAMESPACE::unlink (TEST_FILE), Succeeds (0 ));
137+ }
138+
139+ TEST_F (LlvmLibcFaccessatTest, AtEmptyPath) {
140+ constexpr const char *FILENAME = " faccessat_atemptypath.test" ;
141+ auto TEST_FILE = libc_make_test_file_path (FILENAME);
142+
143+ int fd = LIBC_NAMESPACE::open (TEST_FILE, O_WRONLY | O_CREAT, S_IRWXU);
144+ ASSERT_ERRNO_SUCCESS ();
145+ ASSERT_GT (fd, 0 );
146+
147+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (fd, " " , F_OK, AT_EMPTY_PATH), Succeeds (0 ));
148+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (fd, " " , X_OK | W_OK | R_OK, AT_EMPTY_PATH),
149+ Succeeds (0 ));
150+
151+ ASSERT_THAT (LIBC_NAMESPACE::close (fd), Succeeds (0 ));
152+ ASSERT_THAT (LIBC_NAMESPACE::unlink (TEST_FILE), Succeeds (0 ));
153+
154+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, " " , F_OK, AT_EMPTY_PATH), Succeeds (0 ));
155+ ASSERT_THAT (LIBC_NAMESPACE::faccessat (AT_FDCWD, " " , X_OK | W_OK | R_OK, AT_EMPTY_PATH),
156+ Succeeds (0 ));
157+ }
158+
159+ } // namespace
0 commit comments