Skip to content
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

<filesystem>: weakly_canonical fails for UNC path with \\?\UNC prefix #2823

Open
manxorist opened this issue Jun 25, 2022 · 2 comments
Open
Assignees
Labels
bug Something isn't working filesystem C++17 filesystem

Comments

@manxorist
Copy link

Describe the bug
std::filesystem::weakly_canonical fails for UNC path with \\?\UNC prefix.

Command-line test case

C:\Users\manx\stuff>type weakly_canonical.cpp
#include <filesystem>
#include <iostream>

int main() {
    try {
        std::wcout << std::filesystem::weakly_canonical(L"\\\\?\\UNC\\server\\share\\dir\\name.ext").wstring() << std::endl;
    } catch (const std::exception & e) {
        std::wcout << std::flush;
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

C:\Users\manx\stuff>cl /std:c++20 /permissive- /EHsc /O2 /W4 weakly_canonical.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.32.31332 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

weakly_canonical.cpp
Microsoft (R) Incremental Linker Version 14.32.31332.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:weakly_canonical.exe
weakly_canonical.obj

C:\Users\manx\stuff>weakly_canonical.exe
weakly_canonical: Incorrect function.: "\\?\UNC\server\share\dir\name.ext"

C:\Users\manx\stuff>

(https://godbolt.org/z/v83fbPfrW)

Expected behavior
weakly_canonical does work for plain UNC paths without \\?\UNC prefix, so I think it should also work for prefixed ones:

#include <filesystem>
#include <iostream>

void show(std::filesystem::path p) {
    std::wcout << L"path: " << p.wstring() << std::endl;
    std::wcout << L" absolute: " << std::filesystem::absolute(p).wstring() << std::endl;
    std::wcout << L" canonical: " << std::filesystem::weakly_canonical(p).wstring() << std::endl;
    std::wcout << L" root name " << p.root_name().wstring() << std::endl;
    std::wcout << L" root directory " << p.root_directory().wstring() << std::endl;
    std::wcout << L" relative path " << p.relative_path().wstring() << std::endl;
}

int main() {
    try {
        show(std::filesystem::current_path());
        show(L"C:\\dir\\name.ext");
        show(L"\\\\.\\C:\\dir\\name.ext");
        show(L"\\\\?\\C:\\dir\\name.ext");
        show(L"\\\\server\\share\\dir\\name.ext");
        show(L"\\\\?\\UNC\\server\\share\\dir\\name.ext");
    } catch (const std::exception & e) {
        std::wcout << std::flush;
        std::cerr << e.what() << std::endl;
    }
    return 0;
}

(https://godbolt.org/z/rEdMvWs7h)

_NODISCARD inline const wchar_t* _Find_root_name_end(const wchar_t* const _First, const wchar_t* const _Last) {
talks about this prefix, so I would assume std::filesystem to be aware of it.

@manxorist manxorist changed the title <filesystem>: weakly_canonical fails for UNC path with "\\?\UNC prefix <filesystem>: weakly_canonical fails for UNC path with \\?\UNC prefix Jun 25, 2022
@StephanTLavavej StephanTLavavej added bug Something isn't working filesystem C++17 filesystem labels Jun 27, 2022
@StephanTLavavej
Copy link
Member

Improved readability with a raw string literal:

C:\Temp>type meow.cpp
#include <filesystem>
#include <iostream>
using namespace std;

int main() {
    try {
        cout << filesystem::weakly_canonical(R"(\\?\UNC\server\share\dir\name.ext)").string() << endl;
    } catch (const filesystem::filesystem_error& e) {
        cout << e.what() << endl;
    }
}
C:\Temp>cl /EHsc /nologo /W4 /MTd /std:c++17 meow.cpp && meow
meow.cpp
weakly_canonical: Incorrect function.: "\\?\UNC\server\share\dir\name.ext"

The error is happening here:

STL/stl/inc/filesystem

Lines 4075 to 4089 in ad80eb7

for (const auto& _Elem : _Normalized_relative) {
_Result /= _Elem;
if (_Call_canonical) {
_Temp.clear();
const auto _Err = _Canonical(_Temp, _Result.native());
if (_Err == __std_win_error::_Success) {
_Result = _STD move(_Temp);
} else if (__std_is_file_not_found(_Err)) {
_Call_canonical = false;
} else {
_Ec = _Make_ec(_Err);
return {};

We've called _Canonical() with LR"(\\?\UNC)" and it has failed with _Invalid_function.

@StephanTLavavej
Copy link
Member

Potentially related / involving similar issues: #2256 and LWG-3699 "lexically_relative on UNC drive paths (\\?\C:\...) results in a default-constructed value".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working filesystem C++17 filesystem
Projects
None yet
Development

No branches or pull requests

3 participants