@@ -1891,14 +1891,9 @@ private void Dir(
1891
1891
}
1892
1892
1893
1893
bool hidden = false ;
1894
- bool checkReparsePoint = true ;
1895
1894
if ( ! Force )
1896
1895
{
1897
1896
hidden = ( recursiveDirectory . Attributes & FileAttributes . Hidden ) != 0 ;
1898
-
1899
- // We've already taken the expense of initializing the Attributes property here,
1900
- // so we can use that to avoid needing to call IsReparsePointLikeSymlink() later.
1901
- checkReparsePoint = ( recursiveDirectory . Attributes & FileAttributes . ReparsePoint ) != 0 ;
1
A93C
902
1897
}
1903
1898
1904
1899
// if "Hidden" is explicitly specified anywhere in the attribute filter, then override
@@ -1912,7 +1907,7 @@ private void Dir(
1912
1907
// c) it is not a reparse point with a target (not OneDrive or an AppX link).
1913
1908
if ( tracker == null )
1914
1909
{
1915
- if ( checkReparsePoint && InternalSymbolicLinkLinkCodeMethods . IsReparsePointLikeSymlink ( recursiveDirectory ) )
1910
+ if ( InternalSymbolicLinkLinkCodeMethods . IsReparsePointWithTarget ( recursiveDirectory ) )
1916
1911
{
1917
1912
continue ;
1918
1913
}
@@ -2064,7 +2059,7 @@ string ToModeString(FileSystemInfo fileSystemInfo)
2064
2059
public static string NameString ( PSObject instance )
2065
2060
{
2066
2061
return instance ? . BaseObject is FileSystemInfo fileInfo
2067
- ? InternalSymbolicLinkLinkCodeMethods . IsReparsePointLikeSymlink ( fileInfo )
2062
+ ? InternalSymbolicLinkLinkCodeMethods . IsReparsePointWithTarget ( fileInfo )
2068
2063
? $ "{ fileInfo . Name } -> { InternalSymbolicLinkLinkCodeMethods . GetTarget ( instance ) } "
2069
2064
: fileInfo . Name
2070
2065
: string . Empty ;
@@ -3104,31 +3099,22 @@ private void RemoveDirectoryInfoItem(DirectoryInfo directory, bool recurse, bool
3104
3099
continueRemoval = ShouldProcess ( directory . FullName , action ) ;
3105
3100
}
3106
3101
3107
- if ( InternalSymbolicLinkLinkCodeMethods . IsReparsePointLikeSymlink ( directory ) )
3102
+ if ( directory . Attributes . HasFlag ( FileAttributes . ReparsePoint ) )
3108
3103
{
3109
- void WriteErrorHelper ( Exception exception )
3110
- {
3111
- WriteError ( new ErrorRecord ( exception , errorId : "DeleteSymbolicLinkFailed" , ErrorCategory . WriteError , directory ) ) ;
3112
- }
3113
-
3114
3104
try
3115
3105
{
3116
- if ( InternalTestHooks . OneDriveTestOn )
3117
- {
3118
- WriteErrorHelper ( new IOException ( ) ) ;
3119
- return ;
3120
- }
3121
- else
3122
- {
3123
- // Name surrogates should just be detached.
3124
- directory . Delete ( ) ;
3125
- }
3106
+ // TODO:
3107
+ // Different symlinks seem to vary by behavior.
3108
+ // In particular, OneDrive symlinks won't remove without recurse,
3109
+ // but the .NET API here does not allow us to distinguish them.
3110
+ // We may need to revisit using p/Invokes here to get the right behavior
3111
+ directory . Delete ( ) ;
3126
3112
}
3127
3113
catch ( Exception e )
3128
3114
{
3129
3115
string error = StringUtil . Format ( FileSystemProviderStrings . CannotRemoveItem , directory . FullName , e . Message ) ;
3130
3116
var exception = new IOException ( error , e ) ;
3131
- WriteErrorHelper ( exception ) ;
3117
+ WriteError ( new ErrorRecord ( exception , errorId : "DeleteSymbolicLinkFailed" , ErrorCategory . WriteError , directory ) ) ;
3132
3118
}
3133
3119
3134
3120
return ;
@@ -8039,7 +8025,7 @@ protected override bool ReleaseHandle()
8039
8025
}
8040
8026
8041
8027
// SetLastError is false as the use of this API doesn't not require GetLastError() to be called
8042
- [ DllImport ( PinvokeDllNames . FindFirstFileDllName , EntryPoint = "FindFirstFileExW" , SetLastError = true , CharSet = CharSet . Unicode ) ]
8028
+ [ DllImport ( PinvokeDllNames . FindFirstFileDllName , EntryPoint = "FindFirstFileExW" , SetLastError = false , CharSet = CharSet . Unicode ) ]
8043
8029
private static extern SafeFindHandle FindFirstFileEx ( string lpFileName , FINDEX_INFO_LEVELS fInfoLevelId , ref WIN32_FIND_DATA lpFindFileData , FINDEX_SEARCH_OPS fSearchOp , IntPtr lpSearchFilter , int dwAdditionalFlags ) ;
8044
8030
8045
8031
internal enum FINDEX_INFO_LEVELS : uint
@@ -8230,50 +8216,28 @@ internal static bool IsReparsePoint(FileSystemInfo fileInfo)
8230
8216
return fileInfo . Attributes . HasFlag ( System . IO . FileAttributes . ReparsePoint ) ;
8231
8217
}
8232
8218
8233
- internal static bool IsReparsePointLikeSymlink ( FileSystemInfo fileInfo )
8219
+ internal static bool IsReparsePointWithTarget ( FileSystemInfo fileInfo )
8234
8220
{
8235
- #if UNIX
8236
- // Reparse point on Unix is a symlink.
8237
- return IsReparsePoint ( fileInfo ) ;
8238
- #else
8239
- if ( InternalTestHooks . OneDriveTestOn && fileInfo . Name == InternalTestHooks . OneDriveTestSymlinkName )
8221
+ if ( ! IsReparsePoint ( fileInfo ) )
8240
8222
{
8241
- return ! InternalTestHooks . OneDriveTestRecurseOn ;
8223
+ return false ;
8242
8224
}
8243
-
8244
- WIN32_FIND_DATA data = default ;
8245
- string fullPath = Path . TrimEndingDirectorySeparator ( fileInfo . FullName ) ;
8246
- using ( var handle = FindFirstFileEx ( fullPath , FINDEX_INFO_LEVELS . FindExInfoBasic , ref data , FINDEX_SEARCH_OPS . FindExSearchNameMatch , IntPtr . Zero , 0 ) )
8225
+ #if ! UNIX
8226
+ // It is a reparse point and we should check some reparse point tags.
8227
+ var data = new WIN32_FIND_DATA ( ) ;
8228
+ using ( var handle = FindFirstFileEx ( fileInfo . FullName , FINDEX_INFO_LEVELS . FindExInfoBasic , ref data , FINDEX_SEARCH_OPS . FindExSearchNameMatch , IntPtr . Zero , 0 ) )
8247
8229
{
8248
- if ( handle . IsInvalid )
8249
- {
8250
- // Our handle could be invalidated by something else touching the filesystem,
8251
- // so ensure we deal with that possibility here
8252
- int lastError = Marshal . GetLastWin32Error ( ) ;
8253
- throw new Win32Exception ( lastError ) ;
8254
- }
8255
-
8256
- // We already have the file attribute information from our Win32 call,
8257
- // so no need to take the expense of the FileInfo.FileAttributes call
8258
- const int FILE_ATTRIBUTE_REPARSE_POINT = 0x0400 ;
8259
- if ( ( data . dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) == 0 )
8260
- {
8261
- // Not a reparse point.
8262
- return false ;
8263
- }
8264
-
8265
8230
// The name surrogate bit 0x20000000 is defined in https://docs.microsoft.com/windows/win32/fileio/reparse-point-tags
8266
8231
// Name surrogates (0x20000000) are reparse points that point to other named entities local to the filesystem
8267
8232
// (like symlinks and mount points).
8268
8233
// In the case of OneDrive, they are not name surrogates and would be safe to recurse into.
8269
- if ( ( data . dwReserved0 & 0x20000000 ) == 0 && ( data . dwReserved0 != IO_REPARSE_TAG_APPEXECLINK ) )
8234
+ if ( ! handle . IsInvalid && ( data . dwReserved0 & 0x20000000 ) == 0 && ( data . dwReserved0 != IO_REPARSE_TAG_APPEXECLINK ) )
8270
8235
{
8271
8236
return false ;
8272
8237
}
8273
8238
}
8274
-
8275
- return true ;
8276
8239
#endif
8240
+ return true ;
8277
8241
}
8278
8242
8279
8243
internal static bool WinIsHardLink ( FileSystemInfo fileInfo )
0 commit comments