コード例 #1
0
        private FileSystemItem TransformToFileSystemItem(ref System.IO.Enumeration.FileSystemEntry entry)
        {
            var fullPath = ConvertPathFromInternal(entry.ToFullPath());

            return(new FileSystemItem
            {
                FileSystem = this,
                AbsolutePath = fullPath,
                Path = fullPath,
                Attributes = entry.Attributes,
                CreationTime = entry.CreationTimeUtc.ToLocalTime(),
                LastAccessTime = entry.LastAccessTimeUtc.ToLocalTime(),
                LastWriteTime = entry.LastWriteTimeUtc.ToLocalTime(),
                Length = entry.Length
            });
        }
コード例 #2
0
 /// <summary>
 /// Generate the result type from the current entry;
 /// </summary>
 protected abstract TResult TransformEntry(ref FileSystemEntry entry);
コード例 #3
0
 /// <summary>
 /// Return true if the directory entry given should be recursed into.
 /// </summary>
 protected virtual bool ShouldRecurseIntoEntry(ref FileSystemEntry entry) => true;
コード例 #4
0
 /// <summary>
 /// Return true if the given file system entry should be included in the results.
 /// </summary>
 protected virtual bool ShouldIncludeEntry(ref FileSystemEntry entry) => true;
コード例 #5
0
        public bool MoveNext()
        {
            if (_lastEntryFound)
            {
                return(false);
            }

            FileSystemEntry entry = default;

            lock (_lock)
            {
                if (_lastEntryFound)
                {
                    return(false);

                    // If HAVE_READDIR_R is defined for the platform FindNextEntry depends on _entryBuffer being fixed since
                    // _entry will point to a string in the middle of the array. If the array is not fixed GC can move it after
                    // the native call and _entry will point to a bogus file name.
                    fixed(byte *entryBufferPtr = _entryBuffer)
                    {
                        do
                        {
                            FindNextEntry(entryBufferPtr, _entryBuffer == null ? 0 : _entryBuffer.Length);
                            if (_lastEntryFound)
                            {
                                return(false);
                            }

                            FileAttributes attributes = FileSystemEntry.Initialize(
                                ref entry, _entry, _currentPath, _rootDirectory, _originalRootDirectory, new Span <char>(_pathBuffer));
                            bool isDirectory = (attributes & FileAttributes.Directory) != 0;

                            bool isSpecialDirectory = false;
                            if (isDirectory)
                            {
                                // Subdirectory found
                                if (_entry.Name[0] == '.' && (_entry.Name[1] == 0 || (_entry.Name[1] == '.' && _entry.Name[2] == 0)))
                                {
                                    // "." or "..", don't process unless the option is set
                                    if (!_options.ReturnSpecialDirectories)
                                    {
                                        continue;
                                    }
                                    isSpecialDirectory = true;
                                }
                            }

                            if (!isSpecialDirectory && _options.AttributesToSkip != 0)
                            {
                                if ((_options.AttributesToSkip & FileAttributes.ReadOnly) != 0)
                                {
                                    // ReadOnly is the only attribute that requires hitting entry.Attributes (which hits the disk)
                                    attributes = entry.Attributes;
                                }

                                if ((_options.AttributesToSkip & attributes) != 0)
                                {
                                    continue;
                                }
                            }

                            if (isDirectory && !isSpecialDirectory)
                            {
                                if (_options.RecurseSubdirectories && ShouldRecurseIntoEntry(ref entry))
                                {
                                    // Recursion is on and the directory was accepted, Queue it
                                    if (_pending == null)
                                    {
                                        _pending = new Queue <string>();
                                    }
                                    _pending.Enqueue(Path.Join(_currentPath, entry.FileName));
                                }
                            }

                            if (ShouldIncludeEntry(ref entry))
                            {
                                _current = TransformEntry(ref entry);
                                return(true);
                            }
                        } while (true);
                    }
            }
        }
コード例 #6
0
        public bool MoveNext()
        {
            if (_lastEntryFound)
            {
                return(false);
            }

            FileSystemEntry entry = default;

            lock (_lock)
            {
                if (_lastEntryFound)
                {
                    return(false);
                }

                do
                {
                    FindNextEntry();
                    if (_lastEntryFound)
                    {
                        return(false);
                    }

                    FileAttributes attributes  = FileSystemEntry.Initialize(ref entry, _entry, _currentPath, _rootDirectory, _originalRootDirectory, new Span <char>(_pathBuffer));
                    bool           isDirectory = (attributes & FileAttributes.Directory) != 0;

                    bool isSpecialDirectory = false;
                    if (isDirectory)
                    {
                        // Subdirectory found
                        if (_entry.Name[0] == '.' && (_entry.Name[1] == 0 || (_entry.Name[1] == '.' && _entry.Name[2] == 0)))
                        {
                            // "." or "..", don't process unless the option is set
                            if (!_options.ReturnSpecialDirectories)
                            {
                                continue;
                            }
                            isSpecialDirectory = true;
                        }
                    }

                    if (!isSpecialDirectory && _options.AttributesToSkip != 0)
                    {
                        if ((_options.AttributesToSkip & FileAttributes.ReadOnly) != 0)
                        {
                            // ReadOnly is the only attribute that requires hitting entry.Attributes (which hits the disk)
                            attributes = entry.Attributes;
                        }

                        if (attributes != (FileAttributes)(-1) && (_options.AttributesToSkip & attributes) != 0)
                        {
                            continue;
                        }
                    }

                    if (isDirectory && !isSpecialDirectory)
                    {
                        if (_options.RecurseSubdirectories && ShouldRecurseIntoEntry(ref entry))
                        {
                            // Recursion is on and the directory was accepted, Queue it
                            if (_pending == null)
                            {
                                _pending = new Queue <string>();
                            }
                            _pending.Enqueue(PathHelpers.CombineNoChecks(_currentPath, entry.FileName));
                        }
                    }

                    if (ShouldIncludeEntry(ref entry))
                    {
                        _current = TransformEntry(ref entry);
                        return(true);
                    }
                } while (true);
            }
        }
コード例 #7
0
        internal static FileAttributes Initialize(
            ref FileSystemEntry entry,
            Interop.Sys.DirectoryEntry directoryEntry,
            ReadOnlySpan <char> directory,
            ReadOnlySpan <char> rootDirectory,
            ReadOnlySpan <char> originalRootDirectory,
            Span <char> pathBuffer)
        {
            entry._directoryEntry       = directoryEntry;
            entry.Directory             = directory;
            entry.RootDirectory         = rootDirectory;
            entry.OriginalRootDirectory = originalRootDirectory;
            entry._pathBuffer           = pathBuffer;
            entry._fullPath             = ReadOnlySpan <char> .Empty;
            entry._fileName             = ReadOnlySpan <char> .Empty;

            // IMPORTANT: Attribute logic must match the logic in FileStatus

            bool isDirectory = false;
            bool isSymlink   = false;

            if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_DIR)
            {
                // We know it's a directory.
                isDirectory = true;
            }
            // Some operating systems don't have the inode type in the dirent structure,
            // so we use DT_UNKNOWN as a sentinel value. As such, check if the dirent is a
            // directory.
            else if ((directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK ||
                      directoryEntry.InodeType == Interop.Sys.NodeType.DT_UNKNOWN) &&
                     (Interop.Sys.Stat(entry.FullPath, out Interop.Sys.FileStatus targetStatus) >= 0 ||
                      Interop.Sys.LStat(entry.FullPath, out targetStatus) >= 0))
            {
                // Symlink or unknown: Stat to it to see if we can resolve it to a directory. If Stat fails,
                // it could be because the symlink is broken, we don't have permissions, etc., in which
                // case fall back to using LStat to evaluate based on the symlink itself.
                isDirectory = (targetStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR;
            }
            // Same idea as the directory check, just repeated for (and tweaked due to the
            // nature of) symlinks.
            if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK)
            {
                isSymlink = true;
            }
            else if ((directoryEntry.InodeType == Interop.Sys.NodeType.DT_UNKNOWN) &&
                     (Interop.Sys.LStat(entry.FullPath, out Interop.Sys.FileStatus linkTargetStatus) >= 0))
            {
                isSymlink = (linkTargetStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK;
            }

            entry._status = default;
            FileStatus.Initialize(ref entry._status, isDirectory);

            FileAttributes attributes = default;

            if (isSymlink)
            {
                attributes |= FileAttributes.ReparsePoint;
            }
            if (isDirectory)
            {
                attributes |= FileAttributes.Directory;
            }
            if (directoryEntry.Name[0] == '.')
            {
                attributes |= FileAttributes.Hidden;
            }

            if (attributes == default)
            {
                attributes = FileAttributes.Normal;
            }

            entry._initialAttributes = attributes;
            return(attributes);
        }
コード例 #8
0
        public bool MoveNext()
        {
            if (_lastEntryFound)
            {
                return(false);
            }

            FileSystemEntry entry = default;

            lock (_lock)
            {
                if (_lastEntryFound)
                {
                    return(false);
                }

                do
                {
                    FindNextEntry();
                    if (_lastEntryFound)
                    {
                        return(false);
                    }

                    bool isDirectory = FileSystemEntry.Initialize(ref entry, _entry, _currentPath, _rootDirectory, _originalRootDirectory, new Span <char>(_pathBuffer));

                    if (_options.AttributesToSkip != 0)
                    {
                        if ((_options.AttributesToSkip & ~(FileAttributes.Directory | FileAttributes.Hidden | FileAttributes.ReparsePoint)) == 0)
                        {
                            // These three we don't have to hit the disk again to evaluate
                            if (((_options.AttributesToSkip & FileAttributes.Directory) != 0 && isDirectory) ||
                                ((_options.AttributesToSkip & FileAttributes.Hidden) != 0 && _entry.Name[0] == '.') ||
                                ((_options.AttributesToSkip & FileAttributes.ReparsePoint) != 0 && _entry.InodeType == Interop.Sys.NodeType.DT_LNK))
                            {
                                continue;
                            }
                        }
                        else if ((_options.AttributesToSkip & entry.Attributes) != 0)
                        {
                            // Hitting Attributes on the FileSystemEntry will cause a stat call
                            continue;
                        }
                    }

                    if (isDirectory)
                    {
                        // Subdirectory found
                        if (_entry.Name[0] == '.' && (_entry.Name[1] == 0 || (_entry.Name[1] == '.' && _entry.Name[2] == 0)))
                        {
                            // "." or "..", don't process unless the option is set
                            if (!_options.ReturnSpecialDirectories)
                            {
                                continue;
                            }
                        }
                        else if (_options.RecurseSubdirectories && ShouldRecurseIntoEntry(ref entry))
                        {
                            // Recursion is on and the directory was accepted, Queue it
                            if (_pending == null)
                            {
                                _pending = new Queue <string>();
                            }
                            _pending.Enqueue(PathHelpers.CombineNoChecks(_currentPath, entry.FileName));
                        }
                    }

                    if (ShouldIncludeEntry(ref entry))
                    {
                        _current = TransformEntry(ref entry);
                        return(true);
                    }
                } while (true);
            }
        }
コード例 #9
0
 protected override bool ShouldIncludeEntry(ref FileSystemEntry entry)
 => _enumerable.ShouldIncludePredicate?.Invoke(ref entry) ?? true;
コード例 #10
0
 protected override bool ShouldRecurseIntoEntry(ref FileSystemEntry entry)
 => _enumerable.ShouldRecursePredicate?.Invoke(ref entry) ?? true;
コード例 #11
0
 protected override TResult TransformEntry(ref FileSystemEntry entry) => _enumerable._transform(ref entry);