dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
15.42k stars 4.75k forks source link

GetPathRoot cannot handle UNC paths on unix. #109594

Open crone66 opened 2 weeks ago

crone66 commented 2 weeks ago

Description

System.IO.Path.GetPathRoot() seem to have a strange behavior when using UNC paths on a unix system. Maybe I just don't know how UNC paths are supposed to look like on UNIX but maybe someone can explain whats going on here.

Let's assume we have the UNC path @"\\server\share". If I pass the path to GetPathRoot(path) I would assume the same path as result. On windows this works perfectly but on Unix (tested with Ubuntu 24.4) the result is "". My initial thought was maybe I have to use forward slashes since unix and backward slashs might not work. But when using forward slashes (@"//server/share") the result is even more strange. Since the directory seperator is normalized when using the string overload, windows returns @"\\server\share" but unix returns "/", From my point of view the UNIX result doesn't make sense. I checked the code and the implementations are very different for both platforms. For Unix we just check if the the first character is a forward slash and if yes just return a forward slash not taking into account UNC path.

From what I've read online on multiple sources e.g. https://en.linuxportal.info/encyclopedia/u/unc-universal-naming-convention "//server/share" should be a valid UNC path and therefore be handled as such when using System.IO.Path methods.

Was this a oversight or are my assumptions about UNC paths on UNIX incorrect or is there any other reason for this behavior that I'm not aware of?

Thank you.

Reproduction Steps

Execute the following line on Windows and a Unix system (tested with Ubuntu 24.4)

Console.WriteLine(System.IO.Path.GetPathRoot(@"\\server\share"));

Result: Windows: "\server\share" Unix: ""

Console.WriteLine(System.IO.Path.GetPathRoot(@"//server/share"));

Result: Windows: "\server\share" Unix: "/"

Expected behavior

Console.WriteLine(System.IO.Path.GetPathRoot(@"\\server\share"));

Result: Windows: "\server\share" Unix: "" might be okay but maybe "//server/share" or "\server\share" would be good to

Console.WriteLine(System.IO.Path.GetPathRoot(@"//server/share"));

Result: Windows: "\server\share" Unix: "//server/share" or "\server\share" whatever makes more sense and fits the specification.

Actual behavior

Console.WriteLine(System.IO.Path.GetPathRoot(@"\\server\share"));

Result: Windows: "\server\share" Unix: ""

Console.WriteLine(System.IO.Path.GetPathRoot(@"//server/share"));

Result: Windows: "\server\share" Unix: "/"

Regression?

No response

Known Workarounds

No response

Configuration

Tested on Windows 10 & 11 64 Bit and Ubuntu 24.4 (WSL)

Other information

System.IO.Path.GetPathRoot() is used by other methods such as System.IO.Path.GetDirectoryName() which currently causes weird path modification on UNIX.

Example: path: "//server/share" -> result: "/server/share"

karakasa commented 2 weeks ago

The current doc seemingly implies the method works with UNC paths only on Windows.

  • "\ComputerName\SharedFolder" (Windows: a UNC path).

don't know if this is a design choice, as Linux requires SMB path to be mounted to become "valid".

crone66 commented 2 weeks ago

If this is the case many places in the documentation should mention it too.

If you call GetDirectoryName("\\server\share") the documentation says null should be returned (no platform specified) but on unix empty string is returned. With forward slashes on Unix "/server" is returned (a slash at the start was removed for some reason). Windows works as expected. Essentially everything that uses GetPathRoot() internally has to mention that UNC paths only work on Windows, but thats currently not the cases.

colejohnson66 commented 2 weeks ago

UNC paths are a Windows-ism. Linux requires everything be mounted into the / hierarchy. There are many issues with the docs being Windows-centric: https://github.com/dotnet/dotnet-api-docs/issues/9661