From 4e6c1ef2ee5000dc0b9823146210d9bd87787d9f Mon Sep 17 00:00:00 2001 From: Jeremy Kuhne Date: Sat, 24 Feb 2018 21:01:54 -0800 Subject: [PATCH] Fix path issues Path tests weren't running so a few issues sneaked in. --- src/mscorlib/shared/System/IO/Path.cs | 2 +- .../shared/System/IO/PathHelper.Windows.cs | 3 +++ .../shared/System/IO/PathInternal.Windows.cs | 25 ++++++++++++++----- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/mscorlib/shared/System/IO/Path.cs b/src/mscorlib/shared/System/IO/Path.cs index 7685099a5cce..586ddf3a6998 100644 --- a/src/mscorlib/shared/System/IO/Path.cs +++ b/src/mscorlib/shared/System/IO/Path.cs @@ -79,7 +79,7 @@ public static string ChangeExtension(string path, string extension) /// public static string GetDirectoryName(string path) { - if (PathInternal.IsEffectivelyEmpty(path)) + if (path == null || PathInternal.IsEffectivelyEmpty(path)) return null; int end = GetDirectoryNameOffset(path); diff --git a/src/mscorlib/shared/System/IO/PathHelper.Windows.cs b/src/mscorlib/shared/System/IO/PathHelper.Windows.cs index dda9b2c4de5e..039a28834190 100644 --- a/src/mscorlib/shared/System/IO/PathHelper.Windows.cs +++ b/src/mscorlib/shared/System/IO/PathHelper.Windows.cs @@ -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); diff --git a/src/mscorlib/shared/System/IO/PathInternal.Windows.cs b/src/mscorlib/shared/System/IO/PathInternal.Windows.cs index 95bd0625d80a..433d6b6a3eb4 100644 --- a/src/mscorlib/shared/System/IO/PathInternal.Windows.cs +++ b/src/mscorlib/shared/System/IO/PathInternal.Windows.cs @@ -129,6 +129,19 @@ internal static bool IsDevice(ReadOnlySpan path) ); } + /// + /// Returns true if the path is a device UNC (\\?\UNC\, \\.\UNC\) + /// + internal static bool IsDeviceUNC(ReadOnlySpan path) + { + return path.Length >= UncExtendedPrefixLength + && IsDevice(path) + && IsDirectorySeparator(path[7]) + && path[4] == 'U' + && path[5] == 'N' + && path[6] == 'C'; + } + /// /// 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 @@ -178,12 +191,12 @@ internal static int GetRootLength(ReadOnlySpan 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); + 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; @@ -195,12 +208,12 @@ internal static int GetRootLength(ReadOnlySpan 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\)