internal static bool Initialize( ref FileSystemEntry entry, Interop.Sys.DirectoryEntry directoryEntry, ReadOnlySpan <char> directory, string rootDirectory, string originalRootDirectory, Span <char> pathBuffer) { entry._directoryEntry = directoryEntry; entry.Directory = directory; entry.RootDirectory = rootDirectory; entry.OriginalRootDirectory = originalRootDirectory; entry._pathBuffer = pathBuffer; // Get from the dir entry whether the entry is a file or directory. // We classify everything as a file unless we know it to be a directory. // (This includes regular files, FIFOs, etc.) bool isDirectory = false; if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_DIR) { // We know it's a directory. isDirectory = true; } 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) { // It's a symlink or unknown: stat to it to see if we can resolve it to a directory. isDirectory = (targetStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR; } FileStatus.Initialize(ref entry._status, isDirectory); return(isDirectory); }
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; if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_DIR) { // We know it's a directory. isDirectory = true; } 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) { // Symlink or unknown: Stat to it to see if we can resolve it to a directory. isDirectory = (targetStatus.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFDIR; } entry._status = default; FileStatus.Initialize(ref entry._status, isDirectory); FileAttributes attributes = default; if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK) { 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); }
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; entry._status.InvalidateCaches(); bool isDirectory = directoryEntry.InodeType == Interop.Sys.NodeType.DT_DIR; bool isSymlink = directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK; bool isUnknown = directoryEntry.InodeType == Interop.Sys.NodeType.DT_UNKNOWN; // 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 // symlink or a directory. if (isUnknown) { isSymlink = entry.IsSymbolicLink; // Need to fail silently in case we are enumerating isDirectory = entry._status.IsDirectory(entry.FullPath, continueOnError: true); } // Same idea as the directory check, just repeated for (and tweaked due to the // nature of) symlinks. // Whether we had the dirent structure or not, we treat a symlink to a directory as a directory, // so we need to reflect that in our isDirectory variable. else if (isSymlink) { // Need to fail silently in case we are enumerating isDirectory = entry._status.IsDirectory(entry.FullPath, continueOnError: true); } entry._status.InitiallyDirectory = isDirectory; FileAttributes attributes = default; if (isSymlink) { attributes |= FileAttributes.ReparsePoint; } if (isDirectory) { attributes |= FileAttributes.Directory; } return(attributes); }
private static string?GetDirectoryEntryFullPath(ref Interop.Sys.DirectoryEntry dirent, string currentPath) { ReadOnlySpan <char> direntName = dirent.GetName(stackalloc char[Interop.Sys.DirectoryEntry.NameBufferSize]); if ((direntName.Length == 1 && direntName[0] == '.') || (direntName.Length == 2 && direntName[0] == '.' && direntName[1] == '.')) { return(null); } return(Path.Join(currentPath.AsSpan(), direntName)); }
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; entry._isDirectory = false; entry._status.InvalidateCaches(); bool isDirectory = directoryEntry.InodeType == Interop.Sys.NodeType.DT_DIR; bool isSymlink = directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK; bool isUnknown = directoryEntry.InodeType == Interop.Sys.NodeType.DT_UNKNOWN; if (isDirectory) { entry._isDirectory = true; } else if (isSymlink) { entry._isDirectory = entry._status.IsDirectory(entry.FullPath, continueOnError: true); } else if (isUnknown) { entry._isDirectory = entry._status.IsDirectory(entry.FullPath, continueOnError: true); if (entry._status.IsSymbolicLink(entry.FullPath, continueOnError: true)) { entry._directoryEntry.InodeType = Interop.Sys.NodeType.DT_LNK; } } FileAttributes attributes = default; if (entry.IsSymbolicLink) { attributes |= FileAttributes.ReparsePoint; } if (entry.IsDirectory) { attributes |= FileAttributes.Directory; } return(attributes); }
// TODO: Unix implementation https://github.com/dotnet/corefx/issues/26715 // Inital implementation is naive and not optimized. internal static void Initialize( ref FileSystemEntry entry, Interop.Sys.DirectoryEntry directoryEntry, bool isDirectory, ReadOnlySpan <char> directory, string rootDirectory, string originalRootDirectory) { entry._directoryEntry = directoryEntry; entry._isDirectory = isDirectory; entry.Directory = directory; entry.RootDirectory = rootDirectory; entry.OriginalRootDirectory = originalRootDirectory; }
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 statInfo) >= 0) { // Symlink or unknown: Stat to it to see if we can resolve it to a directory. isDirectory = FileStatus.IsDirectory(statInfo); } // Same idea as the directory check, just repeated for (and tweaked due to the nature of) symlinks. int resultLStat = Interop.Sys.LStat(entry.FullPath, out Interop.Sys.FileStatus lstatInfo); bool isReadOnly = resultLStat >= 0 && FileStatus.IsReadOnly(lstatInfo); if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK) { isSymlink = true; } else if (resultLStat >= 0 && directoryEntry.InodeType == Interop.Sys.NodeType.DT_UNKNOWN) { isSymlink = FileStatus.IsSymLink(lstatInfo); } // If the filename starts with a period or has UF_HIDDEN flag set, it's hidden. bool isHidden = directoryEntry.Name[0] == '.' || (resultLStat >= 0 && FileStatus.IsHidden(lstatInfo)); entry._status = default; FileStatus.Initialize(ref entry._status, isDirectory); FileAttributes attributes = FileStatus.GetAttributes(isReadOnly, isSymlink, isDirectory, isHidden); entry._initialAttributes = attributes; return(attributes); }
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) { // Symlink or unknown: Stat to it to see if we can resolve it to a directory. 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); }
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; if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_DIR) { // We know it's a directory. isDirectory = true; } 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; } entry._status = default; FileStatus.Initialize(ref entry._status, isDirectory); FileAttributes attributes = default; if (directoryEntry.InodeType == Interop.Sys.NodeType.DT_LNK) { 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); }