<filesystem> Treat ERROR_BAD_NETPATH as file not found. (#616)

Resolves GH-615 / DevCom-950424.

* Extract _Is_file_not_found to <xfilesystem_abi.h> as __std_is_file_not_found because we also need that in filesystem.cpp.
* Add ERROR_BAD_NETPATH to __std_is_file_not_found.
* Map ERROR_BAD_NETPATH to errc::no_such_file_or_directory.
* Change filesystem tests that look for file not exists behavior to also test bad network paths.
This commit is contained in:
Billy O'Neal 2020-03-17 18:29:50 -07:00 коммит произвёл GitHub
Родитель e65b2aa6cd
Коммит bf944d2e28
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 131 добавлений и 97 удалений

Просмотреть файл

@ -1826,12 +1826,6 @@ namespace filesystem {
_THROW(filesystem_error(_Op, _Path1, _Path2, _Error));
}
// FUNCTION _Is_file_not_found
_NODISCARD inline bool _Is_file_not_found(const __std_win_error _Error) noexcept {
return _Error == __std_win_error::_File_not_found || _Error == __std_win_error::_Path_not_found
|| _Error == __std_win_error::_Invalid_name;
}
// ENUM CLASS file_type
enum class file_type {
none,
@ -1975,7 +1969,7 @@ namespace filesystem {
}
this->permissions(perms::unknown);
this->type(_Is_file_not_found(_Error) ? file_type::not_found : file_type::none);
this->type(__std_is_file_not_found(_Error) ? file_type::not_found : file_type::none);
}
private:
@ -2724,7 +2718,7 @@ namespace filesystem {
if (_Error == __std_win_error::_Success) {
_Should_recurse =
_Bitmask_includes(_Target_stats._Attributes, __std_fs_file_attr::_Directory);
} else if (_Is_file_not_found(_Error)
} else if (__std_is_file_not_found(_Error)
|| (_Error == __std_win_error::_Access_denied
&& _Bitmask_includes(_Options, directory_options::skip_permission_denied))) {
// skip broken symlinks and permission denied (when configured)
@ -3757,7 +3751,7 @@ namespace filesystem {
_Error = _Create_result._Error;
_Created_last = _Create_result._Created;
_Error = _Create_result._Error;
if (_Error != __std_win_error::_Success && !_Is_file_not_found(_Error)) {
if (_Error != __std_win_error::_Success && !__std_is_file_not_found(_Error)) {
_Most_recent_not_file_not_found = _Error;
}
@ -3790,7 +3784,7 @@ namespace filesystem {
for (directory_iterator _It(_Path, _Ec);; _It.increment(_Ec)) { // remove nonempty directory contents
if (_Ec) {
if (_Ec.category() != _STD system_category()
|| !_Is_file_not_found(static_cast<__std_win_error>(_Ec.value()))) {
|| !__std_is_file_not_found(static_cast<__std_win_error>(_Ec.value()))) {
return;
}
@ -4042,7 +4036,7 @@ namespace filesystem {
return _Temp;
}
if (!_Is_file_not_found(_Err)) {
if (!__std_is_file_not_found(_Err)) {
_Ec = _Make_ec(_Err);
return path();
}
@ -4066,7 +4060,7 @@ namespace filesystem {
if (_Err == __std_win_error::_Success) {
_Result = _STD move(_Temp);
} else if (_Is_file_not_found(_Err)) {
} else if (__std_is_file_not_found(_Err)) {
_Call_canonical = false;
} else {
_Ec = _Make_ec(_Err);

Просмотреть файл

@ -33,6 +33,7 @@ enum class __std_win_error : unsigned long {
_No_more_files = 18, // #define ERROR_NO_MORE_FILES 18L
_Sharing_violation = 32, // #define ERROR_SHARING_VIOLATION 32L
_Not_supported = 50, // #define ERROR_NOT_SUPPORTED 50L
_Error_bad_netpath = 53, // #define ERROR_BAD_NETPATH 53L
_File_exists = 80, // #define ERROR_FILE_EXISTS 80L
_Invalid_parameter = 87, // #define ERROR_INVALID_PARAMETER 87L
_Insufficient_buffer = 122, // #define ERROR_INSUFFICIENT_BUFFER 122L
@ -44,6 +45,22 @@ enum class __std_win_error : unsigned long {
_Max = ~0UL // sentinel not used by Win32
};
// FUNCTION __std_is_file_not_found
#pragma warning(push)
#pragma warning(disable : 4061) // enumerator not explicitly handled by switch label
_NODISCARD inline bool __std_is_file_not_found(const __std_win_error _Error) noexcept {
switch (_Error) {
case __std_win_error::_File_not_found:
case __std_win_error::_Path_not_found:
case __std_win_error::_Error_bad_netpath:
case __std_win_error::_Invalid_name:
return true;
default:
return false;
}
}
#pragma warning(pop)
enum class __std_fs_dir_handle : intptr_t { _Invalid = -1 };
enum class __std_fs_file_attr : unsigned long {

Просмотреть файл

@ -224,13 +224,11 @@ namespace {
}
[[nodiscard]] __std_win_error __stdcall _Translate_not_found_to_success(const __std_win_error _Err) noexcept {
switch (_Err) {
case __std_win_error::_File_not_found:
case __std_win_error::_Path_not_found:
if (__std_is_file_not_found(_Err)) {
return __std_win_error::_Success;
default:
return _Err;
}
return _Err;
}
[[nodiscard]] __std_win_error __stdcall _Get_last_write_time_by_handle(

Просмотреть файл

@ -24,6 +24,7 @@ static constexpr _Win_errtab_t _Win_errtab[] = {
// table of Windows/Posix pairs
{ERROR_ACCESS_DENIED, errc::permission_denied},
{ERROR_ALREADY_EXISTS, errc::file_exists},
{ERROR_BAD_NETPATH, errc::no_such_file_or_directory},
{ERROR_BAD_UNIT, errc::no_such_device},
{ERROR_BROKEN_PIPE, errc::broken_pipe},
{ERROR_BUFFER_OVERFLOW, errc::filename_too_long},

Просмотреть файл

@ -32,8 +32,11 @@ using namespace std;
using namespace std::chrono;
using namespace std::filesystem;
constexpr wstring_view badPath = L"// ?? ?? ///// ?? ?? ? ////"sv;
constexpr wstring_view nonexistentPath = L"C:/This/Path/Should/Not/Exist"sv;
constexpr wstring_view badPath = L"// ?? ?? ///// ?? ?? ? ////"sv;
const path nonexistentPaths[] = {
L"C:/This/Path/Should/Not/Exist"sv,
L"//this_path_does_not_exist_on_the_network_e9da301701f70ead24c65bd30f600d15/docs"sv,
};
constexpr wstring_view longSuffix =
LR"(really\long\path\longer\than\max_path\goes\here\and it just goes)"
LR"( on and on\and it just goes on and on\and it just goes on and on\and it just goes on and on)"
@ -983,18 +986,20 @@ void test_directory_entry() {
// Test VSO-892890 "std::filesystem::directory_entry constructor initializes wrong state"
EXPECT(!default_entry.exists());
directory_entry nonexistentEntry(nonexistentPath);
EXPECT(nonexistentEntry.path() == nonexistentPath);
// Test VSO-892890 "std::filesystem::directory_entry constructor initializes wrong state"
EXPECT(!nonexistentEntry.exists());
for (auto&& nonexistent : nonexistentPaths) {
directory_entry nonexistentEntry(nonexistent);
EXPECT(nonexistentEntry.path() == nonexistent);
// Test VSO-892890 "std::filesystem::directory_entry constructor initializes wrong state"
EXPECT(!nonexistentEntry.exists());
directory_entry nonexistentEntryEc(nonexistentPath, ec);
EXPECT(nonexistentEntryEc.path() == nonexistentPath);
// Test VSO-892890 "std::filesystem::directory_entry constructor initializes wrong state"
EXPECT(!nonexistentEntryEc.exists());
EXPECT(good(ec));
directory_entry nonexistentEntryEc(nonexistent, ec);
EXPECT(nonexistentEntryEc.path() == nonexistent);
// Test VSO-892890 "std::filesystem::directory_entry constructor initializes wrong state"
EXPECT(!nonexistentEntryEc.exists());
EXPECT(good(ec));
EXPECT(throws_filesystem_error([&] { nonexistentEntryEc.refresh(); }, "directory_entry::refresh", nonexistentPath));
EXPECT(throws_filesystem_error([&] { nonexistentEntryEc.refresh(); }, "directory_entry::refresh", nonexistent));
}
directory_entry goodEntry(filePath, ec);
EXPECT(good(ec));
@ -1207,12 +1212,14 @@ void test_directory_entry() {
#endif // _HAS_CXX20
// assert that mutating the path doesn't fail even though the target doesn't exist
cachingEntry.assign(nonexistentPath); // no fail
cachingEntry.assign(nonexistentPath, ec);
EXPECT(good(ec));
cachingEntry.replace_filename(L"Exist2"sv); // no fail
cachingEntry.replace_filename(L"Exist2"sv, ec);
EXPECT(good(ec));
for (auto&& nonexistent : nonexistentPaths) {
cachingEntry.assign(nonexistent); // no fail
cachingEntry.assign(nonexistent, ec);
EXPECT(good(ec));
cachingEntry.replace_filename(L"Exist2"sv); // no fail
cachingEntry.replace_filename(L"Exist2"sv, ec);
EXPECT(good(ec));
}
remove(changingPath, ec);
EXPECT(good(ec));
@ -1256,18 +1263,20 @@ void test_directory_iterator_common_parts(const string_view typeName) {
// bool operator==(const DirectoryIterator& _Rhs) const;
{
error_code ec;
DirectoryIterator bad_dir(nonexistentPath, ec);
EXPECT(bad(ec));
EXPECT(bad_dir == DirectoryIterator{});
EXPECT(bad_dir == bad_dir);
EXPECT(!(bad_dir != bad_dir));
for (auto&& nonexistent : nonexistentPaths) {
DirectoryIterator bad_dir(nonexistent, ec);
EXPECT(bad(ec));
EXPECT(bad_dir == DirectoryIterator{});
EXPECT(bad_dir == bad_dir);
EXPECT(!(bad_dir != bad_dir));
EXPECT(throws_filesystem_error([&] { DirectoryIterator bad_dir{nonexistentPath}; }, typeName, nonexistentPath));
EXPECT(throws_filesystem_error(
[&] {
DirectoryIterator bad_dir{nonexistentPath, directory_options::none};
},
typeName, nonexistentPath));
EXPECT(throws_filesystem_error([&] { DirectoryIterator bad_dir{nonexistent}; }, typeName, nonexistent));
EXPECT(throws_filesystem_error(
[&] {
DirectoryIterator bad_dir{nonexistent, directory_options::none};
},
typeName, nonexistent));
}
// Test VSO-844835 "directory_iterator constructed with empty path iterates over the current directory"
DirectoryIterator empty_dir(path{}, ec);
@ -1469,7 +1478,7 @@ void test_recursive_directory_iterator() {
const path bbb = followSymlinkTests.directoryPath / L"bbb"sv;
const path ccc = followSymlinkTests.directoryPath / L"ccc"sv;
error_code ec;
create_directory_symlink(nonexistentPath, bbb, ec);
create_directory_symlink(nonexistentPaths[0], bbb, ec);
if (ec) {
check_symlink_permissions(ec, L"recursive_directory_iterator");
} else {
@ -1805,7 +1814,10 @@ void test_copy() {
remove_all(basePath);
EXPECT(throws_filesystem_error([&] { copy(nonexistentPath, basePath); }, "copy"sv, nonexistentPath, basePath));
for (auto&& nonexistent : nonexistentPaths) {
EXPECT(throws_filesystem_error([&] { copy(nonexistent, basePath); }, "copy"sv, nonexistent, basePath));
}
EXPECT(throws_filesystem_error([&] { copy(basePath, basePath); }, "copy"sv, basePath, basePath));
}
@ -2698,8 +2710,10 @@ void test_file_size() {
EXPECT(bad_file_size == file_size(L""sv, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(bad_file_size == file_size(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
for (auto&& nonexistent : nonexistentPaths) {
EXPECT(bad_file_size == file_size(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
}
EXPECT(throws_filesystem_error([] { (void) file_size(L""sv); }, "file_size", L""sv));
}
@ -2778,8 +2792,10 @@ void test_last_write_time() {
EXPECT(bad_file_time == last_write_time(L""sv, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(bad_file_time == last_write_time(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
for (auto&& nonexistent : nonexistentPaths) {
EXPECT(bad_file_time == last_write_time(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
}
EXPECT(throws_filesystem_error([] { (void) last_write_time(L""sv); }, "last_write_time", L""sv));
}
@ -2855,11 +2871,14 @@ void test_status() {
error_code ec;
create_file_containing(testFile, L"Hello");
EXPECT(status(nonexistentPath).type() == file_type::not_found); // should not throw
EXPECT(status(nonexistentPath, ec).type() == file_type::not_found);
EXPECT(ec.category() == system_category());
EXPECT(ec.value() == 2 || ec.value() == 3);
EXPECT(ec == errc::no_such_file_or_directory);
for (auto&& nonexistent : nonexistentPaths) {
EXPECT(status(nonexistent).type() == file_type::not_found); // should not throw
EXPECT(status(nonexistent, ec).type() == file_type::not_found);
EXPECT(ec.category() == system_category());
// accept ERROR_FILE_NOT_FOUND (2), ERROR_PATH_NOT_FOUND (3), or ERROR_BAD_NETPATH (53)
EXPECT(ec.value() == 2 || ec.value() == 3 || ec.value() == 53);
EXPECT(ec == errc::no_such_file_or_directory);
}
EXPECT(!exists(file_status{}));
EXPECT(!exists(file_status{file_type::not_found}));
@ -2886,34 +2905,36 @@ void test_status() {
EXPECT(!is_symlink(file_status{}));
EXPECT(is_symlink(file_status{file_type::symlink}));
EXPECT(!exists(nonexistentPath));
EXPECT(!is_block_file(nonexistentPath));
EXPECT(!is_character_file(nonexistentPath));
EXPECT(!is_directory(nonexistentPath));
EXPECT(!is_fifo(nonexistentPath));
EXPECT(!is_other(nonexistentPath));
EXPECT(!is_regular_file(nonexistentPath));
EXPECT(!is_socket(nonexistentPath));
EXPECT(!is_symlink(nonexistentPath));
for (auto&& nonexistent : nonexistentPaths) {
EXPECT(!exists(nonexistent));
EXPECT(!is_block_file(nonexistent));
EXPECT(!is_character_file(nonexistent));
EXPECT(!is_directory(nonexistent));
EXPECT(!is_fifo(nonexistent));
EXPECT(!is_other(nonexistent));
EXPECT(!is_regular_file(nonexistent));
EXPECT(!is_socket(nonexistent));
EXPECT(!is_symlink(nonexistent));
EXPECT(!exists(nonexistentPath, ec));
EXPECT(good(ec));
EXPECT(!is_block_file(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_character_file(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_directory(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_fifo(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_other(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_regular_file(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_socket(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_symlink(nonexistentPath, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!exists(nonexistent, ec));
EXPECT(good(ec));
EXPECT(!is_block_file(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_character_file(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_directory(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_fifo(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_other(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_regular_file(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_socket(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
EXPECT(!is_symlink(nonexistent, ec));
EXPECT(ec == errc::no_such_file_or_directory);
}
EXPECT(exists(testDir));
EXPECT(exists(testDir, ec));
@ -3277,9 +3298,9 @@ void test_remove() {
EXPECT(!exists(dirname, ec));
EXPECT(good(ec));
EXPECT(throws_filesystem_error([] { remove(badPath); }, "remove", badPath));
remove(badPath, ec); // bogus invalid path
EXPECT(bad(ec));
remove(badPath); // we ignore invalid paths
remove(badPath, ec);
EXPECT(good(ec));
}
void test_rename() {
@ -3568,19 +3589,21 @@ void test_create_directory() {
remove(p);
}
// test bogus path
// test invalid path
{
error_code ec;
EXPECT(create_directory(nonexistentPath, ec) == false); // failed
EXPECT(bad(ec));
for (auto&& nonexistent : nonexistentPaths) {
EXPECT(create_directory(nonexistent, ec) == false); // failed
EXPECT(bad(ec));
EXPECT(throws_filesystem_error([] { create_directory(nonexistentPath); }, "create_directory", nonexistentPath));
EXPECT(throws_filesystem_error([&] { create_directory(nonexistent); }, "create_directory", nonexistent));
}
}
// test VSO-654638 where create_directory(p, existing_p) was doing copy_symlink behavior
{
error_code ec;
create_directory_symlink(nonexistentPath, p, ec);
create_directory_symlink(nonexistentPaths[0], p, ec);
if (ec) {
check_symlink_permissions(ec, L"test_create_directory/VSO-654638");
} else {
@ -3634,9 +3657,9 @@ void test_create_dirs_and_remove_all() {
create_directories(badPath, ec);
EXPECT(bad(ec));
EXPECT(throws_filesystem_error([] { remove_all(badPath); }, "remove_all", badPath));
remove_all(badPath); // we ignore invalid paths as in remove
remove_all(badPath, ec);
EXPECT(bad(ec));
EXPECT(good(ec));
// test that normalization isn't done first
auto dots = r / L"a/../b/../c"sv;
@ -3700,14 +3723,15 @@ void test_symlink_status() {
EXPECT(ft.type() == ft2.type());
EXPECT(ft.permissions() == ft2.permissions());
}
{
for (auto&& nonexistent : nonexistentPaths) {
error_code ec;
auto ft = symlink_status(nonexistentPath, ec);
auto ft = symlink_status(nonexistent, ec);
EXPECT(bad(ec));
EXPECT(ft.type() == file_type::not_found);
EXPECT(ft.permissions() == perms::unknown);
auto ft2 = symlink_status(nonexistentPath);
auto ft2 = symlink_status(nonexistent);
EXPECT(ft.type() == ft2.type());
EXPECT(ft.permissions() == ft2.permissions());
}