Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/mscorlib/shared/System/IO/Path.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public static string ChangeExtension(string path, string extension)
/// </remarks>
public static string GetDirectoryName(string path)
{
if (PathInternal.IsEffectivelyEmpty(path))
if (path == null || PathInternal.IsEffectivelyEmpty(path))
return null;

int end = GetDirectoryNameOffset(path);
Expand Down
3 changes: 3 additions & 0 deletions src/mscorlib/shared/System/IO/PathHelper.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ private static string TryExpandShortFileName(ref ValueStringBuilder outputBuilde
}
}

// Need to trim out the trailing separator in the input builder
inputBuilder.Length = inputBuilder.Length - 1;

// If we were able to expand the path, use it, otherwise use the original full path result
ref ValueStringBuilder builderToUse = ref (success ? ref outputBuilder : ref inputBuilder);

Expand Down
25 changes: 19 additions & 6 deletions src/mscorlib/shared/System/IO/PathInternal.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,19 @@ internal static bool IsDevice(ReadOnlySpan<char> path)
);
}

/// <summary>
/// Returns true if the path is a device UNC (\\?\UNC\, \\.\UNC\)
/// </summary>
internal static bool IsDeviceUNC(ReadOnlySpan<char> path)
{
return path.Length >= UncExtendedPrefixLength
&& IsDevice(path)
&& IsDirectorySeparator(path[7])
&& path[4] == 'U'
&& path[5] == 'N'
&& path[6] == 'C';
}

/// <summary>
/// Returns true if the path uses the canonical form of extended syntax ("\\?\" or "\??\"). If the
/// path matches exactly (cannot use alternate directory separators) Windows will skip normalization
Expand Down Expand Up @@ -178,12 +191,12 @@ internal static int GetRootLength(ReadOnlySpan<char> path)
int volumeSeparatorLength = 2; // Length to the colon "C:"
int uncRootLength = 2; // Length to the start of the server name "\\"

bool extendedSyntax = StartsWithOrdinal(path, ExtendedPathPrefix);
bool extendedUncSyntax = StartsWithOrdinal(path, UncExtendedPathPrefix);
if (extendedSyntax)
bool deviceSyntax = IsDevice(path);
bool deviceUnc = deviceSyntax && IsDeviceUNC(path);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that IsDeviceUNC also calls IsDevice itself.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You coudl take off deviceSyntax &&

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that was intentional. Skipping the method call for a bool check.

if (deviceSyntax)
{
// Shift the position we look for the root from to account for the extended prefix
if (extendedUncSyntax)
if (deviceUnc)
{
// "\\" -> "\\?\UNC\"
uncRootLength = UncExtendedPathPrefix.Length;
Expand All @@ -195,12 +208,12 @@ internal static int GetRootLength(ReadOnlySpan<char> path)
}
}

if ((!extendedSyntax || extendedUncSyntax) && pathLength > 0 && IsDirectorySeparator(path[0]))
if ((!deviceSyntax || deviceUnc) && pathLength > 0 && IsDirectorySeparator(path[0]))
{
// UNC or simple rooted path (e.g. "\foo", NOT "\\?\C:\foo")

i = 1; // Drive rooted (\foo) is one character
if (extendedUncSyntax || (pathLength > 1 && IsDirectorySeparator(path[1])))
if (deviceUnc || (pathLength > 1 && IsDirectorySeparator(path[1])))
{
// UNC (\\?\UNC\ or \\), scan past the next two directory separators at most
// (e.g. to \\?\UNC\Server\Share or \\Server\Share\)
Expand Down