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

Question: Is .NET behavior proper in the presence of the \\?\ prefix? What does "\\?\." exactly mean? #39300

Closed
ericwj opened this issue Jul 14, 2020 · 6 comments
Labels
area-System.IO backlog-cleanup-candidate An inactive issue that has been marked for automated closure. no-recent-activity question Answer questions and provide assistance, not an issue with source code or documentation.

Comments

@ericwj
Copy link

ericwj commented Jul 14, 2020

Description

I know \\?\ means 'do not parse', but might I halfway misuse this repo for a Win32 question about this syntax and the behavior of .NET path API's with them?

Is it even valid to use \\?\. unless there is something to talk to that is called exactly that? Like a device or file/directory that has such a weird name? Or should it in fact refer to the current directory and direct API's to maintain the \\?\ prefix to support long paths?

Also, I just give one example where path math isn't being done because the \\?\ prefix is present (presumably). Should this be and remain this way?

private const string PWD = "<PWD>";
[Theory]
[InlineData(@"\\?\.", @"\\?\" + PWD)]
[InlineData(@"\\?\C:\Users\..", @"\\?\C:\")]
public void GetFullPath(string path, string expected) {
    if (expected is object) expected = expected.Replace(PWD, Environment.CurrentDirectory);
    var actual = Path.GetFullPath(path);
    Assert.Equal(expected, actual);
}

First result

  Message: 
    Assert.Equal() Failure
                  ↓ (pos 4)
    Expected: \\?\C:\Users\(...)\b.Tests\b···
    Actual:   \\?\.
                  ↑ (pos 4)

Second result

  Message: 
    Assert.Equal() Failure
                     ↓ (pos 7)
    Expected: \\?\C:\
    Actual:   \\?\C:\Users\..
                     ↑ (pos 7)

Configuration

Same on netcoreapp3.1 as on net5.0

> dotnet --list-sdks
3.1.301 [C:\Program Files\dotnet\sdk]
3.1.400-preview-015178 [C:\Program Files\dotnet\sdk]
5.0.100-preview.5.20279.10 [C:\Program Files\dotnet\sdk]

Regression?

Might be intended behavior.

Opinion

It could be useful to be able to do path math with \\?\ with an increasing number of machines able to use long paths since recent versions of Windows.

@Dotnet-GitSync-Bot
Copy link
Collaborator

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Jul 14, 2020
@hoyosjs hoyosjs added question Answer questions and provide assistance, not an issue with source code or documentation. area-System.IO labels Jul 14, 2020
@ericwj
Copy link
Author

ericwj commented Jul 15, 2020

The relevant documentations is here:

Scrolling slightly up, the section above that reads (emphasis mine):

The "\\?\" prefix (...) indicate that the path should be passed to the system with minimal modification, which means that you cannot use forward slashes to represent path separators, or a period to represent the current directory, or double dots to represent the parent directory.

But this does not mean that .NET API's might not provide support for doing path math and support . and .. before passing paths to the Win32 API if . and .. could not appear in valid paths with "\\?\" otherwise.

Besides long paths on systems not configured to accept them without \\?\, an oddity that might make such support by .NET handy is in rare, perhaps ill-adviced, but valid situations where applications might encounter GPT volume identifiers, e.g. \\?\Volume{bc850fae-cfcd-4783-9093-222ad1635ade}. These always requires the \\?\ prefix. Use of these paths may be required in the rare situation that the volume does not have any access path with a DOS device name.

Paths with \\?\ may be provided in several ways, amongst which as the working directory at application start, and they work with other API's such as Combine, GetPathRoot and GetDirectoryName.

@carlossanlop carlossanlop added this to the Future milestone Aug 6, 2020
@carlossanlop carlossanlop removed the untriaged New issue has not been triaged by the area owner label Aug 14, 2020
@carlossanlop
Copy link
Member

Thanks for the details.

We don't normalize paths prefixed with \\?\, and we are following the same behavior as Windows: a path with such prefix is considered as already normalized, and should not be modified.

Here is the relevant code in Path.GetFullPath:

if (PathInternal.IsExtended(path.AsSpan()))
{
// \\?\ paths are considered normalized by definition. Windows doesn't normalize \\?\
// paths and neither should we. Even if we wanted to GetFullPathName does not work
// properly with device paths. If one wants to pass a \\?\ path through normalization
// one can chop off the prefix, pass it to GetFullPath and add it again.
return path;
}

Here are a couple of articles that might interest you:

https://docs.microsoft.com/en-us/dotnet/standard/io/file-path-formats
https://docs.microsoft.com/en-us/archive/blogs/jeremykuhne/path-normalization <- Written by a former owner of System.IO.

@ericwj
Copy link
Author

ericwj commented Aug 16, 2020

Yes thanks for those links.

Stupid DOS Tricks

lol

Didn't know that \\?\C:\foo and \\?\C:\foo. would refer to different files. That is nasty.

What these don't say explicitly is that these paths with \\?\ are also always absolute paths, so, considering everything I know so far, \\?\. would mean the root of the DOS device namespace - referring to whatever 'current directory' would mean there, which can never exist unless by using an API that doesn't (necessarily) work with files only?

Copy link
Contributor

Due to lack of recent activity, this issue has been marked as a candidate for backlog cleanup. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will undo this process.

This process is part of our issue cleanup automation.

@dotnet-policy-service dotnet-policy-service bot added backlog-cleanup-candidate An inactive issue that has been marked for automated closure. no-recent-activity labels Feb 15, 2025
Copy link
Contributor

This issue will now be closed since it had been marked no-recent-activity but received no further activity in the past 14 days. It is still possible to reopen or comment on the issue, but please note that the issue will be locked if it remains inactive for another 30 days.

@dotnet-policy-service dotnet-policy-service bot removed this from the Future milestone Mar 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.IO backlog-cleanup-candidate An inactive issue that has been marked for automated closure. no-recent-activity question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
None yet
Development

No branches or pull requests

4 participants