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