Repository navigation
<filesystem>: lexically_relative() can not handle long path with prefix \\?\ #2256
Description
Activity
strega-nil-ms commented
on May 12, 2022 ContributorMore actionsUnfortunately, I don't believe this is fixable in our implementation, at least as the standard is currently specified (see [fs.path.gen]/3.4). I may personally agree that
\\?\C:should be treated as the root-name here, but that is not the implementation that we chose and it would be a pretty major silent breaking change to change that now.Due to this, I believe that this should be opened as a WG21 issue?
Related: LWG-3070
I think it is too late to change
root_name()but agree we should have parsed\\?\c:as root-name if I had a time machine. It does make analysis more complicated, for example,\\?\c:baris not a relative path, it is just broken. I think I was thinking "\\?\is an explicit opt-in to everything-like-posix-paths-semantics" (because that is how the NT namespace behaves) when designing this.For your immediate bug/issue, I think a special case inside
lexically_relativefor\\?\is probably reasonable to do... crystalizing into standardese that makes sense everywhere won't be so easy but I don't think we need to wait for an accepted resolution to fix it as long as the LWG issue is actually filed.Thanks for the bug report!
strega-nil-ms commented
on May 13, 2022 ContributorMore actionsI have submitted a WG21 issue, tho it has not been officially opened. I'll update when that's done.
strega-nil commented
on May 23, 2022 ContributorMore actionsWG21 issue here: https://cplusplus.github.io/LWG/issue3699
- addedfixedSomething works now, yay!Something works now, yay!
on Jul 28, 2022 `#include` <filesystem> #include <vector) #include <string> #include <iostream> struct Result { std::string s1; std::string s2; } Result test () { std::string test = {R" (\\?\C:\temp\test-file.txt)"); std::filesystem::path const p(test); Result res; res.s1.append(p.root_name ().string()); res.s2.append(p.root_path().string()); std:: cout <‹ std::endl <‹ test <‹ std::endl; std::cout <‹ "root_name\t" <‹ p.root_name ().string() <‹ std:: endl; std::wcout <‹ L" absolute: " <‹ std::filesystem::absolute (p).wstring() <‹ std::endl; std::cout <‹ "root_directory\t" <‹ p.root_directory().string() <‹ std: :end1; std::cout <‹ "root_path\t" <‹ p.root_path().string() <‹ std::endl; std::cout <‹ "relative_path\t" <‹ p.relative_path ().string() <‹ std:: end1; std::cout <‹ "parent_path\t" <‹ p.parent_path().string() ‹‹ std::endl; return res; }The output:
root name
absolute: w:?\C: \temp\test-file.txt
root directory\
root_path\
relative_path ?\C:\temp\test-file.txt
parent_path \?\C:\tempThe “root name” component extracted from the path is reported as an empty string (
””). However, the expected value was “C:”, which represents the drive letter of the path.The root directory output is
"\", however it should be"C:\".
What is the reason for this behavior of std::filesystem::path?
Describe the bug
I would expect that this line of code is true:
std::filesystem::path("\\\\?\\C:\\a\\d").lexically_relative("\\\\?\\C:\\a") == "d"But it is not, because an empty string will be returned. The reason for that is, that inside of
lexically_relative()a check_Relative_path_contains_root_name()will be executed, but this is always true. The reason is how the filesystem is handling the root name as explained in_Find_root_name_end(). There is pointed out, that in my case\\?\is the root name. But at the same time, the path containsC:\which is a valid root name as well. Because of that, we have the weird behaving, that:std::filesystem::path("\\\\?\\C:\\a\\d").relative_path() == "C:\\a\\d")which is not a relative path and causes the misbehaving of lexically_relative, because it can find another root_name inside of the "relative" path.Command-line test case
Expected behavior
That
\\?\C:\will be treated as root path and not\\?\STL version
Additional context
In another issue #1921 StephanTLavavej pointed out, that
\\?\only should be used by expert users and I agree. But in case I want to use the new Desktop-Bridge I had to use the new manifest appxmanifest, which not has a property anymore longPathAware. So I don't know how my app gives the consence of supporting that. (Is there maybe a better way to opt-in to the long path app wise) And I don't find any documentation for this use case, besides https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd. And so my only solution to solve this issue is, of converting the paths with the prefix\\?\. But this from my point of view is not well handled by the std::filesystem lib.