diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs
index fb59b175346807..05d74c84e789d5 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.FormatInfo.cs
@@ -22,129 +22,6 @@ static Sys()
private const int MountPointFormatBufferSizeInBytes = 32;
- ///
- /// Internal FileSystem names and magic numbers taken from man(2) statfs
- ///
- ///
- /// These value names MUST be kept in sync with those in GetDriveType below,
- /// where this enum must be a subset of the GetDriveType list, with the enum
- /// values here exactly matching a string there.
- ///
- internal enum UnixFileSystemTypes : long
- {
- adfs = 0xADF5,
- affs = 0xADFF,
- afs = 0x5346414F,
- anoninode = 0x09041934,
- aufs = 0x61756673,
- autofs = 0x0187,
- autofs4 = 0x6D4A556D,
- befs = 0x42465331,
- bdevfs = 0x62646576,
- bfs = 0x1BADFACE,
- binfmt_misc = 0x42494E4D,
- bootfs = 0xA56D3FF9,
- btrfs = 0x9123683E,
- ceph = 0x00C36400,
- cgroupfs = 0x0027E0EB,
- cgroup2fs = 0x63677270,
- cifs = 0xFF534D42,
- coda = 0x73757245,
- coherent = 0x012FF7B7,
- configfs = 0x62656570,
- cramfs = 0x28CD3D45,
- debugfs = 0x64626720,
- devfs = 0x1373,
- devpts = 0x1CD1,
- ecryptfs = 0xF15F,
- efs = 0x00414A53,
- exofs = 0x5DF5,
- ext = 0x137D,
- ext2_old = 0xEF51,
- ext2 = 0xEF53,
- ext3 = 0xEF53,
- ext4 = 0xEF53,
- fat = 0x4006,
- fd = 0xF00D1E,
- fhgfs = 0x19830326,
- fuse = 0x65735546,
- fuseblk = 0x65735546,
- fusectl = 0x65735543,
- futexfs = 0x0BAD1DEA,
- gfsgfs2 = 0x1161970,
- gfs2 = 0x01161970,
- gpfs = 0x47504653,
- hfs = 0x4244,
- hfsplus = 0x482B,
- hpfs = 0xF995E849,
- hugetlbfs = 0x958458F6,
- inodefs = 0x11307854,
- inotifyfs = 0x2BAD1DEA,
- isofs = 0x9660,
- // isofs = 0x4004, // R_WIN
- // isofs = 0x4000, // WIN
- jffs = 0x07C0,
- jffs2 = 0x72B6,
- jfs = 0x3153464A,
- kafs = 0x6B414653,
- lofs = 0xEF53, /* loopback filesystem, magic same as ext2 */
- logfs = 0xC97E8168,
- lustre = 0x0BD00BD0,
- minix_old = 0x137F, /* orig. minix */
- minix = 0x138F, /* 30 char minix */
- minix2 = 0x2468, /* minix V2 */
- minix2v2 = 0x2478, /* MINIX V2, 30 char names */
- minix3 = 0x4D5A,
- mqueue = 0x19800202,
- msdos = 0x4D44,
- nfs = 0x6969,
- nfsd = 0x6E667364,
- nilfs = 0x3434,
- novell = 0x564C,
- ntfs = 0x5346544E,
- openprom = 0x9FA1,
- ocfs2 = 0x7461636F,
- omfs = 0xC2993D87,
- overlay = 0x794C7630,
- overlayfs = 0x794C764F,
- panfs = 0xAAD7AAEA,
- pipefs = 0x50495045,
- proc = 0x9FA0,
- pstorefs = 0x6165676C,
- qnx4 = 0x002F,
- qnx6 = 0x68191122,
- ramfs = 0x858458F6,
- reiserfs = 0x52654973,
- romfs = 0x7275,
- rootfs = 0x53464846,
- rpc_pipefs = 0x67596969,
- samba = 0x517B,
- securityfs = 0x73636673,
- selinux = 0xF97CFF8C,
- smb = 0x517B,
- sockfs = 0x534F434B,
- squashfs = 0x73717368,
- sysfs = 0x62656572,
- sysv2 = 0x012FF7B6,
- sysv4 = 0x012FF7B5,
- tmpfs = 0x01021994,
- ubifs = 0x24051905,
- udf = 0x15013346,
- ufs = 0x00011954,
- ufscigam = 0x54190100, // ufs byteswapped
- ufs2 = 0x19540119,
- usbdevice = 0x9FA2,
- v9fs = 0x01021997,
- vmhgfs = 0xBACBACBC,
- vxfs = 0xA501FCF5,
- vzfs = 0x565A4653,
- xenfs = 0xABBA1974,
- xenix = 0x012FF7B4,
- xfs = 0x58465342,
- xia = 0x012FD16D,
- zfs = 0x2FC12FC1,
- }
-
[StructLayout(LayoutKind.Sequential)]
internal struct MountPointInformation
{
diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs
new file mode 100644
index 00000000000000..fd34f87418223f
--- /dev/null
+++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.InteropServices;
+using Microsoft.Win32.SafeHandles;
+
+internal static partial class Interop
+{
+ internal static partial class Sys
+ {
+ ///
+ /// Internal FileSystem names and magic numbers taken from man(2) statfs
+ ///
+ ///
+ /// These value names MUST be kept in sync with those in GetDriveType (moved to Interop.MountPoints.FormatInfo.cs),
+ /// where this enum must be a subset of the GetDriveType list, with the enum
+ /// values here exactly matching a string there.
+ ///
+ internal enum UnixFileSystemTypes : long
+ {
+ adfs = 0xADF5,
+ affs = 0xADFF,
+ afs = 0x5346414F,
+ anoninode = 0x09041934,
+ aufs = 0x61756673,
+ autofs = 0x0187,
+ autofs4 = 0x6D4A556D,
+ befs = 0x42465331,
+ bdevfs = 0x62646576,
+ bfs = 0x1BADFACE,
+ binfmt_misc = 0x42494E4D,
+ bootfs = 0xA56D3FF9,
+ btrfs = 0x9123683E,
+ ceph = 0x00C36400,
+ cgroupfs = 0x0027E0EB,
+ cgroup2fs = 0x63677270,
+ cifs = 0xFF534D42,
+ coda = 0x73757245,
+ coherent = 0x012FF7B7,
+ configfs = 0x62656570,
+ cramfs = 0x28CD3D45,
+ debugfs = 0x64626720,
+ devfs = 0x1373,
+ devpts = 0x1CD1,
+ ecryptfs = 0xF15F,
+ efs = 0x00414A53,
+ exofs = 0x5DF5,
+ ext = 0x137D,
+ ext2_old = 0xEF51,
+ ext2 = 0xEF53,
+ ext3 = 0xEF53,
+ ext4 = 0xEF53,
+ fat = 0x4006,
+ fd = 0xF00D1E,
+ fhgfs = 0x19830326,
+ fuse = 0x65735546,
+ fuseblk = 0x65735546,
+ fusectl = 0x65735543,
+ futexfs = 0x0BAD1DEA,
+ gfsgfs2 = 0x1161970,
+ gfs2 = 0x01161970,
+ gpfs = 0x47504653,
+ hfs = 0x4244,
+ hfsplus = 0x482B,
+ hpfs = 0xF995E849,
+ hugetlbfs = 0x958458F6,
+ inodefs = 0x11307854,
+ inotifyfs = 0x2BAD1DEA,
+ isofs = 0x9660,
+ // isofs = 0x4004, // R_WIN
+ // isofs = 0x4000, // WIN
+ jffs = 0x07C0,
+ jffs2 = 0x72B6,
+ jfs = 0x3153464A,
+ kafs = 0x6B414653,
+ lofs = 0xEF53, /* loopback filesystem, magic same as ext2 */
+ logfs = 0xC97E8168,
+ lustre = 0x0BD00BD0,
+ minix_old = 0x137F, /* orig. minix */
+ minix = 0x138F, /* 30 char minix */
+ minix2 = 0x2468, /* minix V2 */
+ minix2v2 = 0x2478, /* MINIX V2, 30 char names */
+ minix3 = 0x4D5A,
+ mqueue = 0x19800202,
+ msdos = 0x4D44,
+ nfs = 0x6969,
+ nfsd = 0x6E667364,
+ nilfs = 0x3434,
+ novell = 0x564C,
+ ntfs = 0x5346544E,
+ openprom = 0x9FA1,
+ ocfs2 = 0x7461636F,
+ omfs = 0xC2993D87,
+ overlay = 0x794C7630,
+ overlayfs = 0x794C764F,
+ panfs = 0xAAD7AAEA,
+ pipefs = 0x50495045,
+ proc = 0x9FA0,
+ pstorefs = 0x6165676C,
+ qnx4 = 0x002F,
+ qnx6 = 0x68191122,
+ ramfs = 0x858458F6,
+ reiserfs = 0x52654973,
+ romfs = 0x7275,
+ rootfs = 0x53464846,
+ rpc_pipefs = 0x67596969,
+ samba = 0x517B,
+ securityfs = 0x73636673,
+ selinux = 0xF97CFF8C,
+ smb = 0x517B,
+ smb2 = 0xFE534D42,
+ sockfs = 0x534F434B,
+ squashfs = 0x73717368,
+ sysfs = 0x62656572,
+ sysv2 = 0x012FF7B6,
+ sysv4 = 0x012FF7B5,
+ tmpfs = 0x01021994,
+ ubifs = 0x24051905,
+ udf = 0x15013346,
+ ufs = 0x00011954,
+ ufscigam = 0x54190100, // ufs byteswapped
+ ufs2 = 0x19540119,
+ usbdevice = 0x9FA2,
+ v9fs = 0x01021997,
+ vmhgfs = 0xBACBACBC,
+ vxfs = 0xA501FCF5,
+ vzfs = 0x565A4653,
+ xenfs = 0xABBA1974,
+ xenix = 0x012FF7B4,
+ xfs = 0x58465342,
+ xia = 0x012FD16D,
+ zfs = 0x2FC12FC1,
+ }
+
+ [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetFileSystemType")]
+ private static extern long GetFileSystemType(SafeFileHandle fd);
+
+ internal static bool TryGetFileSystemType(SafeFileHandle fd, out UnixFileSystemTypes fileSystemType)
+ {
+ long fstatfsResult = GetFileSystemType(fd);
+ fileSystemType = (UnixFileSystemTypes)fstatfsResult;
+ return fstatfsResult != -1;
+ }
+ }
+}
diff --git a/src/libraries/Native/Unix/Common/pal_config.h.in b/src/libraries/Native/Unix/Common/pal_config.h.in
index 2b86ed15d4cae7..9a02610534101b 100644
--- a/src/libraries/Native/Unix/Common/pal_config.h.in
+++ b/src/libraries/Native/Unix/Common/pal_config.h.in
@@ -5,6 +5,8 @@
#cmakedefine01 HAVE_MMAP64
#cmakedefine01 HAVE_FTRUNCATE64
#cmakedefine01 HAVE_POSIX_FADVISE64
+#cmakedefine01 HAVE_STATFS_VFS
+#cmakedefine01 HAVE_STATFS_MOUNT
#cmakedefine01 HAVE_FLOCK64
#cmakedefine01 HAVE_F_DUPFD_CLOEXEC
#cmakedefine01 HAVE_F_FULLFSYNC
diff --git a/src/libraries/Native/Unix/System.Native/entrypoints.c b/src/libraries/Native/Unix/System.Native/entrypoints.c
index b1b5a92e5f35b7..7af9f07532e91e 100644
--- a/src/libraries/Native/Unix/System.Native/entrypoints.c
+++ b/src/libraries/Native/Unix/System.Native/entrypoints.c
@@ -103,6 +103,7 @@ static const Entry s_sysNative[] =
DllImportEntry(SystemNative_INotifyRemoveWatch)
DllImportEntry(SystemNative_RealPath)
DllImportEntry(SystemNative_GetPeerID)
+ DllImportEntry(SystemNative_GetFileSystemType)
DllImportEntry(SystemNative_LockFileRegion)
DllImportEntry(SystemNative_LChflags)
DllImportEntry(SystemNative_LChflagsCanSetHiddenFlag)
diff --git a/src/libraries/Native/Unix/System.Native/pal_io.c b/src/libraries/Native/Unix/System.Native/pal_io.c
index d7eb6c4ab23aca..13f052974688b2 100644
--- a/src/libraries/Native/Unix/System.Native/pal_io.c
+++ b/src/libraries/Native/Unix/System.Native/pal_io.c
@@ -35,6 +35,11 @@
#if HAVE_INOTIFY
#include
#endif
+#if HAVE_STATFS_VFS // Linux
+#include
+#elif HAVE_STATFS_MOUNT // BSD
+#include
+#endif
#ifdef _AIX
#include
@@ -1379,6 +1384,20 @@ static int16_t ConvertLockType(int16_t managedLockType)
}
}
+int64_t SystemNative_GetFileSystemType(intptr_t fd)
+{
+#if HAVE_STATFS_VFS || HAVE_STATFS_MOUNT
+ int statfsRes;
+ struct statfs statfsArgs;
+ // for our needs (get file system type) statfs is always enough and there is no need to use statfs64
+ // which got deprecated in macOS 10.6, in favor of statfs
+ while ((statfsRes = fstatfs(ToFileDescriptor(fd), &statfsArgs)) == -1 && errno == EINTR) ;
+ return statfsRes == -1 ? (int64_t)-1 : (int64_t)statfsArgs.f_type;
+#else
+ #error "Platform doesn't support fstatfs"
+#endif
+}
+
int32_t SystemNative_LockFileRegion(intptr_t fd, int64_t offset, int64_t length, int16_t lockType)
{
int16_t unixLockType = ConvertLockType(lockType);
diff --git a/src/libraries/Native/Unix/System.Native/pal_io.h b/src/libraries/Native/Unix/System.Native/pal_io.h
index 1dc70387ad5eac..2af2eb3fa4bdd5 100644
--- a/src/libraries/Native/Unix/System.Native/pal_io.h
+++ b/src/libraries/Native/Unix/System.Native/pal_io.h
@@ -710,6 +710,11 @@ PALEXPORT char* SystemNative_RealPath(const char* path);
*/
PALEXPORT int32_t SystemNative_GetPeerID(intptr_t socket, uid_t* euid);
+/**
+* Returns file system type on success, or -1 on error.
+*/
+PALEXPORT int64_t SystemNative_GetFileSystemType(intptr_t fd);
+
/**
* Attempts to lock/unlock the region of the file "fd" specified by the offset and length. lockType
* can be set to F_UNLCK (2) for unlock or F_WRLCK (3) for lock.
diff --git a/src/libraries/Native/Unix/configure.cmake b/src/libraries/Native/Unix/configure.cmake
index b2cfdb3bc40c2a..18afacc2dbc59c 100644
--- a/src/libraries/Native/Unix/configure.cmake
+++ b/src/libraries/Native/Unix/configure.cmake
@@ -108,6 +108,28 @@ check_c_source_compiles(
# /in_pktinfo
+check_c_source_compiles(
+ "
+ #include
+ int main(void)
+ {
+ struct statfs s;
+ return 0;
+ }
+ "
+ HAVE_STATFS_VFS)
+
+check_c_source_compiles(
+ "
+ #include
+ int main(void)
+ {
+ struct statfs s;
+ return 0;
+ }
+ "
+ HAVE_STATFS_MOUNT)
+
check_c_source_compiles(
"
#include
diff --git a/src/libraries/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj b/src/libraries/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj
index c516eb543e3347..d07e89ec979be1 100644
--- a/src/libraries/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj
+++ b/src/libraries/System.IO.FileSystem.DriveInfo/src/System.IO.FileSystem.DriveInfo.csproj
@@ -56,6 +56,8 @@
Link="Common\Interop\Unix\Interop.Libraries.cs" />
+
= 0))
{
// The only error we care about is EWOULDBLOCK, which indicates that the file is currently locked by someone
// else and we would block trying to access it. Other errors, such as ENOTSUP (locking isn't supported) or
@@ -320,6 +327,40 @@ private void Init(string path, FileMode mode, FileAccess access, FileShare share
}
}
+ private bool CanLockTheFile(Interop.Sys.LockOperations lockOperation, FileAccess access)
+ {
+ Debug.Assert(lockOperation == Interop.Sys.LockOperations.LOCK_EX || lockOperation == Interop.Sys.LockOperations.LOCK_SH);
+
+ if (DisableFileLocking)
+ {
+ return false;
+ }
+ else if (lockOperation == Interop.Sys.LockOperations.LOCK_EX)
+ {
+ return true; // LOCK_EX is always OK
+ }
+ else if ((access & FileAccess.Write) == 0)
+ {
+ return true; // LOCK_SH is always OK when reading
+ }
+
+ if (!Interop.Sys.TryGetFileSystemType(this, out Interop.Sys.UnixFileSystemTypes unixFileSystemType))
+ {
+ return false; // assume we should not acquire the lock if we don't know the File System
+ }
+
+ switch (unixFileSystemType)
+ {
+ case Interop.Sys.UnixFileSystemTypes.nfs: // #44546
+ case Interop.Sys.UnixFileSystemTypes.smb:
+ case Interop.Sys.UnixFileSystemTypes.smb2: // #53182
+ case Interop.Sys.UnixFileSystemTypes.cifs:
+ return false; // LOCK_SH is not OK when writing to NFS, CIFS or SMB
+ default:
+ return true; // in all other situations it should be OK
+ }
+ }
+
private bool GetCanSeek()
{
Debug.Assert(!IsClosed);
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index d5c9d5ef37c96b..574dc6e71c6f72 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -1911,6 +1911,9 @@
Common\Interop\Unix\System.Native\Interop.ErrNo.cs
+
+ Common\Interop\Unix\System.Native\Interop.UnixFileSystemTypes.cs
+
Common\Interop\Unix\System.Native\Interop.FLock.cs