diff --git a/src/PowerShellEditorServices/Workspace/Workspace.cs b/src/PowerShellEditorServices/Workspace/Workspace.cs index 7dc328b41..b53832f07 100644 --- a/src/PowerShellEditorServices/Workspace/Workspace.cs +++ b/src/PowerShellEditorServices/Workspace/Workspace.cs @@ -292,7 +292,9 @@ public IEnumerable EnumeratePSFiles() return Enumerable.Empty(); } - return this.RecursivelyEnumerateFiles(WorkspacePath); + var foundFiles = new List(); + this.RecursivelyEnumerateFiles(WorkspacePath, ref foundFiles); + return foundFiles; } #endregion @@ -301,81 +303,29 @@ public IEnumerable EnumeratePSFiles() /// /// Find PowerShell files recursively down from a given directory path. - /// Currently returns files in depth-first order. + /// Currently collects files in depth-first order. /// Directory.GetFiles(folderPath, pattern, SearchOption.AllDirectories) would provide this, /// but a cycle in the filesystem will cause that to enter an infinite loop. /// - /// The absolute path of the base folder to search. - /// - /// All PowerShell files in the recursive directory hierarchy under the given base directory, up to 64 directories deep. - /// - private IEnumerable RecursivelyEnumerateFiles(string folderPath) + /// The path of the current directory to find files in + /// The accumulator for files found so far. + /// The current depth of the recursion from the original base directory. + private void RecursivelyEnumerateFiles(string folderPath, ref List foundFiles, int currDepth = 0) { - var foundFiles = new List(); - var dirStack = new Stack(); - - // Kick the search off with the base directory - dirStack.Push(folderPath); - const int recursionDepthLimit = 64; - while (dirStack.Any()) - { - string currDir = dirStack.Pop(); - - // Look for any PowerShell files in the current directory - foreach (string pattern in s_psFilePatterns) - { - string[] psFiles; - try - { - psFiles = Directory.GetFiles(currDir, pattern, SearchOption.TopDirectoryOnly); - } - catch (DirectoryNotFoundException e) - { - this.logger.WriteHandledException( - $"Could not enumerate files in the path '{currDir}' due to it being an invalid path", - e); - - continue; - } - catch (PathTooLongException e) - { - this.logger.WriteHandledException( - $"Could not enumerate files in the path '{currDir}' due to the path being too long", - e); - - continue; - } - catch (Exception e) when (e is SecurityException || e is UnauthorizedAccessException) - { - this.logger.WriteHandledException( - $"Could not enumerate files in the path '{currDir}' due to the path not being accessible", - e); - - continue; - } - - foundFiles.AddRange(psFiles); - } - - // Prevent unbounded recursion here - // If we get too deep, keep processing but go no deeper - if (dirStack.Count >= recursionDepthLimit) - { - this.logger.Write(LogLevel.Warning, $"Recursion depth limit hit for path {folderPath}"); - continue; - } - // Add the recursive directories to search next - string[] subDirs; + // Look for any PowerShell files in the current directory + foreach (string pattern in s_psFilePatterns) + { + string[] psFiles; try { - subDirs = Directory.GetDirectories(currDir); + psFiles = Directory.GetFiles(folderPath, pattern, SearchOption.TopDirectoryOnly); } catch (DirectoryNotFoundException e) { this.logger.WriteHandledException( - $"Could not enumerate directories in the path '{currDir}' due to it being an invalid path", + $"Could not enumerate files in the path '{folderPath}' due to it being an invalid path", e); continue; @@ -383,7 +333,7 @@ private IEnumerable RecursivelyEnumerateFiles(string folderPath) catch (PathTooLongException e) { this.logger.WriteHandledException( - $"Could not enumerate directories in the path '{currDir}' due to the path being too long", + $"Could not enumerate files in the path '{folderPath}' due to the path being too long", e); continue; @@ -391,19 +341,57 @@ private IEnumerable RecursivelyEnumerateFiles(string folderPath) catch (Exception e) when (e is SecurityException || e is UnauthorizedAccessException) { this.logger.WriteHandledException( - $"Could not enumerate directories in the path '{currDir}' due to the path not being accessible", + $"Could not enumerate files in the path '{folderPath}' due to the path not being accessible", e); continue; } - foreach (string subDir in subDirs) - { - dirStack.Push(subDir); - } + foundFiles.AddRange(psFiles); } - return foundFiles; + // Prevent unbounded recursion here + if (currDepth >= recursionDepthLimit) + { + this.logger.Write(LogLevel.Warning, $"Recursion depth limit hit for path {folderPath}"); + return; + } + + // Add the recursive directories to search next + string[] subDirs; + try + { + subDirs = Directory.GetDirectories(folderPath); + } + catch (DirectoryNotFoundException e) + { + this.logger.WriteHandledException( + $"Could not enumerate directories in the path '{folderPath}' due to it being an invalid path", + e); + + return; + } + catch (PathTooLongException e) + { + this.logger.WriteHandledException( + $"Could not enumerate directories in the path '{folderPath}' due to the path being too long", + e); + + return; + } + catch (Exception e) when (e is SecurityException || e is UnauthorizedAccessException) + { + this.logger.WriteHandledException( + $"Could not enumerate directories in the path '{folderPath}' due to the path not being accessible", + e); + + return; + } + + foreach (string subDir in subDirs) + { + RecursivelyEnumerateFiles(subDir, ref foundFiles, currDepth: currDepth + 1); + } } ///