The IsPathRoot() method does double check for UNC
/// <summary>
/// Determines if the specified path is either a drive root or a UNC root.
/// </summary>
/// <param name="path">
/// The path
/// </param>
/// <returns>
/// True if the path is either a drive root or a UNC root, or false otherwise.
/// </returns>
private static bool IsPathRoot ( string path )
{
if ( string . IsNullOrEmpty ( path ) )
{
return false ;
}
bool isDriveRoot = string . Equals ( path , Path . GetPathRoot ( path ) , StringComparison . OrdinalIgnoreCase ) ;
bool isUNCRoot = IsUNCRoot ( path ) ;
bool result = isDriveRoot || isUNCRoot ;
s_tracer . WriteLine ( "result = {0}; isDriveRoot = {1}; isUNCRoot = {2}" , result , isDriveRoot , isUNCRoot ) ;
return result ;
}
and could be replaced with more short and fast code. Proposal from @mklement0 Tracking FileSystem provider performance issues #14497 (comment)
Also we need to review GetFileSystemItem(string path, ref bool isContainer, bool showHidden) - there is a root check and maybe a bug (no UNC share check)
bool isRootPath =
string . Equals (
Path . GetPathRoot ( path ) ,
result . FullName ,
StringComparison . OrdinalIgnoreCase ) ;
PR Reduce aggressive correcting casing of file system paths #14469 Reduce aggressive correcting casing of file system paths
On Windows we do case normalizations even if results are not used.
No need to allocate FileInfo and extra strings in IsSameWindowsVolume():
private static bool IsSameWindowsVolume ( string source , string destination )
{
FileInfo src = new FileInfo ( source ) ;
FileInfo dest = new FileInfo ( destination ) ;
return ( src . Directory . Root . Name == dest . Directory . Root . Name ) ;
}
We can use GetDirectoryName(ReadOnlySpan<char> path). Also we should use Ordinal comparison.
EnsureDriveIsRooted() method does extra path.IndexOf(':') - we can simply check last char
private static string EnsureDriveIsRooted ( string path )
{
string result = path ;
// Find the drive separator
int index = path . IndexOf ( ':' ) ;
if ( index != - 1 )
{
// if the drive separator is the end of the path, add
// the root path separator back
if ( index + 1 == path . Length )
{
result = path + StringLiterals . DefaultPathSeparator ;
}
}
return result ;
}
We need to review semantic of IsValidPath() method. If it is exactly about path validity the method could be simplified but we need to measure a performance. In common case it is impossible to validate path by parsing but only by opening.
protected override bool IsValidPath ( string path )
{
// Path passed should be fully qualified path.
if ( string . IsNullOrEmpty ( path ) )
{
return false ;
}
// Normalize the path
path = NormalizePath ( path ) ;
path = EnsureDriveIsRooted ( path ) ;
#if ! UNIX
// Remove alternate data stream references
// See if they've used the inline stream syntax. They have more than one colon.
int firstColon = path . IndexOf ( ':' ) ;
int secondColon = path . IndexOf ( ':' , firstColon + 1 ) ;
if ( secondColon > 0 )
{
path = path . Substring ( 0 , secondColon ) ;
}
#endif
// Make sure the path is either drive rooted or UNC Path
if ( ! IsAbsolutePath ( path ) && ! Utils . PathIsUnc ( path ) )
{
return false ;
}
// Exceptions should only deal with exceptional circumstances,
// but unfortunately, FileInfo offers no Try() methods that
// let us check if we _could_ open the file.
try
{
FileInfo testFile = new FileInfo ( path ) ;
}
catch ( Exception e )
{
if ( ( e is ArgumentNullException ) ||
( e is ArgumentException ) ||
( e is System . Security . SecurityException ) ||
( e is UnauthorizedAccessException ) ||
( e is PathTooLongException ) ||
( e is NotSupportedException ) )
{
return false ;
}
else
{
throw ;
}
}
return true ;
}
Statistic shows:
dir - Recurse ' C:\Program Files (x86)\' | Select - ExpandProperty Mode | Sort-Object | Group-Object - NoElement
Count Name
----- ----
1 -----
3 -- r--
44263 - a---
6 - ar--
8136 d----
3 d--- s
2 d- r--
1044 la---
and we could add "la---" as a static element in
if ( ! isLink )
{
// special casing for the common cases - no allocations
switch ( fileAttributes )
{
case FileAttributes . Archive :
return "-a---" ;
case FileAttributes . Directory :
return "d----" ;
case FileAttributes . Normal :
return "-----" ;
case FileAttributes . Directory | FileAttributes . ReadOnly :
return "d-r--" ;
case FileAttributes . Archive | FileAttributes . ReadOnly :
return "-ar--" ;
}
}
if ( ! isLink )
{
// special casing for the common cases - no allocations
switch ( fileAttributes )
{
case FileAttributes . Archive :
return "-a---" ;
case FileAttributes . Directory :
return "d----" ;
case FileAttributes . Normal :
return "-----" ;
case FileAttributes . Directory | FileAttributes . ReadOnly :
return "d-r--" ;
case FileAttributes . Archive | FileAttributes . ReadOnly :
return "-ar--" ;
}
}
else if ( fileAttributes == FileAttributes . ReadOnly )
{
return "la---" ;
}
...
Remove double check ItemExists();
private void CopyAndDelete ( DirectoryInfo directory , string destination , bool force )
{
if ( ! ItemExists ( destination ) )
{
CreateDirectory ( destination , false ) ;
}
else if ( ItemExists ( destination ) && ! IsItemContainer ( destination ) )
{
Reactions are currently unavailable
PowerShell/src/System.Management.Automation/namespaces/FileSystemProvider.cs
Lines 5026 to 5047 in 281b437
and could be replaced with more short and fast code. Proposal from @mklement0 Tracking FileSystem provider performance issues #14497 (comment)
Also we need to review GetFileSystemItem(string path, ref bool isContainer, bool showHidden) - there is a root check and maybe a bug (no UNC share check)
PowerShell/src/System.Management.Automation/namespaces/FileSystemProvider.cs
Lines 1426 to 1430 in 281b437
PR Reduce aggressive correcting casing of file system paths #14469 Reduce aggressive correcting casing of file system paths
On Windows we do case normalizations even if results are not used.
No need to allocate FileInfo and extra strings in IsSameWindowsVolume():
PowerShell/src/System.Management.Automation/namespaces/FileSystemProvider.cs
Lines 6141 to 6147 in 281b437
We can use
GetDirectoryName(ReadOnlySpan<char> path). Also we should use Ordinal comparison.EnsureDriveIsRooted() method does extra path.IndexOf(':') - we can simply check last char
PowerShell/src/System.Management.Automation/namespaces/FileSystemProvider.cs
Lines 5709 to 5727 in 281b437
We need to review semantic of IsValidPath() method. If it is exactly about path validity the method could be simplified but we need to measure a performance. In common case it is impossible to validate path by parsing but only by opening.
PowerShell/src/System.Management.Automation/namespaces/FileSystemProvider.cs
Lines 1192 to 1246 in 281b437
Statistic shows:
and we could add "la---" as a static element in
PowerShell/src/System.Management.Automation/namespaces/FileSystemProvider.cs
Lines 2024 to 2040 in 281b437
PowerShell/src/System.Management.Automation/namespaces/FileSystemProvider.cs
Lines 6105 to 6112 in 281b437