diff --git a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs index 6341d86f818709..b361ec1ef947fb 100644 --- a/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs @@ -16,7 +16,7 @@ public sealed partial class SafeFileHandle : SafeHandleZeroOrMinusOneIsInvalid // not using bool? as it's not thread safe private volatile NullableBool _canSeek = NullableBool.Undefined; - private volatile NullableBool _supportsRandomAccess = NullableBool.Undefined; + private volatile NullableBool _isRegularFile = NullableBool.Undefined; private bool _deleteOnClose; private bool _isLocked; @@ -34,20 +34,7 @@ private SafeFileHandle(bool ownsHandle) internal bool CanSeek => !IsClosed && GetCanSeek(); - internal bool SupportsRandomAccess - { - get - { - NullableBool supportsRandomAccess = _supportsRandomAccess; - if (supportsRandomAccess == NullableBool.Undefined) - { - _supportsRandomAccess = supportsRandomAccess = GetCanSeek() ? NullableBool.True : NullableBool.False; - } - - return supportsRandomAccess == NullableBool.True; - } - set => _supportsRandomAccess = value ? NullableBool.True : NullableBool.False; - } + internal bool IsRegularFile => GetIsRegularFile(); internal ThreadPoolBoundHandle? ThreadPoolBinding => null; @@ -112,8 +99,13 @@ private static SafeFileHandle Open(string path, Interop.Sys.OpenFlags flags, int // and for regular files (most common case) // avoid one extra sys call for determining whether file can be seeked handle._canSeek = NullableBool.True; + handle._isRegularFile = NullableBool.True; Debug.Assert(Interop.Sys.LSeek(handle, 0, Interop.Sys.SeekWhence.SEEK_CUR) >= 0); } + else + { + handle._isRegularFile = NullableBool.False; + } } return handle; @@ -405,6 +397,18 @@ private bool GetCanSeek() return canSeek == NullableBool.True; } + private bool GetIsRegularFile() + { + NullableBool isRegularFile = _isRegularFile; + if (isRegularFile == NullableBool.Undefined) + { + _isRegularFile = isRegularFile = (Interop.Sys.FStat(this, out Interop.Sys.FileStatus status) == 0 + && (status.Mode & Interop.Sys.FileTypes.S_IFMT) == Interop.Sys.FileTypes.S_IFREG) ? NullableBool.True : NullableBool.False; + } + + return isRegularFile == NullableBool.True; + } + private enum NullableBool { Undefined = 0, diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs index d922e89c13de5b..1db7c675f4d0b1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs @@ -33,30 +33,9 @@ internal static unsafe int ReadAtOffset(SafeFileHandle handle, Span buffer // The Windows implementation uses ReadFile, which ignores the offset if the handle // isn't seekable. We do the same manually with PRead vs Read, in order to enable // the function to be used by FileStream for all the same situations. - int result; - if (handle.SupportsRandomAccess) - { - // Try pread for seekable files. - result = Interop.Sys.PRead(handle, bufPtr, buffer.Length, fileOffset); - if (result == -1) - { - // We need to fallback to the non-offset version for certain file types - // e.g: character devices (such as /dev/tty), pipes, and sockets. - Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); - - if (errorInfo.Error == Interop.Error.ENXIO || - errorInfo.Error == Interop.Error.ESPIPE) - { - handle.SupportsRandomAccess = false; - result = Interop.Sys.Read(handle, bufPtr, buffer.Length); - } - } - } - else - { - result = Interop.Sys.Read(handle, bufPtr, buffer.Length); - } - + int result = handle.IsRegularFile ? + Interop.Sys.PRead(handle, bufPtr, buffer.Length, fileOffset) : + Interop.Sys.Read(handle, bufPtr, buffer.Length); FileStreamHelpers.CheckFileCall(result, handle.Path); return result; } @@ -111,29 +90,9 @@ internal static unsafe void WriteAtOffset(SafeFileHandle handle, ReadOnlySpan