Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Clean naming and disable stack pathhelper #3010

Merged
merged 1 commit into from
Aug 29, 2015
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
7 changes: 5 additions & 2 deletions src/Common/src/Interop/Windows/mincore/Interop.CopyFileEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use CopyFileEx.
/// </summary>
[DllImport(Libraries.CoreFile_L2, EntryPoint = "CopyFileExW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern bool CopyFileExPrivate(
string src,
Expand All @@ -26,8 +29,8 @@ internal static bool CopyFileEx(
ref int cancel,
int flags)
{
src = PathInternal.AddExtendedPathPrefixForLongPaths(src);
dst = PathInternal.AddExtendedPathPrefixForLongPaths(dst);
src = PathInternal.EnsureExtendedPrefixOverMaxPath(src);
dst = PathInternal.EnsureExtendedPrefixOverMaxPath(dst);
return CopyFileExPrivate(src, dst, progressRoutine, progressData, ref cancel, flags);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use CreateDirectory.
/// </summary>
[DllImport(Libraries.CoreFile_L1, EntryPoint = "CreateDirectoryW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern bool CreateDirectoryPrivate(string path, ref SECURITY_ATTRIBUTES lpSecurityAttributes);

internal static bool CreateDirectory(string path, ref SECURITY_ATTRIBUTES lpSecurityAttributes)
{
// We always want to add for CreateDirectory to get around the legacy 248 character limitation
path = PathInternal.AddExtendedPathPrefix(path);
path = PathInternal.EnsureExtendedPrefix(path);
return CreateDirectoryPrivate(path, ref lpSecurityAttributes);
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/Common/src/Interop/Windows/mincore/Interop.CreateFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use CreateFile.
/// </summary>
[DllImport(Libraries.CoreFile_L1, EntryPoint = "CreateFileW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern SafeFileHandle CreateFilePrivate(
string lpFileName,
Expand All @@ -29,7 +32,7 @@ internal static SafeFileHandle CreateFile(
int dwFlagsAndAttributes,
IntPtr hTemplateFile)
{
lpFileName = PathInternal.AddExtendedPathPrefixForLongPaths(lpFileName);
lpFileName = PathInternal.EnsureExtendedPrefixOverMaxPath(lpFileName);
return CreateFilePrivate(lpFileName, dwDesiredAccess, dwShareMode, ref securityAttrs, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/Common/src/Interop/Windows/mincore/Interop.DeleteFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use DeleteFile.
/// </summary>
[DllImport(Libraries.CoreFile_L1, EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern bool DeleteFilePrivate(string path);

internal static bool DeleteFile(string path)
{
path = PathInternal.AddExtendedPathPrefixForLongPaths(path);
path = PathInternal.EnsureExtendedPrefixOverMaxPath(path);
return DeleteFilePrivate(path);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use DeleteVolumeMountPoint.
/// </summary>
[DllImport(Libraries.CoreFile_L1, EntryPoint = "DeleteVolumeMountPointW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
internal static extern bool DeleteVolumeMountPointPrivate(string mountPoint);


internal static bool DeleteVolumeMountPoint(string mountPoint)
{
mountPoint = PathInternal.AddExtendedPathPrefixForLongPaths(mountPoint);
mountPoint = PathInternal.EnsureExtendedPrefixOverMaxPath(mountPoint);
return DeleteVolumeMountPointPrivate(mountPoint);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use FindFirstFile.
/// </summary>
[DllImport(Libraries.CoreFile_L1, EntryPoint = "FindFirstFileExW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern SafeFindHandle FindFirstFileExPrivate(string lpFileName, FINDEX_INFO_LEVELS fInfoLevelId, ref WIN32_FIND_DATA lpFindFileData, FINDEX_SEARCH_OPS fSearchOp, IntPtr lpSearchFilter, int dwAdditionalFlags);

internal static SafeFindHandle FindFirstFile(string fileName, ref WIN32_FIND_DATA data)
{
fileName = PathInternal.AddExtendedPathPrefixForLongPaths(fileName);
fileName = PathInternal.EnsureExtendedPrefixOverMaxPath(fileName);

// use FindExInfoBasic since we don't care about short name and it has better perf
return FindFirstFileExPrivate(fileName, FINDEX_INFO_LEVELS.FindExInfoBasic, ref data, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use GetFileAttributesEx.
/// </summary>
[DllImport(Libraries.CoreFile_L1, EntryPoint = "GetFileAttributesExW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern bool GetFileAttributesExPrivate(string name, GET_FILEEX_INFO_LEVELS fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);


internal static bool GetFileAttributesEx(string name, GET_FILEEX_INFO_LEVELS fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation)
{
name = PathInternal.AddExtendedPathPrefixForLongPaths(name);
name = PathInternal.EnsureExtendedPrefixOverMaxPath(name);
return GetFileAttributesExPrivate(name, fileInfoLevel, ref lpFileInformation);
}

Expand Down
19 changes: 11 additions & 8 deletions src/Common/src/Interop/Windows/mincore/Interop.GetFullPathNameW.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,30 @@ partial class Interop
partial class mincore
{
/// <summary>
/// WARNING: This overload does not implicitly handle long paths.
/// WARNING: This method does not implicitly handle long paths. Use GetFullPathName.
/// </summary>
[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, EntryPoint = "GetFullPathNameW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
internal unsafe static extern int GetFullPathNameUnsafe(char* path, int numBufferChars, char* buffer, IntPtr mustBeZero);
Copy link
Member

Choose a reason for hiding this comment

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

Why does this one have a different suffix? It can't be an overload of GetFullPathNamePrivate?

Copy link
Member Author

Choose a reason for hiding this comment

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

Because it is internal and unsafe. It is used by the PathHelper class. Best I could come up with, but always open to suggestions.

Copy link
Member

Choose a reason for hiding this comment

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

There are lots of methods that use unsafe code / take ptr arguments that don't have Unsafe in the name. More importantly, though, that's not the defining characteristic with regards to these various methods: the important thing we want to highlight is that it doesn't handle long paths / doesn't provide the wrapping behavior. How about using "Core" as the suffix, to highlight that it's the core functionality, and then the other things wrap it? Ideally we'd use it consistently instead of using "Private" in some places and other suffixes in others. If we can't do that, I'd prefer something like "Native" here, since it at least that highlights that this is the Win32 P/Invoke function.


/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use GetFullPathName.
/// </summary>
[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);
private static extern int GetFullPathNamePrivate(string path, int numBufferChars, [Out]StringBuilder buffer, IntPtr mustBeZero);

internal static int GetFullPathNameW(string path, int numBufferChars, [Out]StringBuilder buffer, IntPtr mustBeZero)
internal static int GetFullPathName(string path, int numBufferChars, [Out]StringBuilder buffer, IntPtr mustBeZero)
{
bool wasExtended = PathInternal.IsExtended(path);
if (!wasExtended)
{
path = PathInternal.AddExtendedPathPrefixForLongPaths(path);
path = PathInternal.EnsureExtendedPrefixOverMaxPath(path);
}
int result = GetFullPathNameWPrivate(path, buffer.Capacity, buffer, mustBeZero);
int result = GetFullPathNamePrivate(path, buffer.Capacity, buffer, mustBeZero);

if (!wasExtended)
{
// We don't want to give back \\?\ if we possibly added it ourselves
PathInternal.RemoveExtendedPathPrefix(buffer);
PathInternal.RemoveExtendedPrefix(buffer);
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use GetLongPathName.
/// </summary>
[DllImport(Libraries.CoreFile_L1, EntryPoint = "GetLongPathNameW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = false)]
private static extern int GetLongPathNamePrivate(string path, [Out]StringBuilder longPathBuffer, int bufferLength);

internal static int GetLongPathName(string path, [Out]StringBuilder longPathBuffer, int bufferLength)
{
path = PathInternal.AddExtendedPathPrefixForLongPaths(path);
path = PathInternal.EnsureExtendedPrefixOverMaxPath(path);
return GetLongPathNamePrivate(path, longPathBuffer, bufferLength);
}
}
Expand Down
19 changes: 11 additions & 8 deletions src/Common/src/Interop/Windows/mincore/Interop.GetLongPathNameW.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,30 @@ partial class Interop
partial class mincore
{
/// <summary>
/// WARNING: This overload does not implicitly handle long paths.
/// WARNING: This method does not implicitly handle long paths. Use GetLongPathName.
/// </summary>
[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, EntryPoint = "GetLongPathNameW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
internal unsafe static extern int GetLongPathNameUnsafe(char* path, char* longPathBuffer, int bufferLength);
Copy link
Member

Choose a reason for hiding this comment

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

Ditto.


/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use GetLongPathName.
/// </summary>
[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);
private static extern int GetLongPathNamePrivate(string path, [Out]StringBuilder longPathBuffer, int bufferLength);

internal static int GetLongPathNameW(string path, [Out]StringBuilder longPathBuffer, int bufferLength)
internal static int GetLongPathName(string path, [Out]StringBuilder longPathBuffer, int bufferLength)
{
bool wasExtended = PathInternal.IsExtended(path);
if (!wasExtended)
{
path = PathInternal.AddExtendedPathPrefixForLongPaths(path);
path = PathInternal.EnsureExtendedPrefixOverMaxPath(path);
}
int result = GetLongPathNameWPrivate(path, longPathBuffer, longPathBuffer.Capacity);
int result = GetLongPathNamePrivate(path, longPathBuffer, longPathBuffer.Capacity);

if (!wasExtended)
{
// We don't want to give back \\?\ if we possibly added it ourselves
PathInternal.RemoveExtendedPathPrefix(longPathBuffer);
PathInternal.RemoveExtendedPrefix(longPathBuffer);
}
return result;
}
Expand Down
11 changes: 7 additions & 4 deletions src/Common/src/Interop/Windows/mincore/Interop.MoveFileEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use MoveFile.
/// </summary>
[DllImport(Libraries.CoreFile_L2, EntryPoint = "MoveFileExW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern bool MoveFileEx(string src, string dst, uint flags);
private static extern bool MoveFileExPrivate(string src, string dst, uint flags);

internal static bool MoveFile(string src, string dst)
{
src = PathInternal.AddExtendedPathPrefixForLongPaths(src);
dst = PathInternal.AddExtendedPathPrefixForLongPaths(dst);
return MoveFileEx(src, dst, 2 /* MOVEFILE_COPY_ALLOWED */);
src = PathInternal.EnsureExtendedPrefixOverMaxPath(src);
dst = PathInternal.EnsureExtendedPrefixOverMaxPath(dst);
return MoveFileExPrivate(src, dst, 2 /* MOVEFILE_COPY_ALLOWED */);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use RemoveDirectory.
/// </summary>
[DllImport(Libraries.CoreFile_L1, EntryPoint = "RemoveDirectoryW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern bool RemoveDirectoryPrivate(string path);

internal static bool RemoveDirectory(string path)
{
path = PathInternal.AddExtendedPathPrefixForLongPaths(path);
path = PathInternal.EnsureExtendedPrefixOverMaxPath(path);
return RemoveDirectoryPrivate(path);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ internal partial class Interop
{
internal partial class mincore
{
/// <summary>
/// WARNING: This method does not implicitly handle long paths. Use SetFileAttributes.
/// </summary>
[DllImport(Libraries.CoreFile_L1, EntryPoint = "SetFileAttributesW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)]
private static extern bool SetFileAttributesPrivate(string name, int attr);

internal static bool SetFileAttributes(string name, int attr)
{
name = PathInternal.AddExtendedPathPrefixForLongPaths(name);
name = PathInternal.EnsureExtendedPrefixOverMaxPath(name);
return SetFileAttributesPrivate(name, attr);
}
}
Expand Down
16 changes: 8 additions & 8 deletions src/Common/src/System/IO/PathInternal.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,11 @@ internal static bool IsDirectoryTooLong(string fullPath)
/// Adds the extended path prefix (\\?\) if not already present, IF the path is not relative,
/// AND the path is more than 259 characters. (> MAX_PATH + null)
/// </summary>
internal static string AddExtendedPathPrefixForLongPaths(string path)
internal static string EnsureExtendedPrefixOverMaxPath(string path)
{
if (path != null && path.Length >= MaxShortPath)
{
return AddExtendedPathPrefix(path);
return EnsureExtendedPrefix(path);
}
else
{
Expand All @@ -93,9 +93,9 @@ internal static string AddExtendedPathPrefixForLongPaths(string path)
/// <summary>
/// Adds the extended path prefix (\\?\) if not already present, IF the path is not relative.
/// </summary>
internal static string AddExtendedPathPrefix(string path)
internal static string EnsureExtendedPrefix(string path)
{
if (IsExtended(path) || IsPathRelative(path) || IsDevicePath(path))
if (IsExtended(path) || IsRelative(path) || IsDevice(path))
return path;

// Given \\server\share in longpath becomes \\?\UNC\server\share
Expand All @@ -108,7 +108,7 @@ internal static string AddExtendedPathPrefix(string path)
/// <summary>
/// Removes the extended path prefix (\\?\) if present.
/// </summary>
internal static string RemoveExtendedPathPrefix(string path)
internal static string RemoveExtendedPrefix(string path)
{
if (!IsExtended(path))
return path;
Expand All @@ -123,7 +123,7 @@ internal static string RemoveExtendedPathPrefix(string path)
/// <summary>
/// Removes the extended path prefix (\\?\) if present.
/// </summary>
internal static StringBuilder RemoveExtendedPathPrefix(StringBuilder path)
internal static StringBuilder RemoveExtendedPrefix(StringBuilder path)
{
if (!IsExtended(path))
return path;
Expand All @@ -138,7 +138,7 @@ internal static StringBuilder RemoveExtendedPathPrefix(StringBuilder path)
/// <summary>
/// Returns true if the path uses the device syntax (\\.\)
/// </summary>
internal static bool IsDevicePath(string path)
internal static bool IsDevice(string path)
{
return path != null && path.StartsWith(DevicePathPrefix, StringComparison.Ordinal);
}
Expand Down Expand Up @@ -267,7 +267,7 @@ internal static int GetRootLength(string path)
/// for C: (rooted, but relative). "C:\a" is rooted and not relative (the current directory
/// will not be used to modify the path).
/// </remarks>
internal static bool IsPathRelative(string path)
internal static bool IsRelative(string path)
{
if (path.Length < 2)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public class PathInternal_Windows_Tests
[InlineData(@"\\.\Foo", @"\\.\Foo")]
[InlineData(@"\\Server\Share", PathInternal.UncExtendedPathPrefix + @"Server\Share")]
[PlatformSpecific(PlatformID.Windows)]
public void AddExtendedPathPrefixTest(string path, string expected)
public void EnsureExtendedPrefixTest(string path, string expected)
{
Assert.Equal(expected, PathInternal.AddExtendedPathPrefix(path));
Assert.Equal(expected, PathInternal.EnsureExtendedPrefix(path));
}

[Theory,
Expand All @@ -39,8 +39,8 @@ public void AddExtendedPathPrefixTest(string path, string expected)
InlineData(@"Path", true),
InlineData(@"X", true)]
[PlatformSpecific(PlatformID.Windows)]
public void IsPathRelative(string path, bool expected)
public void IsRelativeTest(string path, bool expected)
{
Assert.Equal(expected, PathInternal.IsPathRelative(path));
Assert.Equal(expected, PathInternal.IsRelative(path));
}
}
2 changes: 1 addition & 1 deletion src/System.IO.FileSystem/src/System/IO/Win32FileSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ public override void RemoveDirectory(string fullPath, bool recursive)

// We want extended syntax so we can delete "extended" subdirectories and files
// (most notably ones with trailing whitespace or periods)
RemoveDirectoryHelper(PathInternal.AddExtendedPathPrefix(fullPath), recursive, true);
RemoveDirectoryHelper(PathInternal.EnsureExtendedPrefix(fullPath), recursive, true);
}

[System.Security.SecurityCritical] // auto-generated
Expand Down
11 changes: 1 addition & 10 deletions src/System.Runtime.Extensions/src/System/IO/Path.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,16 +176,7 @@ private unsafe static string NormalizePath(string path, bool fullCheck, int maxP
// since StringBuilder is used.
// 2. IsolatedStorage, which supports paths longer than MaxPath (value given
// by maxPathLength.
PathHelper newBuffer = null;
if (path.Length + 1 <= MaxPath)
{
char* m_arrayPtr = stackalloc char[MaxPath];
newBuffer = new PathHelper(m_arrayPtr, MaxPath);
}
else
{
newBuffer = new PathHelper(path.Length + MaxPath, maxPathLength);
}
PathHelper newBuffer = new PathHelper(path.Length + MaxPath, maxPathLength);
Copy link
Member

Choose a reason for hiding this comment

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

Do we know the perf impact of this change? Should we still use stackalloc for smaller paths?

Copy link
Member Author

Choose a reason for hiding this comment

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

I can't because the stackalloc cannot grow currently. I've opened an issue on it and will fix so we can dynamically move up to the heap.

Copy link
Member

Choose a reason for hiding this comment

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

Isn't there a known maximum amount by which it will need to grow, measured in just a few characters? If so, couldn't we just proactively make the stackalloc'd size that much larger?

Copy link
Member Author

Choose a reason for hiding this comment

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

Technically it shouldn't go beyond 520 characters (start with 260 relative and add to current directory). But there is no guarantee of that- I know of ways you can leak long paths into GetCurrentDirectory, and there might be others. There is also some hope that current directory will support > 260 in the future. I've got a lot of ideas about how to approach this issue- any pointers to perf experts would be appreciated. (One thought is a thread local string builder cache for path normalization.)

Copy link
Member

Choose a reason for hiding this comment

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

If StringBuilderCache solves the need here, I'm fine with that. We'd want to make sure, though, that this particular usage didn't end up poisoning the cache, since IIRC StringBuilderCache only puts builders back into the cache if their capacity is below a threshold.


uint numSpaces = 0;
uint numDots = 0;
Expand Down
Loading