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 // UNSUPPORTED: c++03
10
11 // <filesystem>
12
13 // void permissions(const path& p, perms prms,
14 // perm_options opts = perm_options::replace);
15 // void permissions(const path& p, perms prms, std::error_code& ec) noexcept;
16 // void permissions(const path& p, perms prms, perm_options opts, std::error_code);
17
18
19
20 #include "filesystem_include.h"
21
22 #include "test_macros.h"
23 #include "rapid-cxx-test.h"
24 #include "filesystem_test_helper.h"
25
26 using namespace fs;
27
28 using PR = fs::perms;
29
30 TEST_SUITE(filesystem_permissions_test_suite)
31
TEST_CASE(test_signatures)32 TEST_CASE(test_signatures)
33 {
34 const path p; ((void)p);
35 const perms pr{}; ((void)pr);
36 const perm_options opts{}; ((void)opts);
37 std::error_code ec; ((void)ec);
38 ASSERT_NOT_NOEXCEPT(fs::permissions(p, pr));
39 ASSERT_NOT_NOEXCEPT(fs::permissions(p, pr, opts));
40 ASSERT_NOEXCEPT(fs::permissions(p, pr, ec));
41 LIBCPP_ONLY(ASSERT_NOT_NOEXCEPT(fs::permissions(p, pr, opts, ec)));
42 }
43
TEST_CASE(test_error_reporting)44 TEST_CASE(test_error_reporting)
45 {
46 auto checkThrow = [](path const& f, fs::perms opts,
47 const std::error_code& ec)
48 {
49 #ifndef TEST_HAS_NO_EXCEPTIONS
50 try {
51 fs::permissions(f, opts);
52 return false;
53 } catch (filesystem_error const& err) {
54 return err.path1() == f
55 && err.path2() == ""
56 && err.code() == ec;
57 }
58 #else
59 ((void)f); ((void)opts); ((void)ec);
60 return true;
61 #endif
62 };
63
64 scoped_test_env env;
65 const path dne = env.make_env_path("dne");
66 const path dne_sym = env.create_symlink(dne, "dne_sym");
67 { // !exists
68 std::error_code ec = GetTestEC();
69 fs::permissions(dne, fs::perms{}, ec);
70 TEST_REQUIRE(ec);
71 TEST_CHECK(ec != GetTestEC());
72 TEST_CHECK(checkThrow(dne, fs::perms{}, ec));
73 }
74 {
75 std::error_code ec = GetTestEC();
76 fs::permissions(dne_sym, fs::perms{}, ec);
77 TEST_REQUIRE(ec);
78 TEST_CHECK(ec != GetTestEC());
79 TEST_CHECK(checkThrow(dne_sym, fs::perms{}, ec));
80 }
81 }
82
TEST_CASE(basic_permissions_test)83 TEST_CASE(basic_permissions_test)
84 {
85 scoped_test_env env;
86 const path file = env.create_file("file1", 42);
87 const path dir = env.create_dir("dir1");
88 const path file_for_sym = env.create_file("file2", 42);
89 const path sym = env.create_symlink(file_for_sym, "sym");
90 const perm_options AP = perm_options::add;
91 const perm_options RP = perm_options::remove;
92 const perm_options NF = perm_options::nofollow;
93 struct TestCase {
94 path p;
95 perms set_perms;
96 perms expected;
97 perm_options opts;
98 TestCase(path xp, perms xperms, perms xexpect,
99 perm_options xopts = perm_options::replace)
100 : p(xp), set_perms(xperms), expected(xexpect), opts(xopts) {}
101 } cases[] = {
102 // test file
103 {file, perms::none, perms::none},
104 {file, perms::owner_all, perms::owner_all},
105 {file, perms::group_all, perms::owner_all | perms::group_all, AP},
106 {file, perms::group_all, perms::owner_all, RP},
107 // test directory
108 {dir, perms::none, perms::none},
109 {dir, perms::owner_all, perms::owner_all},
110 {dir, perms::group_all, perms::owner_all | perms::group_all, AP},
111 {dir, perms::group_all, perms::owner_all, RP},
112 // test symlink without symlink_nofollow
113 {sym, perms::none, perms::none},
114 {sym, perms::owner_all, perms::owner_all},
115 {sym, perms::group_all, perms::owner_all | perms::group_all, AP},
116 {sym, perms::group_all, perms::owner_all, RP},
117 // test non-symlink with symlink_nofollow. The last test on file/dir
118 // will have set their permissions to perms::owner_all
119 {file, perms::group_all, perms::owner_all | perms::group_all, AP | NF},
120 {dir, perms::group_all, perms::owner_all | perms::group_all, AP | NF}
121 };
122 for (auto const& TC : cases) {
123 TEST_CHECK(status(TC.p).permissions() != TC.expected);
124 {
125 std::error_code ec = GetTestEC();
126 permissions(TC.p, TC.set_perms, TC.opts, ec);
127 TEST_CHECK(!ec);
128 auto pp = status(TC.p).permissions();
129 TEST_CHECK(pp == TC.expected);
130 }
131 if (TC.opts == perm_options::replace) {
132 std::error_code ec = GetTestEC();
133 permissions(TC.p, TC.set_perms, ec);
134 TEST_CHECK(!ec);
135 auto pp = status(TC.p).permissions();
136 TEST_CHECK(pp == TC.expected);
137 }
138 }
139 }
140
TEST_CASE(test_no_resolve_symlink_on_symlink)141 TEST_CASE(test_no_resolve_symlink_on_symlink)
142 {
143 scoped_test_env env;
144 const path file = env.create_file("file", 42);
145 const path sym = env.create_symlink(file, "sym");
146 const auto file_perms = status(file).permissions();
147
148 struct TestCase {
149 perms set_perms;
150 perms expected; // only expected on platform that support symlink perms.
151 perm_options opts = perm_options::replace;
152 TestCase(perms xperms, perms xexpect,
153 perm_options xopts = perm_options::replace)
154 : set_perms(xperms), expected(xexpect), opts(xopts) {}
155 } cases[] = {
156 {perms::owner_all, perms::owner_all},
157 {perms::group_all, perms::owner_all | perms::group_all, perm_options::add},
158 {perms::owner_all, perms::group_all, perm_options::remove},
159 };
160 for (auto const& TC : cases) {
161 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
162 // On OS X symlink permissions are supported. We should get an empty
163 // error code and the expected permissions.
164 const auto expected_link_perms = TC.expected;
165 std::error_code expected_ec;
166 #else
167 // On linux symlink permissions are not supported. The error code should
168 // be 'operation_not_supported' and the symlink permissions should be
169 // unchanged.
170 const auto expected_link_perms = symlink_status(sym).permissions();
171 std::error_code expected_ec = std::make_error_code(std::errc::operation_not_supported);
172 #endif
173 std::error_code ec = GetTestEC();
174 permissions(sym, TC.set_perms, TC.opts | perm_options::nofollow, ec);
175 if (expected_ec)
176 TEST_CHECK(ErrorIs(ec, static_cast<std::errc>(expected_ec.value())));
177 else
178 TEST_CHECK(!ec);
179 TEST_CHECK(status(file).permissions() == file_perms);
180 TEST_CHECK(symlink_status(sym).permissions() == expected_link_perms);
181 }
182 }
183
184 TEST_SUITE_END()
185