diff --git a/src/libraries/Common/src/Interop/Windows/mincore/Interop.CreateDirectory.cs b/src/libraries/Common/src/Interop/Windows/mincore/Interop.CreateDirectory.cs index 3b603dadd8b13..1432d339f51a0 100644 --- a/src/libraries/Common/src/Interop/Windows/mincore/Interop.CreateDirectory.cs +++ b/src/libraries/Common/src/Interop/Windows/mincore/Interop.CreateDirectory.cs @@ -14,7 +14,8 @@ internal partial class mincore internal static bool CreateDirectory(string path, ref SECURITY_ATTRIBUTES lpSecurityAttributes) { - path = PathInternal.AddExtendedPathPrefixForLongPaths(path); + // We always want to add for CreateDirectory to get around the legacy 248 character limitation + path = PathInternal.AddExtendedPathPrefix(path); return CreateDirectoryPrivate(path, ref lpSecurityAttributes); } } diff --git a/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetFullPathNameW.cs b/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetFullPathNameW.cs index 2435e69694d7d..a78d9ce5f2b0a 100644 --- a/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetFullPathNameW.cs +++ b/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetFullPathNameW.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; +using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -9,10 +10,30 @@ partial class Interop { partial class mincore { + /// + /// WARNING: This overload does not implicitly handle long paths. + /// [DllImport(Libraries.CoreFile_L1, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] internal unsafe static extern int GetFullPathNameW(char* path, int numBufferChars, char* buffer, IntPtr mustBeZero); - [DllImport(Libraries.CoreFile_L1, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] - internal static extern int GetFullPathNameW(string path, int numBufferChars, [Out]StringBuilder buffer, IntPtr mustBeZero); + [DllImport(Libraries.CoreFile_L1, EntryPoint = "GetFullPathNameW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] + private static extern int GetFullPathNameWPrivate(string path, int numBufferChars, [Out]StringBuilder buffer, IntPtr mustBeZero); + + internal static int GetFullPathNameW(string path, int numBufferChars, [Out]StringBuilder buffer, IntPtr mustBeZero) + { + bool wasExtended = PathInternal.IsExtended(path); + if (!wasExtended) + { + path = PathInternal.AddExtendedPathPrefixForLongPaths(path); + } + int result = GetFullPathNameWPrivate(path, buffer.Capacity, buffer, mustBeZero); + + if (!wasExtended) + { + // We don't want to give back \\?\ if we possibly added it ourselves + PathInternal.RemoveExtendedPathPrefix(buffer); + } + return result; + } } } diff --git a/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetLongPathNameW.cs b/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetLongPathNameW.cs index 41078977242ac..a28c275e5b553 100644 --- a/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetLongPathNameW.cs +++ b/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetLongPathNameW.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.IO; using System.Text; using System.Runtime.InteropServices; @@ -8,10 +9,30 @@ partial class Interop { partial class mincore { + /// + /// WARNING: This overload does not implicitly handle long paths. + /// [DllImport(Libraries.CoreFile_L1, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] internal unsafe static extern int GetLongPathNameW(char* path, char* longPathBuffer, int bufferLength); - [DllImport(Libraries.CoreFile_L1, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] - internal static extern int GetLongPathNameW(string path, [Out]StringBuilder longPathBuffer, int bufferLength); + [DllImport(Libraries.CoreFile_L1, EntryPoint = "GetLongPathNameW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] + private static extern int GetLongPathNameWPrivate(string path, [Out]StringBuilder longPathBuffer, int bufferLength); + + internal static int GetLongPathNameW(string path, [Out]StringBuilder longPathBuffer, int bufferLength) + { + bool wasExtended = PathInternal.IsExtended(path); + if (!wasExtended) + { + path = PathInternal.AddExtendedPathPrefixForLongPaths(path); + } + int result = GetLongPathNameWPrivate(path, longPathBuffer, longPathBuffer.Capacity); + + if (!wasExtended) + { + // We don't want to give back \\?\ if we possibly added it ourselves + PathInternal.RemoveExtendedPathPrefix(longPathBuffer); + } + return result; + } } } diff --git a/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetTempPathW.cs b/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetTempPathW.cs index ec2b41794324d..4f80fc7ce328b 100644 --- a/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetTempPathW.cs +++ b/src/libraries/Common/src/Interop/Windows/mincore/Interop.GetTempPathW.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System.IO; using System.Text; using System.Runtime.InteropServices; diff --git a/src/libraries/Common/src/System/IO/PathInternal.Windows.cs b/src/libraries/Common/src/System/IO/PathInternal.Windows.cs index f30d5c3ca3166..a8402e178c9c4 100644 --- a/src/libraries/Common/src/System/IO/PathInternal.Windows.cs +++ b/src/libraries/Common/src/System/IO/PathInternal.Windows.cs @@ -16,7 +16,7 @@ internal static partial class PathInternal internal const string DevicePathPrefix = @"\\.\"; internal const int MaxShortPath = 260; internal const int MaxShortDirectoryPath = 248; - internal const int MaxExtendedPath = short.MaxValue; + internal const int MaxLongPath = short.MaxValue; internal static readonly char[] InvalidPathChars = { @@ -41,16 +41,29 @@ internal static partial class PathInternal /// internal static bool IsPathTooLong(string fullPath) { + // We'll never know precisely what will fail as paths get changed internally in Windows and + // may grow to exceed MaxExtendedPath. We'll only try to catch ones we know will absolutely + // fail. + + if (fullPath.Length < MaxLongPath - UncExtendedPathPrefix.Length) + { + // We won't push it over MaxLongPath + return false; + } + + // We need to check if we have a prefix to account for one being implicitly added. if (IsExtended(fullPath)) { - return fullPath.Length >= MaxExtendedPath; + // We won't prepend, just check + return fullPath.Length >= MaxLongPath; } - else + + if (fullPath.StartsWith(UncPathPrefix, StringComparison.Ordinal)) { - // Will need to be updated with #2581 to allow all paths to MaxExtendedPath - // minus legth of extended local or UNC prefix. - return fullPath.Length >= MaxShortPath; + return fullPath.Length + UncExtendedPrefixToInsert.Length >= MaxLongPath; } + + return fullPath.Length + ExtendedPathPrefix.Length >= MaxLongPath; } /// @@ -58,16 +71,7 @@ internal static bool IsPathTooLong(string fullPath) /// internal static bool IsDirectoryTooLong(string fullPath) { - if (IsExtended(fullPath)) - { - return fullPath.Length >= MaxExtendedPath; - } - else - { - // Will need to be updated with #2581 to allow all paths to MaxExtendedPath - // minus legth of extended local or UNC prefix. - return fullPath.Length >= MaxShortDirectoryPath; - } + return IsPathTooLong(fullPath); } /// @@ -272,17 +276,17 @@ internal static bool IsPathRelative(string path) return true; } - if ((path[0] == '\\') || (path[0] == '/')) + if (IsDirectorySeparator(path[0])) { // There is no valid way to specify a relative path with two initial slashes - return !((path[1] == '\\') || (path[1] == '/')); + return !(IsDirectorySeparator(path[1])); } // The only way to specify a fixed path that doesn't begin with two slashes // is the drive, colon, slash format- i.e. C:\ return !((path.Length >= 3) - && (path[1] == ':') - && ((path[2] == '\\') || (path[2] == '/'))); + && (path[1] == Path.VolumeSeparatorChar) + && (IsDirectorySeparator(path[2]))); } internal static bool IsDirectorySeparator(char c) diff --git a/src/libraries/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs b/src/libraries/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs index c0a7d15571cf9..664774729283b 100644 --- a/src/libraries/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs +++ b/src/libraries/Common/tests/Tests/System/IO/PathInternal.Windows.Tests.cs @@ -29,6 +29,8 @@ public void AddExtendedPathPrefixTest(string path, string expected) InlineData(@"\\?", false), InlineData(@"\\", false), InlineData(@"//", false), + InlineData(@"\a", true), + InlineData(@"/a", true), InlineData(@"\", true), InlineData(@"/", true), InlineData(@"C:Path", true), @@ -36,6 +38,7 @@ public void AddExtendedPathPrefixTest(string path, string expected) InlineData(@"\\?\C:\Path", false), InlineData(@"Path", true), InlineData(@"X", true)] + [PlatformSpecific(PlatformID.Windows)] public void IsPathRelative(string path, bool expected) { Assert.Equal(expected, PathInternal.IsPathRelative(path)); diff --git a/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs b/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs index c7d6eb6df2e5d..421ee187e0319 100644 --- a/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs +++ b/src/libraries/System.IO.FileSystem/tests/Directory/CreateDirectory.cs @@ -210,20 +210,44 @@ public void DirectoryWithComponentLongerThanMaxComponentAsPath_ThrowsPathTooLong [Fact] [PlatformSpecific(PlatformID.Windows)] - public void DirectoryLongerThanMaxPathAsPath_ThrowsPathTooLongException() + public void DirectoryLongerThanMaxPath_Succeeds() { var paths = IOInputs.GetPathsLongerThanMaxPath(); Assert.All(paths, (path) => + { + DirectoryInfo result = Create(path); + Assert.True(Directory.Exists(result.FullName)); + }); + } + + [Fact] + [PlatformSpecific(PlatformID.Windows)] + public void DirectoryLongerThanMaxLongPath_ThrowsPathTooLongException() + { + var paths = IOInputs.GetPathsLongerThanMaxLongPath(); + Assert.All(paths, (path) => + { + Assert.Throws(() => Create(path)); + }); + } + + [Fact] + [PlatformSpecific(PlatformID.Windows)] + public void DirectoryLongerThanMaxLongPathWithExtendedSyntax_ThrowsPathTooLongException() + { + var paths = IOInputs.GetPathsLongerThanMaxLongPath(useExtendedSyntax: true); + Assert.All(paths, (path) => { Assert.Throws(() => Create(path)); }); } + [Fact] [PlatformSpecific(PlatformID.Windows)] - public void ExtendedDirectoryLongerThanLegacyMaxPathSucceeds() + public void ExtendedDirectoryLongerThanLegacyMaxPath_Succeeds() { - var paths = IOInputs.GetPathsLongerThanMaxPath(useExtendedSyntax: true, includeExtendedMaxPath: false); + var paths = IOInputs.GetPathsLongerThanMaxPath(useExtendedSyntax: true); Assert.All(paths, (path) => { Assert.True(Create(path).Exists); @@ -232,12 +256,13 @@ public void ExtendedDirectoryLongerThanLegacyMaxPathSucceeds() [Fact] [PlatformSpecific(PlatformID.Windows)] - public void DirectoryLongerThanMaxDirectoryAsPath_ThrowsPathTooLongException() + public void DirectoryLongerThanMaxDirectoryAsPath_Succeeds() { var paths = IOInputs.GetPathsLongerThanMaxDirectory(); Assert.All(paths, (path) => { - Assert.Throws(() => Create(path)); + var result = Create(path); + Assert.True(Directory.Exists(result.FullName)); }); } diff --git a/src/libraries/System.IO.FileSystem/tests/Directory/Exists.cs b/src/libraries/System.IO.FileSystem/tests/Directory/Exists.cs index f01bd4a89c0a3..42e03c760c803 100644 --- a/src/libraries/System.IO.FileSystem/tests/Directory/Exists.cs +++ b/src/libraries/System.IO.FileSystem/tests/Directory/Exists.cs @@ -105,9 +105,9 @@ public void DotDotAsPath_ReturnsTrue() } [Fact] - public void DirectoryLongerThanMaxPathAsPath_DoesntThrow() + public void DirectoryLongerThanMaxLongPath_DoesntThrow() { - Assert.All((IOInputs.GetPathsLongerThanMaxPath()), (path) => + Assert.All((IOInputs.GetPathsLongerThanMaxLongPath()), (path) => { Assert.False(Exists(path), path); }); diff --git a/src/libraries/System.IO.FileSystem/tests/Directory/Move.cs b/src/libraries/System.IO.FileSystem/tests/Directory/Move.cs index f2b010b9652de..9914d14ec435f 100644 --- a/src/libraries/System.IO.FileSystem/tests/Directory/Move.cs +++ b/src/libraries/System.IO.FileSystem/tests/Directory/Move.cs @@ -127,11 +127,11 @@ public void IncludeSubdirectories() } [Fact] - public void Path_Longer_Than_MaxPath_Throws_Exception() + public void Path_Longer_Than_MaxLongPath_Throws_Exception() { string testDir = GetTestFilePath(); Directory.CreateDirectory(testDir); - Assert.All((IOInputs.GetPathsLongerThanMaxPath()), (path) => + Assert.All((IOInputs.GetPathsLongerThanMaxLongPath()), (path) => { Assert.Throws(() => Move(testDir, path)); Assert.Throws(() => Move(path, testDir)); @@ -144,14 +144,26 @@ public void Path_Longer_Than_MaxPath_Throws_Exception() [Fact] [PlatformSpecific(PlatformID.Windows)] - public void Path_With_Longer_Than_MaxDirectory_Throws_Exception() + public void Path_With_Longer_Than_MaxDirectory_Succeeds() { string testDir = GetTestFilePath(); Directory.CreateDirectory(testDir); + Assert.True(Directory.Exists(testDir), "test directory should exist"); Assert.All((IOInputs.GetPathsLongerThanMaxDirectory()), (path) => { - Assert.Throws(() => Move(testDir, path)); - Assert.Throws(() => Move(path, testDir)); + string baseDestinationPath = Path.GetDirectoryName(path); + if (!Directory.Exists(baseDestinationPath)) + { + Directory.CreateDirectory(baseDestinationPath); + } + Assert.True(Directory.Exists(baseDestinationPath), "base destination path should exist"); + + Move(testDir, path); + Assert.False(Directory.Exists(testDir), "source directory should exist"); + Assert.True(Directory.Exists(path), "destination directory should exist"); + Move(path, testDir); + Assert.False(Directory.Exists(path), "source directory should exist"); + Assert.True(Directory.Exists(testDir), "destination directory should exist"); }); } diff --git a/src/libraries/System.IO.FileSystem/tests/File/Move.cs b/src/libraries/System.IO.FileSystem/tests/File/Move.cs index ca4d72650d002..a4038a2f49ed8 100644 --- a/src/libraries/System.IO.FileSystem/tests/File/Move.cs +++ b/src/libraries/System.IO.FileSystem/tests/File/Move.cs @@ -144,13 +144,43 @@ public void FileNameWithSignificantWhitespace() } [Fact] + [PlatformSpecific(PlatformID.Windows)] + public void MaxPath_Windows() + { + // Create a destination path longer than the traditional Windows limit of 256 characters, + // but under the long path limitation (32K). + + string testFileSource = Path.Combine(TestDirectory, GetTestFileName()); + File.Create(testFileSource).Dispose(); + Assert.True(File.Exists(testFileSource), "test file should exist"); + + Assert.All(IOInputs.GetPathsLongerThanMaxPath(), (path) => + { + string baseDestinationPath = Path.GetDirectoryName(path); + if (!Directory.Exists(baseDestinationPath)) + { + Directory.CreateDirectory(baseDestinationPath); + } + Assert.True(Directory.Exists(baseDestinationPath), "base destination path should exist"); + + Move(testFileSource, path); + Assert.True(File.Exists(path), "moved test file should exist"); + File.Delete(testFileSource); + Assert.False(File.Exists(testFileSource), "source test file should not exist"); + Move(path, testFileSource); + Assert.True(File.Exists(testFileSource), "restored test file should exist"); + }); + } + + [Fact] + [PlatformSpecific(PlatformID.AnyUnix)] public void LongPath() { //Create a destination path longer than the traditional Windows limit of 256 characters string testFileSource = Path.Combine(TestDirectory, GetTestFileName()); File.Create(testFileSource).Dispose(); - Assert.All(IOInputs.GetPathsLongerThanMaxPath(), (path) => + Assert.All(IOInputs.GetPathsLongerThanMaxLongPath(), (path) => { Assert.Throws(() => Move(testFileSource, path)); File.Delete(testFileSource); diff --git a/src/libraries/System.IO.FileSystem/tests/PortedCommon/IOInputs.cs b/src/libraries/System.IO.FileSystem/tests/PortedCommon/IOInputs.cs index 0591a514dbf0c..4cc08ea854d7f 100644 --- a/src/libraries/System.IO.FileSystem/tests/PortedCommon/IOInputs.cs +++ b/src/libraries/System.IO.FileSystem/tests/PortedCommon/IOInputs.cs @@ -21,13 +21,18 @@ internal static class IOInputs // Max path length (minus trailing \0). Unix values vary system to system; just using really long values here likely to be more than on the average system. public static readonly int MaxPath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 259 : 10000; + // Same as MaxPath on Unix + public static readonly int MaxLongPath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? MaxExtendedPath : MaxPath; + // Windows specific, this is the maximum length that can be passed to APIs taking directory names, such as Directory.CreateDirectory & Directory.Move. // Does not include the trailing \0. + // We now do the appropriate wrapping to allow creating longer directories. Like MaxPath, this is a legacy restriction. public static readonly int MaxDirectory = 247; // Windows specific, this is the maximum length that can be passed using extended syntax. Does not include the trailing \0. public static readonly int MaxExtendedPath = short.MaxValue - 1; + public const int MaxComponent = 255; public const string ExtendedPrefix = @"\\?\"; @@ -218,16 +223,17 @@ public static IEnumerable GetPathsLongerThanMaxDirectory() yield return GetLongPath(MaxDirectory + 3); } - public static IEnumerable GetPathsLongerThanMaxPath(bool useExtendedSyntax = false, bool includeExtendedMaxPath = true) + public static IEnumerable GetPathsLongerThanMaxPath(bool useExtendedSyntax = false) { yield return GetLongPath(MaxPath + 1, useExtendedSyntax); yield return GetLongPath(MaxPath + 2, useExtendedSyntax); yield return GetLongPath(MaxPath + 3, useExtendedSyntax); - if (includeExtendedMaxPath) - { - yield return GetLongPath(MaxExtendedPath + 1, useExtendedSyntax); - yield return GetLongPath(MaxExtendedPath + 2, useExtendedSyntax); - } + } + + public static IEnumerable GetPathsLongerThanMaxLongPath(bool useExtendedSyntax = false) + { + yield return GetLongPath(MaxExtendedPath + 1 - (useExtendedSyntax ? 0 : ExtendedPrefix.Length), useExtendedSyntax); + yield return GetLongPath(MaxExtendedPath + 2 - (useExtendedSyntax ? 0 : ExtendedPrefix.Length), useExtendedSyntax); } private static string GetLongPath(int characterCount, bool extended = false) diff --git a/src/libraries/System.Runtime.Extensions/src/System/IO/Path.Unix.cs b/src/libraries/System.Runtime.Extensions/src/System/IO/Path.Unix.cs index e3e25fbc77ca4..1e7cc016a727b 100644 --- a/src/libraries/System.Runtime.Extensions/src/System/IO/Path.Unix.cs +++ b/src/libraries/System.Runtime.Extensions/src/System/IO/Path.Unix.cs @@ -18,6 +18,7 @@ public static partial class Path private static readonly char[] InvalidFileNameChars = { '\0', '/' }; private static readonly int MaxPath = Interop.libc.MaxPath; + private static readonly int MaxLongPath = MaxPath; private static readonly int MaxComponentLength = Interop.libc.MaxName; private static bool IsDirectoryOrVolumeSeparator(char c) diff --git a/src/libraries/System.Runtime.Extensions/src/System/IO/Path.Windows.cs b/src/libraries/System.Runtime.Extensions/src/System/IO/Path.Windows.cs index a65e1b7eb545d..3ab932d0d3223 100644 --- a/src/libraries/System.Runtime.Extensions/src/System/IO/Path.Windows.cs +++ b/src/libraries/System.Runtime.Extensions/src/System/IO/Path.Windows.cs @@ -33,7 +33,7 @@ public static partial class Path // For example, D:\<256 char file name> isn't legal, even though it's under 260 chars. internal static readonly int MaxPath = 260; private static readonly int MaxComponentLength = 255; - private const int MaxLongPath = 32000; + internal static readonly int MaxLongPath = short.MaxValue; private static bool IsDirectoryOrVolumeSeparator(char c) { @@ -323,8 +323,10 @@ private unsafe static string NormalizePath(string path, bool fullCheck, int maxP } int thisPos = newBuffer.Length - 1; - if (thisPos - lastDirectorySeparatorPos > MaxComponentLength) + if (thisPos - lastDirectorySeparatorPos > MaxComponentLength + 1) { + // Components can be up to 255 characters plus an additional null, + // so separators can be 256 characters apart throw new PathTooLongException(SR.IO_PathTooLong); } lastDirectorySeparatorPos = thisPos; @@ -405,7 +407,8 @@ private unsafe static string NormalizePath(string path, bool fullCheck, int maxP index++; } // end while - if (newBuffer.Length - 1 - lastDirectorySeparatorPos > MaxComponentLength) + // Components can be up to 255 characters plus an additional null + if (newBuffer.Length - lastDirectorySeparatorPos > MaxComponentLength) { throw new PathTooLongException(SR.IO_PathTooLong); } diff --git a/src/libraries/System.Runtime.Extensions/src/System/IO/Path.cs b/src/libraries/System.Runtime.Extensions/src/System/IO/Path.cs index 7779628931b8c..73628bf2e231e 100644 --- a/src/libraries/System.Runtime.Extensions/src/System/IO/Path.cs +++ b/src/libraries/System.Runtime.Extensions/src/System/IO/Path.cs @@ -134,21 +134,15 @@ private static string GetFullPathInternal(string path) [System.Security.SecuritySafeCritical] // auto-generated private static string NormalizePath(string path, bool fullCheck) { - return NormalizePath(path, fullCheck, MaxPath); + return NormalizePath(path, fullCheck, MaxLongPath, expandShortPaths: true); } [System.Security.SecuritySafeCritical] // auto-generated private static string NormalizePath(string path, bool fullCheck, bool expandShortPaths) { - return NormalizePath(path, fullCheck, MaxPath, expandShortPaths); + return NormalizePath(path, fullCheck, MaxLongPath, expandShortPaths); } - - [System.Security.SecuritySafeCritical] // auto-generated - private static string NormalizePath(string path, bool fullCheck, int maxPathLength) - { - return NormalizePath(path, fullCheck, maxPathLength, expandShortPaths: true); - } - + // Returns the name and extension parts of the given path. The resulting // string contains the characters of path that follow the last // separator in path. The resulting string is null if path is null. diff --git a/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests.cs b/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests.cs index 0172718f283ba..ec314f4b4cf02 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/IO/PathTests.cs @@ -408,7 +408,9 @@ public static void GetFullPath_Windows_NormalizedLongPathTooLong() { longPath.Append(Path.DirectorySeparatorChar).Append('a').Append(Path.DirectorySeparatorChar).Append('.'); } - Assert.Throws(() => Path.GetFullPath(longPath.ToString())); + + // Now no longer throws unless over ~32K + Assert.NotNull(Path.GetFullPath(longPath.ToString())); } [PlatformSpecific(PlatformID.Windows)] @@ -453,11 +455,19 @@ public static void GetFullPath_Windows_ArgumentExceptionPaths(string path) Assert.Throws(() => Path.GetFullPath(path)); } + [PlatformSpecific(PlatformID.Windows)] + [Fact] + public static void GetFullPath_Windows_MaxPathNotTooLong() + { + // Shouldn't throw anymore + Path.GetFullPath(@"C:\" + new string('a', 255) + @"\"); + } + [PlatformSpecific(PlatformID.Windows)] [Fact] public static void GetFullPath_Windows_PathTooLong() { - Assert.Throws(() => Path.GetFullPath(@"C:\" + new string('a', 255) + @"\")); + Assert.Throws(() => Path.GetFullPath(@"C:\" + new string('a', short.MaxValue) + @"\")); } [PlatformSpecific(PlatformID.Windows)]