Skip to content

Commit

Permalink
[libcxx] Test accessing a directory on windows that gives "access den…
Browse files Browse the repository at this point in the history
…ied" errors

Fix handling of skip_permission_denied on windows; after converting
the return value of GetLastError() to a standard error_code, ec.value()
is in the standard errc range, not a native windows error code. This
was missed in 1561807.

The directory "C:\System Volume Information" does seem to exist and
have these properties on most relevant contempory setups.

Differential Revision: https://reviews.llvm.org/D98166
  • Loading branch information
mstorsjo committed Mar 11, 2021
1 parent cfe69c8 commit e69c65d
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 4 deletions.
3 changes: 2 additions & 1 deletion libcxx/src/filesystem/directory_iterator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ class __dir_stream {
ec = detail::make_windows_error(GetLastError());
const bool ignore_permission_denied =
bool(opts & directory_options::skip_permission_denied);
if (ignore_permission_denied && ec.value() == ERROR_ACCESS_DENIED)
if (ignore_permission_denied &&
ec.value() == static_cast<int>(errc::permission_denied))
ec.clear();
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,23 @@ TEST_CASE(path_ctor_dne) {

TEST_CASE(path_ctor_cannot_resolve) {
using namespace fs;
#ifdef _WIN32
// Windows doesn't support setting perms::none to trigger failures
// reading directories; test using a special inaccessible directory
// instead.
const path dir = GetWindowsInaccessibleDir();
TEST_REQUIRE(!dir.empty());
const path file = dir / "file";
{
std::error_code ec = GetTestEC();
directory_entry ent(file, ec);
TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
TEST_CHECK(ent.path() == file);
}
{
TEST_CHECK_NO_THROW(directory_entry(file));
}
#else
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
Expand Down Expand Up @@ -179,6 +196,7 @@ TEST_CASE(path_ctor_cannot_resolve) {
TEST_CHECK_NO_THROW(directory_entry(sym_in_dir));
TEST_CHECK_NO_THROW(directory_entry(sym_out_of_dir));
}
#endif
}

TEST_SUITE_END()
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ TEST_CASE(test_construction_from_bad_path)
TEST_CASE(access_denied_test_case)
{
using namespace fs;
#ifdef _WIN32
// Windows doesn't support setting perms::none to trigger failures
// reading directories; test using a special inaccessible directory
// instead.
const path testDir = GetWindowsInaccessibleDir();
TEST_REQUIRE(!testDir.empty());
#else
scoped_test_env env;
path const testDir = env.make_env_path("dir1");
path const testFile = testDir / "testFile";
Expand All @@ -100,6 +107,7 @@ TEST_CASE(access_denied_test_case)
}
// Change the permissions so we can no longer iterate
permissions(testDir, perms::none);
#endif

// Check that the construction fails when skip_permissions_denied is
// not given.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ TEST_CASE(test_construction_from_bad_path)
TEST_CASE(access_denied_test_case)
{
using namespace fs;
#ifdef _WIN32
// Windows doesn't support setting perms::none to trigger failures
// reading directories; test using a special inaccessible directory
// instead.
const path testDir = GetWindowsInaccessibleDir();
TEST_REQUIRE(!testDir.empty());
#else
scoped_test_env env;
path const testDir = env.make_env_path("dir1");
path const testFile = testDir / "testFile";
Expand All @@ -102,6 +109,7 @@ TEST_CASE(access_denied_test_case)

// Change the permissions so we can no longer iterate
permissions(testDir, perms::none);
#endif

// Check that the construction fails when skip_permissions_denied is
// not given.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,24 @@ TEST_CASE(test_exist_not_found)

TEST_CASE(test_exists_fails)
{
#ifdef _WIN32
// Windows doesn't support setting perms::none to trigger failures
// reading directories; test using a special inaccessible directory
// instead.
const path p = GetWindowsInaccessibleDir();
TEST_REQUIRE(!p.empty());
#else
scoped_test_env env;
const path dir = env.create_dir("dir");
const path file = env.create_file("dir/file", 42);
const path p = env.create_file("dir/file", 42);
permissions(dir, perms::none);
#endif

std::error_code ec;
TEST_CHECK(exists(file, ec) == false);
TEST_CHECK(exists(p, ec) == false);
TEST_CHECK(ec);

TEST_CHECK_THROW(filesystem_error, exists(file));
TEST_CHECK_THROW(filesystem_error, exists(p));
}

#ifndef _WIN32
Expand Down
25 changes: 25 additions & 0 deletions libcxx/test/support/filesystem_test_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -671,4 +671,29 @@ struct ExceptionChecker {

};

inline fs::path GetWindowsInaccessibleDir() {
// Only makes sense on windows, but the code can be compiled for
// any platform.
const fs::path dir("C:\\System Volume Information");
std::error_code ec;
const fs::path root("C:\\");
fs::directory_iterator it(root, ec);
if (ec)
return fs::path();
const fs::directory_iterator endIt{};
while (it != endIt) {
const fs::directory_entry &ent = *it;
if (ent == dir) {
// Basic sanity checks on the directory_entry
if (!ent.exists())
return fs::path();
if (!ent.is_directory())
return fs::path();
return ent;
}
++it;
}
return fs::path();
}

#endif /* FILESYSTEM_TEST_HELPER_HPP */

0 comments on commit e69c65d

Please sign in to comment.