From 60d640fe411195540b215553ec250b97a3ad067a Mon Sep 17 00:00:00 2001 From: Windos Date: Tue, 3 Oct 2017 22:32:51 +1300 Subject: [PATCH 1/3] Add depth to ProcessPathItems Honors capped recursion when using Include or Exclude filters with Get-ChildItem --- .../engine/SessionStateContainer.cs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateContainer.cs b/src/System.Management.Automation/engine/SessionStateContainer.cs index 97c412f3f0e..32406d2fe0a 100644 --- a/src/System.Management.Automation/engine/SessionStateContainer.cs +++ b/src/System.Management.Automation/engine/SessionStateContainer.cs @@ -1593,7 +1593,7 @@ internal void GetChildItems( } int unUsedChildrenNotMatchingFilterCriteria = 0; - ProcessPathItems(providerInstance, providerPath, recurse, context, out unUsedChildrenNotMatchingFilterCriteria, ProcessMode.Enumerate); + ProcessPathItems(providerInstance, providerPath, recurse, context, out unUsedChildrenNotMatchingFilterCriteria, ProcessMode.Enumerate, depth: depth); } } else @@ -1836,6 +1836,10 @@ private bool IsPathContainer( /// /// a hint used to skip IsItemContainer checks /// + /// + /// Limits the depth of recursion; uint.MaxValue performs full recursion. + /// + /// /// /// If the refers to a provider that could not be found. /// @@ -1860,7 +1864,8 @@ private void ProcessPathItems( CmdletProviderContext context, out int childrenNotMatchingFilterCriteria, ProcessMode processMode = ProcessMode.Enumerate, - bool skipIsItemContainerCheck = false) + bool skipIsItemContainerCheck = false, + uint depth = uint.MaxValue) { ContainerCmdletProvider containerCmdletProvider = GetContainerProviderInstance(providerInstance); childrenNotMatchingFilterCriteria = 0; @@ -2016,7 +2021,7 @@ private void ProcessPathItems( } // Now recurse if it is a container - if (recurse && IsPathContainer(providerInstance, qualifiedPath, context)) + if (recurse && IsPathContainer(providerInstance, qualifiedPath, context) && depth > 0) { // Making sure to obey the StopProcessing. if (context.Stopping) @@ -2024,7 +2029,7 @@ private void ProcessPathItems( return; } // The item is a container so recurse into it. - ProcessPathItems(providerInstance, qualifiedPath, recurse, context, out childrenNotMatchingFilterCriteria, processMode, skipIsItemContainerCheck: true); + ProcessPathItems(providerInstance, qualifiedPath, recurse, context, out childrenNotMatchingFilterCriteria, processMode, skipIsItemContainerCheck: true, depth: depth - 1); } } // for each childName } From 1cf186479cfe6acd5b0675bca8b6e8e53276edfa Mon Sep 17 00:00:00 2001 From: Windos Date: Tue, 3 Oct 2017 23:14:40 +1300 Subject: [PATCH 2/3] Including test cases to test include/exclude recursion --- .../Get-ChildItem.Tests.ps1 | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) 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 043b9c4c6f9..1956a558f9f 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Get-ChildItem.Tests.ps1 @@ -9,13 +9,15 @@ Describe "Get-ChildItem" -Tags "CI" { $item_c = "c283d143-2116-4809-bf11-4f7d61613f92" $item_D = "D39B4FD9-3E1D-4DD5-8718-22FE2C934CE3" $item_E = "EE150FEB-0F21-4AFF-8066-AF59E925810C" - $item_F = ".F81D8514-8862-4227-B041-0529B1656A43" + $item_F = ".F81D8514-8862-4227-B041-0529B1656A43" + $item_G = "5560A62F-74F1-4FAE-9A23-F4EBD90D2676" $null = New-Item -Path $TestDrive -Name $item_a -ItemType "File" -Force $null = New-Item -Path $TestDrive -Name $item_B -ItemType "File" -Force $null = New-Item -Path $TestDrive -Name $item_c -ItemType "File" -Force $null = New-Item -Path $TestDrive -Name $item_D -ItemType "File" -Force $null = New-Item -Path $TestDrive -Name $item_E -ItemType "Directory" -Force $null = New-Item -Path $TestDrive -Name $item_F -ItemType "File" -Force | ForEach-Object {$_.Attributes = "hidden"} + $null = New-Item -Path (Join-Path -Path $TestDrive -ChildPath $item_E) -Name $item_G -ItemType "File" -Force } It "Should list the contents of the current folder" { @@ -66,6 +68,18 @@ Describe "Get-ChildItem" -Tags "CI" { $file.Count | Should be 1 $file.Name | Should be $item_F } + + It "Should list items in current directory only with depth set to 0" { + (Get-ChildItem -Path $TestDrive -Depth 0).Count | Should Be 5 + (Get-ChildItem -Path $TestDrive -Depth 0 -Include *).Count | Should Be 5 + (Get-ChildItem -Path $TestDrive -Depth 0 -Exclude IntentionallyNonexistent).Count | Should Be 5 + } + + It "Should return items recursively when using 'Include' or 'Exclude' parameters" { + (Get-ChildItem -Path $TestDrive -Depth 1).Count | Should Be 6 + (Get-ChildItem -Path $TestDrive -Depth 1 -Include $item_G).Count | Should Be 1 + (Get-ChildItem -Path $TestDrive -Depth 1 -Exclude $item_a).Count | Should Be 5 + } } Context 'Env: Provider' { From a464c578a2d96da7e23df7597670fe8780c89c84 Mon Sep 17 00:00:00 2001 From: Windos Date: Wed, 4 Oct 2017 12:41:37 +1300 Subject: [PATCH 3/3] Swap optional paramater for overload --- .../engine/SessionStateContainer.cs | 70 +++++++++++++++++-- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/engine/SessionStateContainer.cs b/src/System.Management.Automation/engine/SessionStateContainer.cs index 32406d2fe0a..efcc2feedc3 100644 --- a/src/System.Management.Automation/engine/SessionStateContainer.cs +++ b/src/System.Management.Automation/engine/SessionStateContainer.cs @@ -1593,7 +1593,7 @@ internal void GetChildItems( } int unUsedChildrenNotMatchingFilterCriteria = 0; - ProcessPathItems(providerInstance, providerPath, recurse, context, out unUsedChildrenNotMatchingFilterCriteria, ProcessMode.Enumerate, depth: depth); + ProcessPathItems(providerInstance, providerPath, recurse, depth, context, out unUsedChildrenNotMatchingFilterCriteria, ProcessMode.Enumerate); } } else @@ -1836,10 +1836,71 @@ private bool IsPathContainer( /// /// a hint used to skip IsItemContainer checks /// + /// + /// If the refers to a provider that could not be found. + /// + /// + /// + /// If the refers to a drive that could not be found. + /// + /// + /// + /// If the provider that the refers to does + /// not support this operation. + /// + /// + /// + /// If the provider threw an exception. + /// + /// + private void ProcessPathItems( + CmdletProvider providerInstance, + string path, + bool recurse, + CmdletProviderContext context, + out int childrenNotMatchingFilterCriteria, + ProcessMode processMode = ProcessMode.Enumerate, + bool skipIsItemContainerCheck = false) + { + // Call ProcessPathItems with 'depth' set to maximum value for infinite recursion when needed. + ProcessPathItems(providerInstance, path, recurse, uint.MaxValue, context, out childrenNotMatchingFilterCriteria, processMode, skipIsItemContainerCheck); + } // ProcessPathItems + + /// + /// Since we can't do include and exclude filtering on items we have to + /// do the recursion ourselves. We get each child name and see if it matches + /// the include and exclude filters. If the child is a container we recurse + /// into that container. + /// + /// + /// + /// The instance of the provider to use. + /// + /// + /// + /// The path to the item to get the children from. + /// + /// + /// + /// Recurse into sub-containers when getting children. + /// + /// /// /// Limits the depth of recursion; uint.MaxValue performs full recursion. /// /// + /// + /// The context under which the command is running. + /// + /// + /// + /// The count of items that do not match any include/exclude criteria. + /// + /// + /// Indicates if this is a Enumerate/Remove operation + /// + /// a hint used to skip IsItemContainer checks + /// /// /// If the refers to a provider that could not be found. /// @@ -1861,11 +1922,11 @@ private void ProcessPathItems( CmdletProvider providerInstance, string path, bool recurse, + uint depth, CmdletProviderContext context, out int childrenNotMatchingFilterCriteria, ProcessMode processMode = ProcessMode.Enumerate, - bool skipIsItemContainerCheck = false, - uint depth = uint.MaxValue) + bool skipIsItemContainerCheck = false) { ContainerCmdletProvider containerCmdletProvider = GetContainerProviderInstance(providerInstance); childrenNotMatchingFilterCriteria = 0; @@ -2029,7 +2090,7 @@ private void ProcessPathItems( return; } // The item is a container so recurse into it. - ProcessPathItems(providerInstance, qualifiedPath, recurse, context, out childrenNotMatchingFilterCriteria, processMode, skipIsItemContainerCheck: true, depth: depth - 1); + ProcessPathItems(providerInstance, qualifiedPath, recurse, depth - 1, context, out childrenNotMatchingFilterCriteria, processMode, skipIsItemContainerCheck: true); } } // for each childName } @@ -2071,7 +2132,6 @@ private void ProcessPathItems( } } // ProcessPathItems - /// /// Gets the dynamic parameters for the get-childitem cmdlet. ///