public IEnumerable <string> EnumerateDirectories(string path, string pattern, SearchOption searchOption) { if (!IsPathInCone(path, out string processedPath)) { //TODO: Handle cases where part of the directory set is inside our cone and part is not foreach (string s in _basis.EnumerateDirectories(path, pattern, searchOption)) { yield return(s); } yield break; } path = processedPath; string rel = path.Substring(_root.FullPath.Length).Trim('/', '\\'); FileSystemDirectory currentDir = _root; if (!string.IsNullOrEmpty(rel)) { string[] parts = rel.Split('/', '\\'); for (int i = 0; i < parts.Length; ++i) { FileSystemDirectory dir; if (!currentDir.Directories.TryGetValue(parts[i], out dir)) { yield break; } currentDir = dir; } } Regex rx = new Regex(Regex.Escape(pattern).Replace("\\*", ".*").Replace("\\?", ".")); if (searchOption == SearchOption.TopDirectoryOnly) { foreach (KeyValuePair <string, FileSystemDirectory> entry in currentDir.Directories) { if (rx.IsMatch(entry.Key)) { yield return(entry.Value.FullPath); } } yield break; } Stack <IEnumerator <KeyValuePair <string, FileSystemDirectory> > > directories = new Stack <IEnumerator <KeyValuePair <string, FileSystemDirectory> > >(); IEnumerator <KeyValuePair <string, FileSystemDirectory> > current = currentDir.Directories.GetEnumerator(); bool moveNext; while ((moveNext = current.MoveNext()) || directories.Count > 0) { while (!moveNext) { current.Dispose(); if (directories.Count == 0) { break; } current = directories.Pop(); moveNext = current.MoveNext(); } if (!moveNext) { break; } if (rx.IsMatch(current.Current.Key)) { yield return(current.Current.Value.FullPath); } directories.Push(current); current = current.Current.Value.Directories.GetEnumerator(); } }