private static IEnumerable <string> InternalEnumerateFiles( string directoryName, string filePattern, string fromFilePath, SearchOption searchOption, CancellationToken cancellationToken) { Stack <string> folders = new Stack <string>(); Stack <string> currentFolderSubFolders = new Stack <string>(); folders.Push(directoryName); string[] pathSegList = null; bool passedContinuationToken = false; int pathSegListIndex = 0; if (null != fromFilePath) { pathSegList = fromFilePath.Split(new char[] { Path.DirectorySeparatorChar }); } else { passedContinuationToken = true; } while (folders.Count > 0) { string folder = AppendDirectorySeparator(folders.Pop()); Utils.CheckCancellation(cancellationToken); // Skip non-existent folders if (!LongPathDirectory.Exists(folder)) { continue; } #if CODE_ACCESS_SECURITY // Only accessible to fully trusted code in non-CAS models try { CheckPathDiscoveryPermission(folder); } catch (SecurityException) { // Ignore this folder if we have no right to discovery it. continue; } #else // CODE_ACCESS_SECURITY try { // In non-CAS scenarios, it's still important to check for folder accessibility // since the OS can block access to some paths. Getting files from a location // will force path discovery checks which will indicate whether or not the user // is authorized to access the directory. LongPathDirectory.GetFiles(folder); } catch (SecurityException) { // Ignore this folder if we have no right to discovery it. continue; } catch (UnauthorizedAccessException) { // Ignore this folder if we have no right to discovery it. continue; } #endif // CODE_ACCESS_SECURITY // Return all files contained directly in this folder (which occur after the continuationTokenFile) // Only consider the folder if the continuation token is already past or the continuation token may be passed by // a file within this directory (based on pathSegListIndex and the patSegList.Length) if (passedContinuationToken || (pathSegList.Length - 1 == pathSegListIndex)) { string continuationTokenFile = null; if (!passedContinuationToken) { continuationTokenFile = pathSegList[pathSegListIndex]; } // Load files directly under this folder. foreach (var filePath in LongPathDirectory.EnumerateFileSystemEntries(folder, filePattern, SearchOption.TopDirectoryOnly)) { Utils.CheckCancellation(cancellationToken); FileAttributes fileAttributes = FileAttributes.Normal; string fileName = null; try { fileName = LongPath.GetFileName(filePath); fileAttributes = LongPathFile.GetAttributes(filePath); } // Cross-plat file system accessibility settings may cause exceptions while // retrieving attributes from inaccessible paths. These paths shold be skipped. catch (FileNotFoundException) { } catch (IOException) { } catch (UnauthorizedAccessException) { } if (fileName == null) { continue; } if (FileAttributes.Directory != (fileAttributes & FileAttributes.Directory)) { if (passedContinuationToken) { yield return(LongPath.Combine(folder, fileName)); } else { if (CrossPlatformHelpers.IsLinux) { if (!passedContinuationToken) { if (string.Equals(fileName, continuationTokenFile, StringComparison.Ordinal)) { passedContinuationToken = true; } } else { yield return(LongPath.Combine(folder, fileName)); } } else { // Windows file system is case-insensitive; OSX and Linux are case-sensitive var comparison = CrossPlatformHelpers.IsWindows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; int compareResult = string.Compare(fileName, continuationTokenFile, comparison); if (compareResult < 0) { // Skip files prior to the continuation token file continue; } passedContinuationToken = true; if (compareResult > 0) { yield return(LongPath.Combine(folder, fileName)); } } } } } // Passed folder which continuation token file is under, // set passedContinuationToken to true. passedContinuationToken = true; } // Next add sub-folders for processing if (SearchOption.AllDirectories == searchOption) { string fromSubfolder = null; bool passedSubfoler = passedContinuationToken; if (!passedContinuationToken) { fromSubfolder = pathSegList[pathSegListIndex]; pathSegListIndex++; } // Add sub-folders. foreach (var filePath in LongPathDirectory.EnumerateFileSystemEntries(folder, "*", SearchOption.TopDirectoryOnly)) { Utils.CheckCancellation(cancellationToken); FileAttributes fileAttributes = FileAttributes.Normal; string fileName = null; try { fileName = LongPath.GetFileName(filePath); fileAttributes = LongPathFile.GetAttributes(filePath); } // Cross-plat file system accessibility settings may cause exceptions while // retrieving attributes from inaccessible paths. These paths shold be skipped. catch (FileNotFoundException) { } catch (IOException) { } catch (UnauthorizedAccessException) { } if (fileName == null) { continue; } if (FileAttributes.Directory == (fileAttributes & FileAttributes.Directory) && !fileName.Equals(@".") && !fileName.Equals(@"..")) { // TODO: Ignore junction point or not. Make it configurable. if (FileAttributes.ReparsePoint != (fileAttributes & FileAttributes.ReparsePoint)) { if (passedSubfoler) { currentFolderSubFolders.Push(LongPath.Combine(folder, fileName)); } else { if (CrossPlatformHelpers.IsLinux) { if (string.Equals(fileName, fromSubfolder, StringComparison.Ordinal)) { passedSubfoler = true; currentFolderSubFolders.Push(LongPath.Combine(folder, fileName)); } } else { // Windows file system is case-insensitive; OSX and Linux are case-sensitive var comparison = CrossPlatformHelpers.IsWindows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; int compareResult = string.Compare(fileName, fromSubfolder, comparison); if (compareResult >= 0) { passedSubfoler = true; currentFolderSubFolders.Push(LongPath.Combine(folder, fileName)); if (compareResult > 0) { passedContinuationToken = true; } } } } } } } if (currentFolderSubFolders.Count <= 0) { passedContinuationToken = true; } else { while (currentFolderSubFolders.Count > 0) { folders.Push(currentFolderSubFolders.Pop()); } } } } }