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/Path.Windows.cs')
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs101
1 files changed, 72 insertions, 29 deletions
diff --git a/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs b/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs
index b921db9e6..ddfd7966b 100644
--- a/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs
@@ -5,7 +5,14 @@
using System.Diagnostics;
using System.Text;
+#if MS_IO_REDIST
+using System;
+using System.IO;
+
+namespace Microsoft.IO
+#else
namespace System.IO
+#endif
{
public static partial class Path
{
@@ -34,16 +41,16 @@ namespace System.IO
throw new ArgumentNullException(nameof(path));
// If the path would normalize to string empty, we'll consider it empty
- if (PathInternal.IsEffectivelyEmpty(path))
+ if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
throw new ArgumentException(SR.Arg_PathEmpty, nameof(path));
// Embedded null characters are the only invalid character case we trully care about.
// This is because the nulls will signal the end of the string to Win32 and therefore have
// unpredictable results.
- if (path.IndexOf('\0') != -1)
+ if (path.Contains('\0'))
throw new ArgumentException(SR.Argument_InvalidPathChars, nameof(path));
- if (PathInternal.IsExtended(path))
+ if (PathInternal.IsExtended(path.AsSpan()))
{
// \\?\ paths are considered normalized by definition. Windows doesn't normalize \\?\
// paths and neither should we. Even if we wanted to GetFullPathName does not work
@@ -72,6 +79,9 @@ namespace System.IO
if (IsPathFullyQualified(path))
return GetFullPath(path);
+ if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
+ return basePath;
+
int length = path.Length;
string combinedPath = null;
@@ -80,30 +90,30 @@ namespace System.IO
// Path is current drive rooted i.e. starts with \:
// "\Foo" and "C:\Bar" => "C:\Foo"
// "\Foo" and "\\?\C:\Bar" => "\\?\C:\Foo"
- combinedPath = Join(GetPathRoot(basePath.AsSpan()), path);
+ combinedPath = Join(GetPathRoot(basePath.AsSpan()), path.AsSpan(1)); // Cut the separator to ensure we don't end up with two separators when joining with the root.
}
else if (length >= 2 && PathInternal.IsValidDriveChar(path[0]) && path[1] == PathInternal.VolumeSeparatorChar)
{
// Drive relative paths
Debug.Assert(length == 2 || !PathInternal.IsDirectorySeparator(path[2]));
- if (StringSpanHelpers.Equals(GetVolumeName(path), GetVolumeName(basePath)))
+ if (GetVolumeName(path.AsSpan()).EqualsOrdinal(GetVolumeName(basePath.AsSpan())))
{
// Matching root
// "C:Foo" and "C:\Bar" => "C:\Bar\Foo"
// "C:Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo"
- combinedPath = Join(basePath, path.AsSpan().Slice(2));
+ combinedPath = Join(basePath.AsSpan(), path.AsSpan(2));
}
else
{
// No matching root, root to specified drive
// "D:Foo" and "C:\Bar" => "D:Foo"
// "D:Foo" and "\\?\C:\Bar" => "\\?\D:\Foo"
- combinedPath = !PathInternal.IsDevice(basePath)
+ combinedPath = !PathInternal.IsDevice(basePath.AsSpan())
? path.Insert(2, @"\")
: length == 2
- ? JoinInternal(basePath.AsSpan().Slice(0, 4), path, @"\")
- : JoinInternal(basePath.AsSpan().Slice(0, 4), path.AsSpan().Slice(0, 2), @"\", path.AsSpan().Slice(2));
+ ? JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(), @"\".AsSpan())
+ : JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(0, 2), @"\".AsSpan(), path.AsSpan(2));
}
}
else
@@ -111,37 +121,70 @@ namespace System.IO
// "Simple" relative path
// "Foo" and "C:\Bar" => "C:\Bar\Foo"
// "Foo" and "\\?\C:\Bar" => "\\?\C:\Bar\Foo"
- combinedPath = JoinInternal(basePath, path);
+ combinedPath = JoinInternal(basePath.AsSpan(), path.AsSpan());
}
- // Device paths are normalized by definition, so passing something of this format
- // to GetFullPath() won't do anything by design. Additionally, GetFullPathName() in
- // Windows doesn't root them properly. As such we need to manually remove segments.
- return PathInternal.IsDevice(combinedPath)
- ? RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath))
+ // Device paths are normalized by definition, so passing something of this format (i.e. \\?\C:\.\tmp, \\.\C:\foo)
+ // to Windows APIs won't do anything by design. Additionally, GetFullPathName() in Windows doesn't root
+ // them properly. As such we need to manually remove segments and not use GetFullPath().
+
+ return PathInternal.IsDevice(combinedPath.AsSpan())
+ ? PathInternal.RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath.AsSpan()))
: GetFullPath(combinedPath);
}
public static string GetTempPath()
{
- StringBuilder sb = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH);
- uint r = Interop.Kernel32.GetTempPathW(Interop.Kernel32.MAX_PATH, sb);
- if (r == 0)
+ Span<char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
+ var builder = new ValueStringBuilder(initialBuffer);
+
+ GetTempPath(ref builder);
+
+ string path = PathHelper.Normalize(ref builder);
+ builder.Dispose();
+ return path;
+ }
+
+ private static void GetTempPath(ref ValueStringBuilder builder)
+ {
+ uint result = 0;
+ while ((result = Interop.Kernel32.GetTempPathW(builder.Capacity, ref builder.GetPinnableReference())) > builder.Capacity)
+ {
+ // Reported size is greater than the buffer size. Increase the capacity.
+ builder.EnsureCapacity(checked((int)result));
+ }
+
+ if (result == 0)
throw Win32Marshal.GetExceptionForLastWin32Error();
- return GetFullPath(StringBuilderCache.GetStringAndRelease(sb));
+
+ builder.Length = (int)result;
}
// Returns a unique temporary file name, and creates a 0-byte file by that
// name on disk.
public static string GetTempFileName()
{
- string path = GetTempPath();
+ Span<char> initialTempPathBuffer = stackalloc char[PathInternal.MaxShortPath];
+ ValueStringBuilder tempPathBuilder = new ValueStringBuilder(initialTempPathBuffer);
+
+ GetTempPath(ref tempPathBuilder);
+
+ Span<char> initialBuffer = stackalloc char[PathInternal.MaxShortPath];
+ var builder = new ValueStringBuilder(initialBuffer);
- StringBuilder sb = StringBuilderCache.Acquire(Interop.Kernel32.MAX_PATH);
- uint r = Interop.Kernel32.GetTempFileNameW(path, "tmp", 0, sb);
- if (r == 0)
+ uint result = Interop.Kernel32.GetTempFileNameW(
+ ref tempPathBuilder.GetPinnableReference(), "tmp", 0, ref builder.GetPinnableReference());
+
+ tempPathBuilder.Dispose();
+
+ if (result == 0)
throw Win32Marshal.GetExceptionForLastWin32Error();
- return StringBuilderCache.GetStringAndRelease(sb);
+
+ builder.Length = builder.RawChars.IndexOf('\0');
+
+ string path = PathHelper.Normalize(ref builder);
+ builder.Dispose();
+ return path;
}
// Tests if the given path contains a root. A path is considered rooted
@@ -169,14 +212,14 @@ namespace System.IO
// only contains whitespace characters an ArgumentException gets thrown.
public static string GetPathRoot(string path)
{
- if (PathInternal.IsEffectivelyEmpty(path))
+ if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
return null;
ReadOnlySpan<char> result = GetPathRoot(path.AsSpan());
if (path.Length == result.Length)
return PathInternal.NormalizeDirectorySeparators(path);
- return PathInternal.NormalizeDirectorySeparators(new string(result));
+ return PathInternal.NormalizeDirectorySeparators(result.ToString());
}
/// <remarks>
@@ -237,11 +280,11 @@ namespace System.IO
{
bool isDevice = PathInternal.IsDevice(path);
- if (!isDevice && StringSpanHelpers.Equals(path.Slice(0, 2), @"\\") )
+ if (!isDevice && path.Slice(0, 2).EqualsOrdinal(@"\\".AsSpan()) )
return 2;
else if (isDevice && path.Length >= 8
- && (StringSpanHelpers.Equals(path.Slice(0, 8), PathInternal.UncExtendedPathPrefix)
- || StringSpanHelpers.Equals(path.Slice(5, 4), @"UNC\")))
+ && (path.Slice(0, 8).EqualsOrdinal(PathInternal.UncExtendedPathPrefix.AsSpan())
+ || path.Slice(5, 4).EqualsOrdinal(@"UNC\".AsSpan())))
return 8;
return -1;