Skip to content

<filesystem>: Fix the path returned when there is an error with temp_directory_path and simplify the validation logic #5561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions stl/inc/filesystem
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ namespace filesystem {
friend inline path absolute(const path& _Input, error_code& _Ec);
friend inline __std_win_error _Canonical(path& _Result, const wstring& _Text);
friend inline path temp_directory_path(error_code& _Ec);
friend inline path temp_directory_path();
friend inline path current_path(error_code& _Ec);
friend inline void current_path(const path& _To);
friend inline void current_path(const path& _To, error_code& _Ec) noexcept;
Expand Down Expand Up @@ -4045,23 +4046,28 @@ namespace filesystem {
path _Result;
_Result._Text.resize(__std_fs_temp_path_max);
const auto _Temp_result = __std_fs_get_temp_path(_Result._Text.data());
_Result._Text.resize(_Temp_result._Size);
if (_Temp_result._Error == __std_win_error::_Max) { // path could be retrieved, but was not a directory
_Ec = _STD make_error_code(errc::not_a_directory);
} else {
if (_Temp_result._Error != __std_win_error::_Success) {
// When there is an error, returns path() (N5008 [fs.op.temp.dir.path]/3)
_Result._Text.clear();
_Ec = _Make_ec(_Temp_result._Error);
} else {
_Result._Text.resize(_Temp_result._Size);
}

return _Result;
}

_EXPORT_STD _NODISCARD inline path temp_directory_path() {
// get a location suitable for temporary storage, and verify that it is a directory
error_code _Ec; // unusual arrangement to allow thrown error_code to have generic_category()
path _Result(_STD filesystem::temp_directory_path(_Ec));
if (_Ec) {
_Throw_fs_error("temp_directory_path", _Ec, _Result);
error_code _Ec;
path _Result;
_Result._Text.resize(__std_fs_temp_path_max);
const auto _Temp_result = __std_fs_get_temp_path(_Result._Text.data());
_Result._Text.resize(_Temp_result._Size);
if (_Temp_result._Error != __std_win_error::_Success) {
_Throw_fs_error("temp_directory_path", _Make_ec(_Temp_result._Error), _Result);
}

return _Result;
}

Expand Down
32 changes: 17 additions & 15 deletions stl/src/filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -810,28 +810,30 @@ namespace {
// If getting the path failed, returns 0 size; otherwise, returns the size of the
// expected directory. If the path could be resolved to an existing directory,
// returns __std_win_error::_Success; otherwise, returns __std_win_error::_Max.
const auto _Size = _Stl_GetTempPath2W(__std_fs_temp_path_max, _Target);
if (_Size == 0) {
return {0, __std_win_error{GetLastError()}};
__std_ulong_and_error _Result{_Stl_GetTempPath2W(__std_fs_temp_path_max, _Target), __std_win_error{GetLastError()}};
if (_Result._Size == 0) {
return _Result;
}

// Effects: If exists(p) is false or is_directory(p) is false, an error is reported
const DWORD _Attributes = GetFileAttributesW(_Target);
if (_Attributes == INVALID_FILE_ATTRIBUTES || (_Attributes & FILE_ATTRIBUTE_DIRECTORY) == 0u) {
return {_Size, __std_win_error::_Max};
}
__std_fs_file_handle _Handle;

if ((_Attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0u) {
__std_fs_file_handle _Handle;
const auto _Last_error = __std_fs_open_handle(
&_Handle, _Target, __std_access_rights::_File_read_attributes, __std_fs_file_flags::_Backup_semantics);
__std_fs_close_handle(_Handle);
if (_Last_error != __std_win_error::_Success) {
return {_Size, __std_win_error::_Max};
// Following symlinks
_Result._Error = __std_fs_open_handle(
&_Handle, _Target, __std_access_rights::_File_read_attributes, __std_fs_file_flags::_Backup_semantics);
if (_Handle != __std_fs_file_handle::_Invalid) {
FILE_BASIC_INFO _Ex_info;
if (!GetFileInformationByHandleEx(
reinterpret_cast<HANDLE>(_Handle), FileBasicInfo, &_Ex_info, sizeof(_Ex_info))) {
_Result._Error = __std_win_error{GetLastError()};
} else if (!(_Ex_info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
_Result._Error = __std_win_error::_Directory_name_is_invalid;
}

__std_fs_close_handle(_Handle);
}

return {_Size, __std_win_error::_Success};
return _Result;
}

[[nodiscard]] _Success_(return == __std_win_error::_Success) __std_win_error
Expand Down
8 changes: 4 additions & 4 deletions tests/std/tests/P0218R1_filesystem/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3569,15 +3569,15 @@ void test_temp_directory_path() {
(void) temp_directory_path();
EXPECT(false);
} catch (const filesystem_error& err) {
EXPECT(err.code() == make_error_code(errc::not_a_directory));
EXPECT(errc{err.code().value()} == errc::no_such_file_or_directory);
const auto& p1Native = err.path1().native();
EXPECT(p1Native.find(LR"(\nonexistent.dir\)") == p1Native.size() - 17);
EXPECT(err.path2().empty());
}

const auto nonexistentTemp = temp_directory_path(ec).native();
EXPECT(nonexistentTemp.find(LR"(\nonexistent.dir\)") == nonexistentTemp.size() - 17);
EXPECT(ec == make_error_code(errc::not_a_directory));
const auto nonexistentTemp = temp_directory_path(ec);
EXPECT(nonexistentTemp.empty());
EXPECT(errc{ec.value()} == errc::no_such_file_or_directory);

// TODO: automated test is_directory(p) is false, symlinks, after other filesystem components are implemented

Expand Down