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 }); }
/// <summary> /// Generate the result type from the current entry; /// </summary> protected abstract TResult TransformEntry(ref FileSystemEntry entry);
/// <summary> /// Return true if the directory entry given should be recursed into. /// </summary> protected virtual bool ShouldRecurseIntoEntry(ref FileSystemEntry entry) => true;
/// <summary> /// Return true if the given file system entry should be included in the results. /// </summary> protected virtual bool ShouldIncludeEntry(ref FileSystemEntry entry) => true;
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); } } }
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); } }
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); }
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); } }
protected override bool ShouldIncludeEntry(ref FileSystemEntry entry) => _enumerable.ShouldIncludePredicate?.Invoke(ref entry) ?? true;
protected override bool ShouldRecurseIntoEntry(ref FileSystemEntry entry) => _enumerable.ShouldRecursePredicate?.Invoke(ref entry) ?? true;
protected override TResult TransformEntry(ref FileSystemEntry entry) => _enumerable._transform(ref entry);