private static Microsoft.Win32.SafeHandles.SafeDirectoryHandle OpenDirectory(string fullPath) { Microsoft.Win32.SafeHandles.SafeDirectoryHandle handle = Interop.Sys.OpenDir(fullPath); if (handle.IsInvalid) { throw Interop.GetExceptionForIoErrno(Interop.Sys.GetLastErrorInfo(), fullPath, isDirectory: true); } return(handle); }
private IEnumerator <T> Enumerate(Microsoft.Win32.SafeHandles.SafeDirectoryHandle dirHandle) { if (dirHandle == null) { // Empty search yield break; } Debug.Assert(!dirHandle.IsInvalid); Debug.Assert(!dirHandle.IsClosed); // Maintain a stack of the directories to explore, in the case of SearchOption.AllDirectories // Lazily-initialized only if we find subdirectories that will be explored. Stack <PathPair> toExplore = null; PathPair dirPath = _initialDirectory; while (dirHandle != null) { try { // Read each entry from the enumerator Interop.Sys.DirectoryEntry dirent; while (Interop.Sys.ReadDir(dirHandle, out dirent) == 0) { // Get from the dir entry whether the entry is a file or directory. // We classify everything as a file unless we know it to be a directory. bool isDir; if (dirent.InodeType == Interop.Sys.NodeType.DT_DIR) { // We know it's a directory. isDir = true; } else if (dirent.InodeType == Interop.Sys.NodeType.DT_LNK || dirent.InodeType == Interop.Sys.NodeType.DT_UNKNOWN) { // It's a symlink or unknown: stat to it to see if we can resolve it to a directory. // If we can't (e.g. symlink to a file, broken symlink, etc.), we'll just treat it as a file. Interop.ErrorInfo errnoIgnored; isDir = DirectoryExists(Path.Combine(dirPath.FullPath, dirent.InodeName), out errnoIgnored); } else { // Otherwise, treat it as a file. This includes regular files, FIFOs, etc. isDir = false; } // Yield the result if the user has asked for it. In the case of directories, // always explore it by pushing it onto the stack, regardless of whether // we're returning directories. if (isDir) { if (!ShouldIgnoreDirectory(dirent.InodeName)) { string userPath = null; if (_searchOption == SearchOption.AllDirectories) { if (toExplore == null) { toExplore = new Stack <PathPair>(); } userPath = Path.Combine(dirPath.UserPath, dirent.InodeName); toExplore.Push(new PathPair(userPath, Path.Combine(dirPath.FullPath, dirent.InodeName))); } if (_includeDirectories && Interop.Sys.FnMatch(_searchPattern, dirent.InodeName, Interop.Sys.FnMatchFlags.FNM_NONE) == 0) { yield return(_translateResult(userPath ?? Path.Combine(dirPath.UserPath, dirent.InodeName), /*isDirectory*/ true)); } } } else if (_includeFiles && Interop.Sys.FnMatch(_searchPattern, dirent.InodeName, Interop.Sys.FnMatchFlags.FNM_NONE) == 0) { yield return(_translateResult(Path.Combine(dirPath.UserPath, dirent.InodeName), /*isDirectory*/ false)); } } } finally { // Close the directory enumerator dirHandle.Dispose(); dirHandle = null; } if (toExplore != null && toExplore.Count > 0) { // Open the next directory. dirPath = toExplore.Pop(); dirHandle = OpenDirectory(dirPath.FullPath); } } }