-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
We've defined these functions in filesystem.cpp to implement std::filesystem::space():
Lines 266 to 277 in 8f4c816
| [[nodiscard]] __std_win_error _Fs_space_attempt(wchar_t* const _Temp_buffer, const DWORD _Temp_buffer_characters, | |
| const wchar_t* const _Target, uintmax_t* const _Available, uintmax_t* const _Total_bytes, | |
| uintmax_t* const _Free_bytes) noexcept { | |
| if (GetVolumePathNameW(_Target, _Temp_buffer, _Temp_buffer_characters)) { | |
| if (GetDiskFreeSpaceExW(_Temp_buffer, reinterpret_cast<PULARGE_INTEGER>(_Available), | |
| reinterpret_cast<PULARGE_INTEGER>(_Total_bytes), reinterpret_cast<PULARGE_INTEGER>(_Free_bytes))) { | |
| return __std_win_error::_Success; | |
| } | |
| } | |
| return __std_win_error{GetLastError()}; | |
| } |
Lines 763 to 798 in 8f4c816
| [[nodiscard]] __std_win_error __stdcall __std_fs_space(const wchar_t* const _Target, uintmax_t* const _Available, | |
| uintmax_t* const _Total_bytes, uintmax_t* const _Free_bytes) noexcept { | |
| // get capacity information for the volume on which the file _Target resides | |
| __std_win_error _Last_error; | |
| if (GetFileAttributesW(_Target) == INVALID_FILE_ATTRIBUTES) { | |
| _Last_error = __std_win_error{GetLastError()}; | |
| } else { | |
| { | |
| constexpr DWORD _Static_size = MAX_PATH; | |
| wchar_t _Temp_buf[_Static_size]; | |
| _Last_error = _Fs_space_attempt(_Temp_buf, _Static_size, _Target, _Available, _Total_bytes, _Free_bytes); | |
| if (_Last_error == __std_win_error::_Success) { | |
| return __std_win_error::_Success; | |
| } | |
| } | |
| if (_Last_error == __std_win_error::_Filename_exceeds_range) { | |
| constexpr DWORD _Dynamic_size = USHRT_MAX + 1; // assuming maximum NT path fits in a UNICODE_STRING | |
| const auto _Temp_buf = _malloc_crt_t(wchar_t, _Dynamic_size); | |
| if (_Temp_buf) { | |
| _Last_error = | |
| _Fs_space_attempt(_Temp_buf.get(), _Dynamic_size, _Target, _Available, _Total_bytes, _Free_bytes); | |
| if (_Last_error == __std_win_error::_Success) { | |
| return __std_win_error::_Success; | |
| } | |
| } else { | |
| _Last_error = __std_win_error::_Not_enough_memory; | |
| } | |
| } | |
| } | |
| *_Available = ~0ull; | |
| *_Total_bytes = ~0ull; | |
| *_Free_bytes = ~0ull; | |
| return _Last_error; | |
| } |
Because this is a single source file, whose object file is injected into the import lib (effectively linking statically), when a developer uses anything from std::filesystem that needs separately compiled support machinery, filesystem.obj is dragged in.
For UWP developers, there's an issue with all currently available versions of the Windows SDK where GetVolumePathNameW() isn't usable (without linking to onecoreuap.lib, which is an arcane workaround that nobody knows about). This has been fixed and will be available in a future version of the Windows SDK. However, at this time, UWP developers who attempt to use anything from std::filesystem that needs separately compiled support, like std::filesystem::create_directories(), are experiencing mysterious linker errors.
We can change how the STL is built in order to fix this scenario for the vast majority of UWP developers. (Only UWP developers specifically calling std::filesystem::space() would still be affected; they inherently need either the onecoreuap.lib workaround or the future Windows SDK.)
We simply need to move _Fs_space_attempt() and __std_fs_space() into a separate source/object file, so that the linker drags it in only when specifically needed. We can comment this as TRANSITION to remove the workaround later, although it's unclear how long this workaround will be needed.
I am unfamiliar with UWP environments, but this should be simple to validate with desktop compilations - use /link /verbose to ensure that the new object file is dragged in when, and only when, std::filesystem::space() is directly used.
Also tracked by Microsoft-internal VSO-1000285.