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