From 5cbf1b43de52fe9025bf756990b1cc6eb4e694e9 Mon Sep 17 00:00:00 2001 From: Charu Bassi Date: Tue, 27 Sep 2016 16:13:03 -0700 Subject: [PATCH] Fix 'Get-ChildItem -Hidden' to work on system hidden files like c:\hiberfil.sys c:\pagefile.sys and c:\swapfile.sys --- .../engine/Utils.cs | 22 +++++++++++- .../namespaces/FileSystemProvider.cs | 20 +++++++++++ .../Get-ChildItem.Tests.ps1 | 36 +++++++++++++++---- 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index d84bd9d3af..ec28855e14 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -996,7 +996,27 @@ namespace System.Management.Automation Win32Exception win32Exception = new Win32Exception(errorCode); exception = new UnauthorizedAccessException(win32Exception.Message, win32Exception); } - + else if (errorCode == 32) + { + // Errorcode 32 is 'ERROR_SHARING_VIOLATION' i.e. + // The process cannot access the file because it is being used by another process. + // GetFileAttributes may return INVALID_FILE_ATTRIBUTES for a system file or directory because of this error. + // GetFileAttributes function tries to open the file with FILE_READ_ATTRIBUTES access right but it fails if the + // sharing flag for the file is set to 0x00000000.This flag prevents it from opening a file for delete, read, or + // write access. For example: C:\pagefile.sys is always opened by OS with sharing flag 0x00000000. + // But FindFirstFile is still able to get attributes as this api retrieves the required information using a find + // handle generated with FILE_LIST_DIRECTORY access. + // Fall back to FindFirstFile to check if the file actually exists. + IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); + NativeMethods.WIN32_FIND_DATA findData; + IntPtr findHandle = NativeMethods.FindFirstFile(path, out findData); + if (findHandle != INVALID_HANDLE_VALUE) + { + isDirectory = (findData.dwFileAttributes & NativeMethods.FileAttributes.Directory) != 0; + NativeMethods.FindClose(findHandle); + return true; + } + } else if (errorCode == 53) { // ERROR_BAD_NETPATH - The network path was not found. diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 39f43df6fa..3d8452367f 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -6991,6 +6991,26 @@ namespace Microsoft.PowerShell.Commands Win32Exception win32Exception = new Win32Exception(errorCode); throw new UnauthorizedAccessException(win32Exception.Message, win32Exception); } + else if (errorCode == 32) + { + // Errorcode 32 is 'ERROR_SHARING_VIOLATION' i.e. + // The process cannot access the file because it is being used by another process. + // GetFileAttributes may return INVALID_FILE_ATTRIBUTES for a system file or directory because of this error. + // GetFileAttributes function tries to open the file with FILE_READ_ATTRIBUTES access right but it fails if the + // sharing flag for the file is set to 0x00000000.This flag prevents it from opening a file for delete, read, or + // write access. For example: C:\pagefile.sys is always opened by OS with sharing flag 0x00000000. + // But FindFirstFile is still able to get attributes as this api retrieves the required information using a find + // handle generated with FILE_LIST_DIRECTORY access. + // Fall back to FindFirstFile to check if the file actually exists. + IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); + Utils.NativeMethods.WIN32_FIND_DATA findData; + IntPtr findHandle = Utils.NativeMethods.FindFirstFile(path, out findData); + if (findHandle != INVALID_HANDLE_VALUE) + { + Utils.NativeMethods.FindClose(findHandle); + return (int)findData.dwFileAttributes; + } + } } return result; diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 index ab66fb43f6..8ccf7b31ec 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 @@ -2,6 +2,16 @@ Describe "Get-ChildItem" -Tags "CI" { Context 'FileSystem provider' { + BeforeAll { + # Create Test data + $null = New-Item -Path $TestDrive -Name "a" -ItemType "File" -Force + $null = New-Item -Path $TestDrive -Name "B" -ItemType "File" -Force + $null = New-Item -Path $TestDrive -Name "c" -ItemType "File" -Force + $null = New-Item -Path $TestDrive -Name "D" -ItemType "File" -Force + $null = New-Item -Path $TestDrive -Name "E" -ItemType "Directory" -Force + $null = New-Item -Path $TestDrive -Name ".F" -ItemType "File" -Force | %{$_.Attributes = "hidden"} + } + It "Should list the contents of the current folder" { (Get-ChildItem .).Name.Length | Should BeGreaterThan 0 } @@ -23,12 +33,6 @@ Describe "Get-ChildItem" -Tags "CI" { } It "Should list files in sorted order" { - New-Item -Path $TestDrive -Name "a" -ItemType "File" -Force - New-Item -Path $TestDrive -Name "B" -ItemType "File" -Force - New-Item -Path $TestDrive -Name "c" -ItemType "File" -Force - New-Item -Path $TestDrive -Name "D" -ItemType "File" -Force - New-Item -Path $TestDrive -Name "E" -ItemType "Directory" -Force - $files = Get-ChildItem -Path $TestDrive $files[0].Name | Should Be "E" $files[1].Name | Should Be "a" @@ -36,6 +40,26 @@ Describe "Get-ChildItem" -Tags "CI" { $files[3].Name | Should Be "c" $files[4].Name | Should Be "D" } + + It "Should list hidden files as well when 'Force' parameter is used" { + $files = Get-ChildItem -path $TestDrive -Force + $files | Should not be $null + $files.Count | Should be 6 + $files.Name.Contains(".F") + } + + It "Should list only hidden files when 'Hidden' parameter is used" { + $files = Get-ChildItem -path $TestDrive -Hidden + $files | Should not be $null + $files.Count | Should be 1 + $files[0].Name | Should Be ".F" + } + It "Should give .sys file if the fullpath is specified with hidden and force parameter" -Skip:(!$IsWindows){ + $file = Get-ChildItem -path "$env:SystemDrive\\pagefile.sys" -Hidden + $file | Should not be $null + $file.Count | Should be 1 + $file.Name | Should be "pagefile.sys" + } } Context 'Env: Provider' {