diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnblockFile.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnblockFile.cs index 785d797d02..31c48d3300 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnblockFile.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/UnblockFile.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Management.Automation; using System.Management.Automation.Internal; @@ -119,18 +120,9 @@ namespace Microsoft.PowerShell.Commands { AlternateDataStreamUtilities.DeleteFileStream(path, "Zone.Identifier"); } - catch (Win32Exception accessException) + catch (Exception e) { - // NativeErrorCode=2 - File not found. - // If the block stream not found the 'path' was not blocked and we successfully return. - if (accessException.NativeErrorCode != 2) - { - WriteError(new ErrorRecord(accessException, "RemoveItemUnauthorizedAccessError", ErrorCategory.PermissionDenied, path)); - } - else - { - WriteVerbose(StringUtil.Format(UtilityCommonStrings.NoZoneIdentifierFileStream, path)); - } + WriteError(new ErrorRecord(e, "RemoveItemUnableToAccessFile", ErrorCategory.ResourceUnavailable, path)); } } } diff --git a/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx b/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx index ce98a18260..d11d22cfc9 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx +++ b/src/Microsoft.PowerShell.Commands.Utility/resources/UtilityCommonStrings.resx @@ -174,9 +174,6 @@ '{0}' is not supported in this system. - - The file is not blocked: {0} - Processing object of type [{0}] at depth {1} diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index fd860cafd6..f9314b8649 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -2874,41 +2874,20 @@ namespace Microsoft.PowerShell.Commands continueRemoval = ShouldProcess(directory.FullName, action); } - if ((directory.Attributes & FileAttributes.ReparsePoint) != 0) + if (directory.Attributes.HasFlag(FileAttributes.ReparsePoint)) { - bool success = InternalSymbolicLinkLinkCodeMethods.DeleteJunction(directory.FullName); - - if (!success) - { - string error = StringUtil.Format(FileSystemProviderStrings.CannotRemoveItem, directory.FullName); - Exception e = new IOException(error); - WriteError(new ErrorRecord(e, "DeleteJunctionFailed", ErrorCategory.WriteError, directory)); - return; - } - try { - if (!Utils.ItemExists(directory.FullName, out bool _)) - { - // Directory does not exist - return; - } + directory.Delete(); } - catch (Exception accessException) + catch (Exception e) { - ErrorRecord errorRecord = new ErrorRecord(accessException, "RemoveFileSystemItemUnAuthorizedAccess", ErrorCategory.PermissionDenied, directory); - - ErrorDetails errorDetails = - new ErrorDetails(this, "FileSystemProviderStrings", - "CannotRemoveItem", - directory.FullName, - accessException.Message); - - errorRecord.ErrorDetails = errorDetails; - - WriteError(errorRecord); - return; + string error = StringUtil.Format(FileSystemProviderStrings.CannotRemoveItem, directory.FullName); + Exception exception = new IOException(error, e); + WriteError(new ErrorRecord(exception, "DeleteSymbolicLinkFailed", ErrorCategory.WriteError, directory)); } + + return; } if (continueRemoval) @@ -8336,91 +8315,6 @@ namespace Microsoft.PowerShell.Commands } } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")] - internal static bool DeleteJunction(string junctionPath) - { - bool result = false; - - if (!String.IsNullOrEmpty(junctionPath)) - { - if (!Platform.IsWindows) - { - // For non-Windows platform, treat it as a file. Just delete it. - try - { - File.Delete(junctionPath); - return true; - } - catch - { - return false; - } - } - - using (SafeHandle handle = OpenReparsePoint(junctionPath, FileDesiredAccess.GenericWrite)) - { - bool success = false; - int inOutBufferSize = Marshal.SizeOf(); - IntPtr outBuffer = Marshal.AllocHGlobal(inOutBufferSize); - IntPtr inBuffer = Marshal.AllocHGlobal(inOutBufferSize); - - try - { - handle.DangerousAddRef(ref success); - IntPtr dangerousHandle = handle.DangerousGetHandle(); - int bytesReturned; - - // Do a FSCTL_GET_REPARSE_POINT first because the ReparseTag could be - // IO_REPARSE_TAG_MOUNT_POINT or IO_REPARSE_TAG_SYMLINK. - // Using the wrong one results in mismatched-tag error. - - REPARSE_GUID_DATA_BUFFER junctionData = new REPARSE_GUID_DATA_BUFFER(); - Marshal.StructureToPtr(junctionData, outBuffer, false); - - result = DeviceIoControl(dangerousHandle, FSCTL_GET_REPARSE_POINT, IntPtr.Zero, 0, - outBuffer, inOutBufferSize, out bytesReturned, IntPtr.Zero); - if (!result) - { - int lastError = Marshal.GetLastWin32Error(); - throw new Win32Exception(lastError); - } - - junctionData = Marshal.PtrToStructure(outBuffer); - junctionData.ReparseDataLength = 0; - junctionData.DataBuffer = new char[MAX_REPARSE_SIZE]; - - Marshal.StructureToPtr(junctionData, inBuffer, false); - - // To delete a reparse point: - // ReparseDataLength must be 0 - // inBufferSize must be REPARSE_GUID_DATA_BUFFER_HEADER_SIZE - result = DeviceIoControl(dangerousHandle, FSCTL_DELETE_REPARSE_POINT, inBuffer, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero); - if (!result) - { - int lastError = Marshal.GetLastWin32Error(); - throw new Win32Exception(lastError); - } - } - finally - { - if (success) - { - handle.DangerousRelease(); - } - - Marshal.FreeHGlobal(outBuffer); - Marshal.FreeHGlobal(inBuffer); - } - } - } - else - { - throw new ArgumentNullException("junctionPath"); - } - - return result; - } - private static SafeFileHandle OpenReparsePoint(string reparsePoint, FileDesiredAccess accessMode) { #if UNIX @@ -8585,11 +8479,7 @@ namespace System.Management.Automation.Internal } string resultPath = path + adjustedStreamName; - if (!NativeMethods.DeleteFile(resultPath)) - { - int error = Marshal.GetLastWin32Error(); - throw new Win32Exception(error); - } + File.Delete(resultPath); } internal static void SetZoneOfOrigin(string path, SecurityZone securityZone) @@ -8617,9 +8507,6 @@ namespace System.Management.Automation.Internal IntPtr lpSecurityAttributes, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); - [DllImport(PinvokeDllNames.DeleteFileDllName, CharSet = CharSet.Unicode, SetLastError = true)] - internal static extern bool DeleteFile(string lpFileName); - [DllImport(PinvokeDllNames.FindFirstStreamDllName, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)] [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "AlternateStreamNativeData.Name")] internal static extern SafeFindHandle FindFirstStreamW( diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 index 3f4482e2e0..13d2421d5b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/New-Item.Tests.ps1 @@ -242,6 +242,8 @@ Describe "New-Item with links" -Tags @('CI', 'RequireAdminOnWindows') { # Remove the link explicitly to avoid broken symlink issue Remove-Item $FullyQualifiedLink -Force + # Test a code path removing a symbolic link (reparse point) + Test-Path $FullyQualifiedLink | Should -BeFalse } It "New-Item -ItemType SymbolicLink should understand directory path ending with slash" { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/Unblock-File.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/Unblock-File.Tests.ps1 index b85cb1156f..a62d38d4a7 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/Unblock-File.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/Unblock-File.Tests.ps1 @@ -64,6 +64,6 @@ Describe "Unblock-File" -Tags "CI" { $TestFileCreated = Get-ChildItem $TestFile $TestFileCreated.IsReadOnly | Should -BeTrue - { Unblock-File -LiteralPath $TestFile -ErrorAction Stop } | Should -Throw -ErrorId "RemoveItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.UnblockFileCommand" + { Unblock-File -LiteralPath $TestFile -ErrorAction Stop } | Should -Throw -ErrorId "RemoveItemUnableToAccessFile,Microsoft.PowerShell.Commands.UnblockFileCommand" } }