예제 #1
0
        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());
                        }
                    }
                }
            }
        }