Exemple #1
0
        /// <inheritdoc />
        protected override IFileSystemWatcher WatchImpl(UPath path)
        {
            var watcher = new Watcher(this, path);

            if (Fallback != null && Fallback.CanWatch(path) && Fallback.DirectoryExists(path))
            {
                watcher.Add(Fallback.Watch(path));
            }

            foreach (var fs in _fileSystems)
            {
                if (fs.CanWatch(path) && fs.DirectoryExists(path))
                {
                    watcher.Add(fs.Watch(path));
                }
            }

            _watchers.Add(watcher);
            return(watcher);
        }
        /// <inheritdoc />
        protected override IEnumerable <UPath> EnumeratePathsImpl(UPath path, string searchPattern, SearchOption searchOption, SearchTarget searchTarget)
        {
            // Use the search pattern to normalize the path/search pattern
            var search = SearchPattern.Parse(ref path, ref searchPattern);

            // Query all mounts just once
            List <KeyValuePair <UPath, IFileSystem> > mounts;

            lock (_mounts)
            {
                mounts = _mounts.ToList();
            }

            // Internal method used to retrieve the list of search locations
            List <SearchLocation> GetSearchLocations(UPath basePath)
            {
                var locations    = new List <SearchLocation>();
                var matchedMount = false;

                foreach (var kvp in mounts)
                {
                    // Check if path partially matches a mount name
                    var remainingPath = GetRemaining(basePath, kvp.Key);
                    if (!remainingPath.IsNull && remainingPath != UPath.Root)
                    {
                        locations.Add(new SearchLocation(this, basePath, remainingPath));
                        continue;
                    }

                    if (!matchedMount)
                    {
                        // Check if path fully matches a mount name
                        remainingPath = GetRemaining(kvp.Key, basePath);
                        if (!remainingPath.IsNull)
                        {
                            matchedMount = true; // don't check other mounts, we don't want to merge them together

                            if (kvp.Value.DirectoryExists(remainingPath))
                            {
                                locations.Add(new SearchLocation(kvp.Value, kvp.Key, remainingPath));
                            }
                        }
                    }
                }

                if (!matchedMount && Fallback != null && Fallback.DirectoryExists(basePath))
                {
                    locations.Add(new SearchLocation(Fallback, UPath.Null, basePath));
                }

                return(locations);
            }

            var directoryToVisit = new List <UPath>();

            directoryToVisit.Add(path);

            var entries           = new SortedSet <UPath>(UPath.DefaultComparerIgnoreCase);
            var sortedDirectories = new SortedSet <UPath>(UPath.DefaultComparerIgnoreCase);

            var first = true;

            while (directoryToVisit.Count > 0)
            {
                var pathToVisit = directoryToVisit[0];
                directoryToVisit.RemoveAt(0);
                var dirIndex = 0;
                entries.Clear();
                sortedDirectories.Clear();

                var locations = GetSearchLocations(pathToVisit);

                // Only need to search within one filesystem, no need to sort or do other work
                if (locations.Count == 1 && locations[0].FileSystem != this && (!first || searchOption == SearchOption.AllDirectories))
                {
                    var last = locations[0];
                    foreach (var item in last.FileSystem.EnumeratePaths(last.Path, searchPattern, searchOption, searchTarget))
                    {
                        yield return(CombinePrefix(last.Prefix, item));
                    }
                }
                else
                {
                    for (var i = locations.Count - 1; i >= 0; i--)
                    {
                        var location   = locations[i];
                        var fileSystem = location.FileSystem;
                        var searchPath = location.Path;

                        if (fileSystem == this)
                        {
                            // List a single part of a mount name, queue it to be visited if needed
                            var mountPart = new UPath(searchPath.GetFirstDirectory(out _)).ToRelative();
                            var mountPath = location.Prefix / mountPart;

                            var isMatching = search.Match(mountPath);
                            if (isMatching && searchTarget != SearchTarget.File)
                            {
                                entries.Add(mountPath);
                            }

                            if (searchOption == SearchOption.AllDirectories)
                            {
                                sortedDirectories.Add(mountPath);
                            }
                        }
                        else
                        {
                            // List files in the mounted filesystems, merged and sorted into one list
                            foreach (var item in fileSystem.EnumeratePaths(searchPath, "*", SearchOption.TopDirectoryOnly, SearchTarget.Both))
                            {
                                var publicName = CombinePrefix(location.Prefix, item);
                                if (entries.Contains(publicName))
                                {
                                    continue;
                                }

                                var isFile      = fileSystem.FileExists(item);
                                var isDirectory = fileSystem.DirectoryExists(item);
                                var isMatching  = search.Match(publicName);

                                if (isMatching && ((isFile && searchTarget != SearchTarget.Directory) || (isDirectory && searchTarget != SearchTarget.File)))
                                {
                                    entries.Add(publicName);
                                }

                                if (searchOption == SearchOption.AllDirectories && isDirectory)
                                {
                                    sortedDirectories.Add(publicName);
                                }
                            }
                        }
                    }
                }

                if (first)
                {
                    if (locations.Count == 0 && path != UPath.Root)
                    {
                        throw NewDirectoryNotFoundException(path);
                    }

                    first = false;
                }

                // Enqueue directories and respect order
                foreach (var nextDir in sortedDirectories)
                {
                    directoryToVisit.Insert(dirIndex++, nextDir);
                }

                // Return entries
                foreach (var entry in entries)
                {
                    yield return(entry);
                }
            }
        }
Exemple #3
0
        /// <inheritdoc/>
        protected override IEnumerable <FileSystemItem> EnumerateItemsImpl(UPath path, SearchOption searchOption, SearchPredicate?searchPredicate)
        {
            // Internal method used to retrieve the list of search locations
            List <SearchLocation> GetSearchLocations(UPath basePath)
            {
                var locations    = new List <SearchLocation>();
                var matchedMount = false;

                foreach (var kvp in _mounts)
                {
                    // Check if path partially matches a mount name
                    var remainingPath = GetRemaining(basePath, kvp.Key);
                    if (!remainingPath.IsNull && remainingPath != UPath.Root)
                    {
                        locations.Add(new SearchLocation(this, basePath, remainingPath));
                        continue;
                    }

                    if (!matchedMount)
                    {
                        // Check if path fully matches a mount name
                        remainingPath = GetRemaining(kvp.Key, basePath);
                        if (!remainingPath.IsNull)
                        {
                            matchedMount = true; // don't check other mounts, we don't want to merge them together

                            if (kvp.Value.DirectoryExists(remainingPath))
                            {
                                locations.Add(new SearchLocation(kvp.Value, kvp.Key, remainingPath));
                            }
                        }
                    }
                }

                if (!matchedMount && Fallback != null && Fallback.DirectoryExists(basePath))
                {
                    locations.Add(new SearchLocation(Fallback, UPath.Null, basePath));
                }

                return(locations);
            }

            var directoryToVisit = new List <UPath> {
                path
            };

            var entries           = new HashSet <UPath>();
            var sortedDirectories = new SortedSet <UPath>();

            var first = true;

            while (directoryToVisit.Count > 0)
            {
                var pathToVisit = directoryToVisit[0];
                directoryToVisit.RemoveAt(0);
                var dirIndex = 0;
                entries.Clear();
                sortedDirectories.Clear();

                var locations = GetSearchLocations(pathToVisit);

                // Only need to search within one filesystem, no need to sort or do other work
                if (locations.Count == 1 && locations[0].FileSystem != this && (!first || searchOption == SearchOption.AllDirectories))
                {
                    var last = locations[0];
                    foreach (var item in last.FileSystem.EnumerateItems(last.Path, searchOption, searchPredicate))
                    {
                        var localItem = item;
                        localItem.Path = CombinePrefix(last.Prefix, item.Path);
                        if (entries.Add(localItem.Path))
                        {
                            yield return(localItem);
                        }
                    }
                }
                else
                {
                    for (var i = locations.Count - 1; i >= 0; i--)
                    {
                        var location   = locations[i];
                        var fileSystem = location.FileSystem;
                        var searchPath = location.Path;

                        if (fileSystem == this)
                        {
                            // List a single part of a mount name, queue it to be visited if needed
                            var mountPart = new UPath(searchPath.GetFirstDirectory(out _)).ToRelative();
                            var mountPath = location.Prefix / mountPart;

                            var item = new FileSystemItem(this, mountPath, true);
                            if (searchPredicate == null || searchPredicate(ref item))
                            {
                                if (entries.Add(item.Path))
                                {
                                    yield return(item);
                                }
                            }

                            if (searchOption == SearchOption.AllDirectories)
                            {
                                sortedDirectories.Add(mountPath);
                            }
                        }
                        else
                        {
                            // List files in the mounted filesystems, merged and sorted into one list
                            foreach (var item in fileSystem.EnumerateItems(searchPath, SearchOption.TopDirectoryOnly, searchPredicate))
                            {
                                var publicName = CombinePrefix(location.Prefix, item.Path);
                                if (entries.Add(publicName))
                                {
                                    var localItem = item;
                                    localItem.Path = publicName;
                                    yield return(localItem);

                                    if (searchOption == SearchOption.AllDirectories && item.IsDirectory)
                                    {
                                        sortedDirectories.Add(publicName);
                                    }
                                }
                            }
                        }
                    }
                }

                if (first)
                {
                    if (locations.Count == 0 && path != UPath.Root)
                    {
                        throw NewDirectoryNotFoundException(path);
                    }

                    first = false;
                }

                // Enqueue directories and respect order
                foreach (var nextDir in sortedDirectories)
                {
                    directoryToVisit.Insert(dirIndex++, nextDir);
                }
            }
        }