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"
28namespace fs = std::filesystem;
29using namespace fs;
30
31static void signature_test()
32{
33 const path p; ((void)p);
34 std::error_code ec; ((void)ec);
35 ASSERT_NOT_NOEXCEPT(symlink_status(p: p));
36 ASSERT_NOEXCEPT(symlink_status(p: p, ec&: ec));
37}
38
39static 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
67static 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(p: dir, prms: 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(e: set_errc);
107 file_status st = symlink_status(p: sym_points_in_dir, ec&: 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(p: 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
120static 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
158static 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(p: possible_p, ec&: 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(e: std::errc::address_in_use);
182 file_status st = symlink_status(p: p, ec&: 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: 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(to: p, new_symlink: sym);
193 { // test symlink to block file
194 // test non-throwing case
195 std::error_code ec = std::make_error_code(e: std::errc::address_in_use);
196 file_status st = symlink_status(p: sym, ec&: 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(p: sym));
202 assert(st.type() == file_type::symlink);
203 assert(st.permissions() != perms::unknown);
204 }
205}
206
207int 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

source code of libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.symlink_status/symlink_status.pass.cpp