예제 #1
0
        /// <inheritdoc />
        protected override IFileSystemWatcher WatchImpl(UPath path)
        {
            // TODO: create/delete events when mounts are added/removed

            var watcher = new AggregateFileSystemWatcher(this, path);

            lock (_mounts)
                lock (_aggregateWatchers)
                {
                    foreach (var kvp in _mounts)
                    {
                        if (!IsMountIncludedInWatch(kvp.Key, path, out var remainingPath))
                        {
                            continue;
                        }

                        if (kvp.Value.CanWatch(remainingPath))
                        {
                            var internalWatcher = kvp.Value.Watch(remainingPath);
                            watcher.Add(new Watcher(kvp.Value, kvp.Key, remainingPath, internalWatcher));
                        }
                    }

                    if (NextFileSystem != null && NextFileSystem.CanWatch(path))
                    {
                        var internalWatcher = NextFileSystem.Watch(path);
                        watcher.Add(new Watcher(NextFileSystem, null, path, internalWatcher));
                    }

                    _aggregateWatchers.Add(watcher);
                }

            return(watcher);
        }
예제 #2
0
 public void Dispose()
 {
     if (Owned)
     {
         NextFileSystem?.Dispose();
     }
 }
예제 #3
0
 protected override void Dispose(bool disposing)
 {
     if (disposing && Owned)
     {
         NextFileSystem?.Dispose();
     }
 }
예제 #4
0
        /// <inheritdoc />
        protected override IFileSystemWatcher WatchImpl(UPath path)
        {
            lock (_fileSystems)
            {
                var watcher = new Watcher(this, path);

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

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

                _watchers.Add(watcher);
                return(watcher);
            }
        }
예제 #5
0
        /// <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 && NextFileSystem != null && NextFileSystem.DirectoryExists(basePath))
                {
                    locations.Add(new SearchLocation(NextFileSystem, 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);
                }
            }
        }
예제 #6
0
        /// <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);
            var originalSrcPath = path;

            // Internal method used to retrieve the list of root directories
            SortedSet <UPath> GetRootDirectories()
            {
                var directories = new SortedSet <UPath>(UPath.DefaultComparerIgnoreCase);

                lock (_mounts)
                {
                    foreach (var mountName in _mounts.Keys)
                    {
                        directories.Add(mountName);
                    }
                }

                if (NextFileSystem != null)
                {
                    foreach (var dir in NextFileSystem.EnumeratePaths(path, "*", SearchOption.TopDirectoryOnly, SearchTarget.Directory))
                    {
                        if (!directories.Contains(dir))
                        {
                            directories.Add(dir);
                        }
                    }
                }

                return(directories);
            }

            IEnumerable <UPath> EnumeratePathFromFileSystem(UPath subPath, bool failOnInvalidPath)
            {
                var fs = TryGetMountOrNext(ref subPath, out var mountPath);

                if (fs == null)
                {
                    if (failOnInvalidPath)
                    {
                        throw NewDirectoryNotFoundException(originalSrcPath);
                    }
                    yield break;
                }

                if (fs != NextFileSystem)
                {
                    // In the case of a mount, we need to return the full path
                    Debug.Assert(!mountPath.IsNull);

                    foreach (var entry in fs.EnumeratePaths(subPath, searchPattern, searchOption, searchTarget))
                    {
                        yield return(mountPath / entry.ToRelative());
                    }
                }
                else
                {
                    foreach (var entry in fs.EnumeratePaths(subPath, searchPattern, searchOption, searchTarget))
                    {
                        yield return(entry);
                    }
                }
            }

            // Special case for the root as we have to return the list of mount directories
            // and merge them with the underlying FileSystem
            if (path == UPath.Root)
            {
                var entries = new SortedSet <UPath>(UPath.DefaultComparerIgnoreCase);

                // Return the list of dircetories
                var directories = GetRootDirectories();

                // Process the files first
                if (NextFileSystem != null && (searchTarget == SearchTarget.File || searchTarget == SearchTarget.Both))
                {
                    foreach (var file in NextFileSystem.EnumeratePaths(path, searchPattern, SearchOption.TopDirectoryOnly, SearchTarget.File))
                    {
                        entries.Add(file);
                    }
                }

                if (searchTarget != SearchTarget.File)
                {
                    foreach (var dir in directories)
                    {
                        if (search.Match(dir))
                        {
                            entries.Add(dir);
                        }
                    }
                }

                // Return all entries sorted
                foreach (var entry in entries)
                {
                    yield return(entry);
                }

                if (searchOption == SearchOption.AllDirectories)
                {
                    foreach (var dir in directories)
                    {
                        foreach (var entry in EnumeratePathFromFileSystem(dir, false))
                        {
                            yield return(entry);
                        }
                    }
                }
            }
            else
            {
                foreach (var entry in EnumeratePathFromFileSystem(path, true))
                {
                    yield return(entry);
                }
            }
        }