Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs')
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs66
1 files changed, 44 insertions, 22 deletions
diff --git a/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs b/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs
index 74ceed10a..bada2f5cd 100644
--- a/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/PathHelper.Windows.cs
@@ -26,30 +26,57 @@ namespace System.IO
internal static string Normalize(string path)
{
Span<char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
- ValueStringBuilder builder = new ValueStringBuilder(initialBuffer);
+ var builder = new ValueStringBuilder(initialBuffer);
// Get the full path
- GetFullPathName(path, ref builder);
+ GetFullPathName(path.AsSpan(), ref builder);
// If we have the exact same string we were passed in, don't allocate another string.
// TryExpandShortName does this input identity check.
- string result = builder.AsSpan().Contains('~')
+ string result = builder.AsSpan().IndexOf('~') >= 0
? TryExpandShortFileName(ref builder, originalPath: path)
- : builder.AsSpan().Equals(path.AsSpan()) ? path : builder.ToString();
+ : builder.AsSpan().Equals(path.AsSpan(), StringComparison.Ordinal) ? path : builder.ToString();
// Clear the buffer
builder.Dispose();
return result;
}
- private static void GetFullPathName(string path, ref ValueStringBuilder builder)
+ /// <summary>
+ /// Normalize the given path.
+ /// </summary>
+ /// <remarks>
+ /// Exceptions are the same as the string overload.
+ /// </remarks>
+ internal static string Normalize(ref ValueStringBuilder path)
+ {
+ Span<char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
+ var builder = new ValueStringBuilder(initialBuffer);
+
+ // Get the full path
+ GetFullPathName(path.AsSpan(terminate: true), ref builder);
+
+ string result = builder.AsSpan().IndexOf('~') >= 0
+ ? TryExpandShortFileName(ref builder, originalPath: null)
+ : builder.ToString();
+
+ // Clear the buffer
+ builder.Dispose();
+ return result;
+ }
+
+ /// <summary>
+ /// Calls GetFullPathName on the given path.
+ /// </summary>
+ /// <param name="path">The path name. MUST be null terminated after the span.</param>
+ private static void GetFullPathName(ReadOnlySpan<char> path, ref ValueStringBuilder builder)
{
// If the string starts with an extended prefix we would need to remove it from the path before we call GetFullPathName as
// it doesn't root extended paths correctly. We don't currently resolve extended paths, so we'll just assert here.
Debug.Assert(PathInternal.IsPartiallyQualified(path) || !PathInternal.IsExtended(path));
uint result = 0;
- while ((result = Interop.Kernel32.GetFullPathNameW(path, (uint)builder.Capacity, ref builder.GetPinnableReference(), IntPtr.Zero)) > builder.Capacity)
+ while ((result = Interop.Kernel32.GetFullPathNameW(ref MemoryMarshal.GetReference(path), (uint)builder.Capacity, ref builder.GetPinnableReference(), IntPtr.Zero)) > builder.Capacity)
{
// Reported size is greater than the buffer size. Increase the capacity.
builder.EnsureCapacity(checked((int)result));
@@ -61,13 +88,13 @@ namespace System.IO
int errorCode = Marshal.GetLastWin32Error();
if (errorCode == 0)
errorCode = Interop.Errors.ERROR_BAD_PATHNAME;
- throw Win32Marshal.GetExceptionForWin32Error(errorCode, path);
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, path.ToString());
}
builder.Length = (int)result;
}
- private static int PrependDevicePathChars(ref ValueStringBuilder content, bool isDosUnc, ref ValueStringBuilder buffer)
+ internal static int PrependDevicePathChars(ref ValueStringBuilder content, bool isDosUnc, ref ValueStringBuilder buffer)
{
int length = content.Length;
@@ -84,7 +111,7 @@ namespace System.IO
buffer.Append(PathInternal.UncExtendedPathPrefix);
// Copy Server\Share\... over to the buffer
- buffer.Append(content.AsSpan().Slice(PathInternal.UncPrefixLength));
+ buffer.Append(content.AsSpan(PathInternal.UncPrefixLength));
// Return the prefix difference
return PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength;
@@ -98,7 +125,7 @@ namespace System.IO
}
}
- private static string TryExpandShortFileName(ref ValueStringBuilder outputBuilder, string originalPath)
+ internal static string TryExpandShortFileName(ref ValueStringBuilder outputBuilder, string originalPath)
{
// We guarantee we'll expand short names for paths that only partially exist. As such, we need to find the part of the path that actually does exist. To
// avoid allocating like crazy we'll create only one input array and modify the contents with embedded nulls.
@@ -119,7 +146,7 @@ namespace System.IO
bool isDevice = PathInternal.IsDevice(outputBuilder.AsSpan());
// As this is a corner case we're not going to add a stackalloc here to keep the stack pressure down.
- ValueStringBuilder inputBuilder = new ValueStringBuilder();
+ var inputBuilder = new ValueStringBuilder();
bool isDosUnc = false;
int rootDifference = 0;
@@ -149,12 +176,10 @@ namespace System.IO
bool success = false;
int foundIndex = inputBuilder.Length - 1;
- // Need to null terminate the input builder
- inputBuilder.Append('\0');
-
while (!success)
{
- uint result = Interop.Kernel32.GetLongPathNameW(ref inputBuilder.GetPinnableReference(), ref outputBuilder.GetPinnableReference(), (uint)outputBuilder.Capacity);
+ uint result = Interop.Kernel32.GetLongPathNameW(
+ ref inputBuilder.GetPinnableReference(terminate: true), ref outputBuilder.GetPinnableReference(), (uint)outputBuilder.Capacity);
// Replace any temporary null we added
if (inputBuilder[foundIndex] == '\0') inputBuilder[foundIndex] = '\\';
@@ -198,14 +223,11 @@ namespace System.IO
if (foundIndex < inputLength - 1)
{
// It was a partial find, put the non-existent part of the path back
- outputBuilder.Append(inputBuilder.AsSpan().Slice(foundIndex, inputBuilder.Length - foundIndex));
+ outputBuilder.Append(inputBuilder.AsSpan(foundIndex, inputBuilder.Length - foundIndex));
}
}
}
- // 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);
@@ -218,10 +240,10 @@ namespace System.IO
builderToUse[PathInternal.UncExtendedPrefixLength - PathInternal.UncPrefixLength] = '\\';
// Strip out any added characters at the front of the string
- ReadOnlySpan<char> output = builderToUse.AsSpan().Slice(rootDifference);
+ ReadOnlySpan<char> output = builderToUse.AsSpan(rootDifference);
- string returnValue = output.Equals(originalPath.AsSpan())
- ? originalPath : new string(output);
+ string returnValue = ((originalPath != null) && output.Equals(originalPath.AsSpan(), StringComparison.Ordinal))
+ ? originalPath : output.ToString();
inputBuilder.Dispose();
return returnValue;