1 //===----------------------------------------------------------------------===//
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 // REQUIRES: can-create-symlinks
10 // UNSUPPORTED: c++03, c++11, c++14
11 // UNSUPPORTED: no-filesystem
12 // UNSUPPORTED: availability-filesystem-missing
13
14 // Starting in Android N (API 24), SELinux policy prevents the shell user from
15 // creating a FIFO file.
16 // XFAIL: LIBCXX-ANDROID-FIXME && !android-device-api={{21|22|23}}
17
18 // <filesystem>
19
20 // file_status symlink_status(const path& p);
21 // file_status symlink_status(const path& p, error_code& ec) noexcept;
22
23 #include <filesystem>
24
25 #include "assert_macros.h"
26 #include "test_macros.h"
27 #include "filesystem_test_helper.h"
28 namespace fs = std::filesystem;
29 using namespace fs;
30
signature_test()31 static void signature_test()
32 {
33 const path p; ((void)p);
34 std::error_code ec; ((void)ec);
35 ASSERT_NOT_NOEXCEPT(symlink_status(p));
36 ASSERT_NOEXCEPT(symlink_status(p, ec));
37 }
38
test_symlink_status_not_found()39 static void test_symlink_status_not_found()
40 {
41 static_test_env static_env;
42 const std::errc expect_errc = std::errc::no_such_file_or_directory;
43 const path cases[] {
44 static_env.DNE
45 };
46 for (auto& p : cases) {
47 std::error_code ec = std::make_error_code(std::errc::address_in_use);
48 // test non-throwing overload.
49 file_status st = symlink_status(p, ec);
50 assert(ErrorIs(ec, expect_errc));
51 assert(st.type() == file_type::not_found);
52 assert(st.permissions() == perms::unknown);
53 // test throwing overload. It should not throw even though it reports
54 // that the file was not found.
55 TEST_DOES_NOT_THROW(st = status(p));
56 assert(st.type() == file_type::not_found);
57 assert(st.permissions() == perms::unknown);
58 }
59 }
60
61 // Windows doesn't support setting perms::none to trigger failures
62 // reading directories. Imaginary files under GetWindowsInaccessibleDir()
63 // produce no_such_file_or_directory, not the error codes this test checks
64 // for. Finally, status() for a too long file name doesn't return errors
65 // on windows.
66 #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE
test_symlink_status_cannot_resolve()67 static void test_symlink_status_cannot_resolve()
68 {
69 scoped_test_env env;
70 const path dir = env.create_dir("dir");
71 const path file_in_dir = env.create_file("dir/file", 42);
72 const path sym_in_dir = env.create_symlink("dir/file", "dir/bad_sym");
73 const path sym_points_in_dir = env.create_symlink("dir/file", "sym");
74 permissions(dir, perms::none);
75
76 const std::errc set_errc = std::errc::address_in_use;
77 const std::errc expect_errc = std::errc::permission_denied;
78
79 const path fail_cases[] = {
80 file_in_dir, sym_in_dir
81 };
82 for (auto& p : fail_cases)
83 {
84 { // test non-throwing case
85 std::error_code ec = std::make_error_code(set_errc);
86 file_status st = symlink_status(p, ec);
87 assert(ErrorIs(ec, expect_errc));
88 assert(st.type() == file_type::none);
89 assert(st.permissions() == perms::unknown);
90 }
91 #ifndef TEST_HAS_NO_EXCEPTIONS
92 { // test throwing case
93 try {
94 (void)symlink_status(p);
95 } catch (filesystem_error const& err) {
96 assert(err.path1() == p);
97 assert(err.path2() == "");
98 assert(ErrorIs(err.code(), expect_errc));
99 }
100 }
101 #endif
102 }
103 // Test that a symlink that points into a directory without read perms
104 // can be stat-ed using symlink_status
105 {
106 std::error_code ec = std::make_error_code(set_errc);
107 file_status st = symlink_status(sym_points_in_dir, ec);
108 assert(!ec);
109 assert(st.type() == file_type::symlink);
110 assert(st.permissions() != perms::unknown);
111 // test non-throwing version
112 TEST_DOES_NOT_THROW(st = symlink_status(sym_points_in_dir));
113 assert(st.type() == file_type::symlink);
114 assert(st.permissions() != perms::unknown);
115 }
116 }
117 #endif // TEST_WIN_NO_FILESYSTEM_PERMS_NONE
118
119
symlink_status_file_types_test()120 static void symlink_status_file_types_test()
121 {
122 static_test_env static_env;
123 scoped_test_env env;
124 struct TestCase {
125 path p;
126 file_type expect_type;
127 } cases[] = {
128 {static_env.BadSymlink, file_type::symlink},
129 {static_env.File, file_type::regular},
130 {static_env.SymlinkToFile, file_type::symlink},
131 {static_env.Dir, file_type::directory},
132 {static_env.SymlinkToDir, file_type::symlink},
133 // file_type::block files tested elsewhere
134 #ifndef _WIN32
135 {static_env.CharFile, file_type::character},
136 #endif
137 #if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(_WIN32) // No support for domain sockets
138 {env.create_socket("socket"), file_type::socket},
139 #endif
140 #ifndef _WIN32
141 {env.create_fifo("fifo"), file_type::fifo}
142 #endif
143 };
144 for (const auto& TC : cases) {
145 // test non-throwing case
146 std::error_code ec = std::make_error_code(std::errc::address_in_use);
147 file_status st = symlink_status(TC.p, ec);
148 assert(!ec);
149 assert(st.type() == TC.expect_type);
150 assert(st.permissions() != perms::unknown);
151 // test throwing case
152 TEST_DOES_NOT_THROW(st = symlink_status(TC.p));
153 assert(st.type() == TC.expect_type);
154 assert(st.permissions() != perms::unknown);
155 }
156 }
157
test_block_file()158 static void test_block_file()
159 {
160 const path possible_paths[] = {
161 "/dev/drive0", // Apple
162 "/dev/sda", // Linux
163 "/dev/loop0" // Linux
164 // No FreeBSD files known
165 };
166 path p;
167 for (const path& possible_p : possible_paths) {
168 std::error_code ec;
169 if (exists(possible_p, ec)) {
170 p = possible_p;
171 break;
172 }
173 }
174 if (p == path{}) {
175 // No possible path found.
176 return;
177 }
178 scoped_test_env env;
179 { // test block file
180 // test non-throwing case
181 std::error_code ec = std::make_error_code(std::errc::address_in_use);
182 file_status st = symlink_status(p, ec);
183 assert(!ec);
184 assert(st.type() == file_type::block);
185 assert(st.permissions() != perms::unknown);
186 // test throwing case
187 TEST_DOES_NOT_THROW(st = symlink_status(p));
188 assert(st.type() == file_type::block);
189 assert(st.permissions() != perms::unknown);
190 }
191 const path sym = env.make_env_path("sym");
192 create_symlink(p, sym);
193 { // test symlink to block file
194 // test non-throwing case
195 std::error_code ec = std::make_error_code(std::errc::address_in_use);
196 file_status st = symlink_status(sym, ec);
197 assert(!ec);
198 assert(st.type() == file_type::symlink);
199 assert(st.permissions() != perms::unknown);
200 // test throwing case
201 TEST_DOES_NOT_THROW(st = symlink_status(sym));
202 assert(st.type() == file_type::symlink);
203 assert(st.permissions() != perms::unknown);
204 }
205 }
206
main(int,char **)207 int main(int, char**) {
208 signature_test();
209 test_symlink_status_not_found();
210 #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE
211 test_symlink_status_cannot_resolve();
212 #endif
213 symlink_status_file_types_test();
214 test_block_file();
215 return 0;
216 }
217