From 2423af0d638ca35794125905d962bd19756d9ab4 Mon Sep 17 00:00:00 2001 From: carlossanlop Date: Tue, 4 May 2021 21:16:51 -0700 Subject: [PATCH] Defering some more file checking actions to FileStatus. Addressing accessibility of methods/properties. Addressing suggestions. --- .../IO/Enumeration/FileSystemEntry.Unix.cs | 15 +++++----- .../src/System/IO/FileStatus.Unix.cs | 30 +++++++++++-------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs b/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs index ea396bf9803241..e644d6e24d4c1a 100644 --- a/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs +++ b/src/libraries/System.IO.FileSystem/src/System/IO/Enumeration/FileSystemEntry.Unix.cs @@ -45,15 +45,15 @@ internal static FileAttributes Initialize( // directory. if (isSymlink || isUnknown) { - // DT_LNK: stat to it to see if we can resolve it to a directory - entry._status.TryRefreshSymbolicLinkCache(entry.FullPath); - isDirectory = entry._status.HasDirectoryFlag; + // DT_LNK and DT_UNKNOWN: stat to it to see if we can resolve it to a directory + isDirectory = entry._status.IsDirectory(entry.FullPath); } + // Same idea as the directory check, just repeated for (and tweaked due to the + // nature of) symlinks. if (isUnknown) { - entry._status.TryRefreshFileCache(entry.FullPath); - isSymlink = entry._status.HasSymbolicLinkFlag; + isSymlink = entry._status.IsSymbolicLink(entry.FullPath); } entry._status.InitiallyDirectory = isDirectory; @@ -63,10 +63,9 @@ internal static FileAttributes Initialize( attributes |= FileAttributes.ReparsePoint; if (isDirectory) attributes |= FileAttributes.Directory; - if ((directoryEntry.NameLength > 0 && directoryEntry.Name[0] == '.') || - (entry._status.IsFileCacheInitialized && entry._status.HasHiddenFlag)) // soft retrieval + if ((directoryEntry.NameLength > 0 && directoryEntry.Name[0] == '.') || entry._status.HasHiddenFlag) // soft retrieval attributes |= FileAttributes.Hidden; - if (entry._status.IsFileCacheInitialized && entry._status.HasReadOnlyFlag) // soft retrieval + if (entry._status.HasReadOnlyFlag) // soft retrieval attributes |= FileAttributes.ReadOnly; return attributes; diff --git a/src/libraries/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs b/src/libraries/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs index cfec11e90053fc..96ed7e569f870d 100644 --- a/src/libraries/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs +++ b/src/libraries/System.IO.FileSystem/src/System/IO/FileStatus.Unix.cs @@ -39,10 +39,10 @@ internal struct FileStatus // Exists as of the last refresh private bool _exists; - internal bool IsFileCacheInitialized => _initializedFileCache == 0; - internal bool IsSymlinkCacheInitialized => _initializedSymlinkCache == 0; + private bool IsFileCacheInitialized => _initializedFileCache == 0; + private bool IsSymlinkCacheInitialized => _initializedSymlinkCache == 0; - internal bool AreCachesInitialized => + private bool AreCachesInitialized => // The file cache should always be successfully refreshed _initializedFileCache == 0 && // The symbolic link cache only gets refreshed when the path is detected @@ -56,7 +56,8 @@ internal bool HasHiddenFlag get { Debug.Assert(IsFileCacheInitialized); - return (_fileCache.UserFlags & (uint)Interop.Sys.UserFlags.UF_HIDDEN) == (uint)Interop.Sys.UserFlags.UF_HIDDEN; + return IsFileCacheInitialized && + (_fileCache.UserFlags & (uint)Interop.Sys.UserFlags.UF_HIDDEN) == (uint)Interop.Sys.UserFlags.UF_HIDDEN; } } @@ -67,6 +68,10 @@ internal bool HasReadOnlyFlag get { Debug.Assert(IsFileCacheInitialized); + if (!IsFileCacheInitialized) + { + return false; + } #if TARGET_BROWSER const Interop.Sys.Permissions readBit = Interop.Sys.Permissions.S_IRUSR; const Interop.Sys.Permissions writeBit = Interop.Sys.Permissions.S_IWUSR; @@ -93,8 +98,8 @@ internal bool HasReadOnlyFlag } #endif - return ((_fileCache.Mode & (int)readBit) != 0 && // has read permission - (_fileCache.Mode & (int)writeBit) == 0); // but not write permission + return (_fileCache.Mode & (int)readBit) != 0 && // has read permission + (_fileCache.Mode & (int)writeBit) == 0; // but not write permission } } @@ -105,7 +110,8 @@ internal bool HasSymbolicLinkFlag get { Debug.Assert(IsFileCacheInitialized); - return (_fileCache.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK; + return IsFileCacheInitialized && + (_fileCache.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFLNK; } } @@ -175,7 +181,7 @@ internal bool IsSymbolicLink(ReadOnlySpan path, bool continueOnError = fal return HasSymbolicLinkFlag; } - public FileAttributes GetAttributes(ReadOnlySpan path, ReadOnlySpan fileName) + internal FileAttributes GetAttributes(ReadOnlySpan path, ReadOnlySpan fileName) { EnsureCachesInitialized(path); @@ -199,7 +205,7 @@ public FileAttributes GetAttributes(ReadOnlySpan path, ReadOnlySpan return attributes != default ? attributes : FileAttributes.Normal; } - public void SetAttributes(string path, FileAttributes attributes) + internal void SetAttributes(string path, FileAttributes attributes) { // Validate that only flags from the attribute are being provided. This is an // approximation for the validation done by the Win32 function. @@ -368,7 +374,7 @@ internal long GetLength(ReadOnlySpan path, bool continueOnError = false) // Tries to refresh the lstat cache (_fileCache) and, if the file is pointing to a symbolic link, then also the stat cache (_symlinkCache) // This method should not throw. Instead, we store the results, and we will throw when the user attempts to access any of the properties when there was a failure - public void RefreshCaches(ReadOnlySpan path) + internal void RefreshCaches(ReadOnlySpan path) { _isDirectory = false; path = Path.TrimEndingDirectorySeparator(path); @@ -436,10 +442,10 @@ private void ThrowOnCacheInitializationError(ReadOnlySpan path) } } - internal bool TryRefreshFileCache(ReadOnlySpan path, bool verify = true) => + private bool TryRefreshFileCache(ReadOnlySpan path) => VerifyStatCall(Interop.Sys.LStat(path, out _fileCache), out _initializedFileCache); - internal bool TryRefreshSymbolicLinkCache(ReadOnlySpan path, bool verify = true) => + private bool TryRefreshSymbolicLinkCache(ReadOnlySpan path) => VerifyStatCall(Interop.Sys.Stat(path, out _symlinkCache), out _initializedSymlinkCache); // Receives the return value of a stat or lstat call.