From 136f4f1331cf0c397dfae597b1980dbfbde5e64b Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Wed, 7 Jan 2026 11:09:00 +0100 Subject: [PATCH 1/8] Trim UnixFileSystemTypes to the values .NET runtime cares about. --- .../Interop.MountPoints.FormatInfo.cs | 3 +- .../Interop.UnixFileSystemTypes.cs | 132 +----------------- src/native/libs/System.Native/pal_io.c | 128 +---------------- 3 files changed, 8 insertions(+), 255 deletions(-) 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 c7c4dd1ff3bd25..17305bcb5678e7 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 @@ -60,8 +60,7 @@ internal static unsafe Error GetFileSystemTypeNameForMountPoint(string name, out int result = GetFileSystemTypeNameForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes, &formatType); if (result == 0) { - format = formatType == -1 ? Utf8StringMarshaller.ConvertToManaged(formatBuffer)! - : (Enum.GetName(typeof(UnixFileSystemTypes), formatType) ?? ""); + format = formatType == -1 ? Utf8StringMarshaller.ConvertToManaged(formatBuffer)! : ""; return Error.SUCCESS; } else 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 index dd4ef23319febe..14ac769d5dc142 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs @@ -11,143 +11,17 @@ internal static partial class Interop internal static partial class Sys { /// - /// FileSystem magic numbers used to turn numbers into a DriveInfo.DriveFormat string representation. + /// FileSystem types used for special handling. /// /// - /// 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. - /// If possible, use names that match the Linux file system type strings. - /// Don't add multiple names for the same value. + /// As values, we use Linux magic numbers. These values are Linux specific. Mapping for other platforms happens in PAL. /// internal enum UnixFileSystemTypes : uint { - adfs = 0xADF5, - affs = 0xADFF, - afs = 0x5346414F, - anoninode = 0x09041934, - apfs = 0x1A, - aufs = 0x61756673, - autofs = 0x0187, - autofs4 = 0x6D4A556D, - befs = 0x42465331, - bdev = 0x62646576, - bfs = 0x1BADFACE, - bpf_fs = 0xCAFE4A11, - binfmt_misc = 0x42494E4D, - bootfs = 0xA56D3FF9, - btrfs = 0x9123683E, - ceph = 0x00C36400, - cgroup = 0x0027E0EB, - cgroup2 = 0x63677270, - cifs = 0xFF534D42, - coda = 0x73757245, - coherent = 0x012FF7B7, - configfs = 0x62656570, - // cpuset = 0x01021994, // same as tmpfs - cramfs = 0x28CD3D45, - // ctfs = 0x01021994, // same as tmpfs - debugfs = 0x64626720, - dev = 0x1373, - // devfs = 0x1373, // same as dev - devpts = 0x1CD1, - ecryptfs = 0xF15F, - efs = 0x00414A53, - exofs = 0x5DF5, - ext = 0x137D, - ext2_old = 0xEF51, - ext2 = 0xEF53, - // ext3 = 0xEF53, // same as ext2 - // ext4 = 0xEF53, // same as ext2 - f2fs = 0xF2F52010, - fat = 0x4006, - fd = 0xF00D1E, - fhgfs = 0x19830326, - fuse = 0x65735546, - // fuseblk = 0x65735546, // same as fuse - fusectl = 0x65735543, - futexfs = 0x0BAD1DEA, - // gfsgfs2 = 0x1161970, // same as gfs2 - 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, 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, - // mntfs = 0x01021994, // same as tmpfs - mqueue = 0x19800202, - msdos = 0x4D44, nfs = 0x6969, - nfsd = 0x6E667364, - nilfs = 0x3434, - novell = 0x564C, - ntfs = 0x5346544E, - // objfs = 0x01021994, // same as tmpfs - ocfs2 = 0x7461636F, - openprom = 0x9FA1, - omfs = 0xC2993D87, - overlay = 0x794C7630, - overlayfs = 0x794C764F, - panfs = 0xAAD7AAEA, - pipefs = 0x50495045, - proc = 0x9FA0, - pstore = 0x6165676C, - qnx4 = 0x002F, - qnx6 = 0x68191122, - ramfs = 0x858458F6, - reiserfs = 0x52654973, - romfs = 0x7275, - rootfs = 0x53464846, - rpc_pipefs = 0x67596969, - // samba = 0x517B, // same as smb - sdcardfs = 0x5DCA2DF5, - securityfs = 0x73636673, - selinuxfs = 0xF97CFF8C, - // sffs = 0x786F4256, // same as vboxfs - // sharefs = 0x01021994, // same as tmpfs + cifs = 0xFF534D42, smb = 0x517B, smb2 = 0xFE534D42, - sockfs = 0x534F434B, - squashfs = 0x73717368, - sysfs = 0x62656572, - sysv2 = 0x012FF7B6, - sysv4 = 0x012FF7B5, - tmpfs = 0x01021994, - tracefs = 0x74726163, - ubifs = 0x24051905, - udf = 0x15013346, - ufs = 0x00011954, - ufscigam = 0x54190100, // ufs byteswapped - ufs2 = 0x19540119, - usbdevice = 0x9FA2, - v9fs = 0x01021997, - // vagrant = 0x786F4256, // same as vboxfs - vboxfs = 0x786F4256, - vmhgfs = 0xBACBACBC, - vxfs = 0xA501FCF5, - vzfs = 0x565A4653, - xenfs = 0xABBA1974, - xenix = 0x012FF7B4, - xfs = 0x58465342, - xia = 0x012FD16D, - // udev = 0x01021994, // same as tmpfs - zfs = 0x2FC12FC1, } [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetFileSystemType")] diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index 23b226d74e0362..2474448d542db6 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -1561,137 +1561,17 @@ static int16_t ConvertLockType(int16_t managedLockType) } #if !HAVE_NON_LEGACY_STATFS || defined(TARGET_APPLE) || defined(TARGET_FREEBSD) +// Maps OS file system names to values from the managed UnixFileSystemTypes enum. +// UnixFileSystemTypes only includes values .NET wants to handle specifically. static uint32_t MapFileSystemNameToEnum(const char* fileSystemName) { uint32_t result = 0; - if (strcmp(fileSystemName, "adfs") == 0) result = 0xADF5; - else if (strcmp(fileSystemName, "affs") == 0) result = 0xADFF; - else if (strcmp(fileSystemName, "afs") == 0) result = 0x5346414F; - else if (strcmp(fileSystemName, "anoninode") == 0) result = 0x09041934; - else if (strcmp(fileSystemName, "apfs") == 0) result = 0x1A; - else if (strcmp(fileSystemName, "aufs") == 0) result = 0x61756673; - else if (strcmp(fileSystemName, "autofs") == 0) result = 0x0187; - else if (strcmp(fileSystemName, "autofs4") == 0) result = 0x6D4A556D; - else if (strcmp(fileSystemName, "befs") == 0) result = 0x42465331; - else if (strcmp(fileSystemName, "bdevfs") == 0) result = 0x62646576; - else if (strcmp(fileSystemName, "bfs") == 0) result = 0x1BADFACE; - else if (strcmp(fileSystemName, "bpf_fs") == 0) result = 0xCAFE4A11; - else if (strcmp(fileSystemName, "binfmt_misc") == 0) result = 0x42494E4D; - else if (strcmp(fileSystemName, "bootfs") == 0) result = 0xA56D3FF9; - else if (strcmp(fileSystemName, "btrfs") == 0) result = 0x9123683E; - else if (strcmp(fileSystemName, "ceph") == 0) result = 0x00C36400; - else if (strcmp(fileSystemName, "cgroupfs") == 0) result = 0x0027E0EB; - else if (strcmp(fileSystemName, "cgroup2fs") == 0) result = 0x63677270; + if (strcmp(fileSystemName, "nfs") == 0) result = 0x6969; else if (strcmp(fileSystemName, "cifs") == 0) result = 0xFF534D42; - else if (strcmp(fileSystemName, "coda") == 0) result = 0x73757245; - else if (strcmp(fileSystemName, "coherent") == 0) result = 0x012FF7B7; - else if (strcmp(fileSystemName, "configfs") == 0) result = 0x62656570; - else if (strcmp(fileSystemName, "cpuset") == 0) result = 0x01021994; - else if (strcmp(fileSystemName, "cramfs") == 0) result = 0x28CD3D45; - else if (strcmp(fileSystemName, "ctfs") == 0) result = 0x01021994; - else if (strcmp(fileSystemName, "debugfs") == 0) result = 0x64626720; - else if (strcmp(fileSystemName, "dev") == 0) result = 0x1373; - else if (strcmp(fileSystemName, "devfs") == 0) result = 0x1373; - else if (strcmp(fileSystemName, "devpts") == 0) result = 0x1CD1; - else if (strcmp(fileSystemName, "ecryptfs") == 0) result = 0xF15F; - else if (strcmp(fileSystemName, "efs") == 0) result = 0x00414A53; - else if (strcmp(fileSystemName, "exofs") == 0) result = 0x5DF5; - else if (strcmp(fileSystemName, "ext") == 0) result = 0x137D; - else if (strcmp(fileSystemName, "ext2_old") == 0) result = 0xEF51; - else if (strcmp(fileSystemName, "ext2") == 0) result = 0xEF53; - else if (strcmp(fileSystemName, "ext3") == 0) result = 0xEF53; - else if (strcmp(fileSystemName, "ext4") == 0) result = 0xEF53; - else if (strcmp(fileSystemName, "f2fs") == 0) result = 0xF2F52010; - else if (strcmp(fileSystemName, "fat") == 0) result = 0x4006; - else if (strcmp(fileSystemName, "fd") == 0) result = 0xF00D1E; - else if (strcmp(fileSystemName, "fhgfs") == 0) result = 0x19830326; - else if (strcmp(fileSystemName, "fuse") == 0) result = 0x65735546; - else if (strcmp(fileSystemName, "fuseblk") == 0) result = 0x65735546; - else if (strcmp(fileSystemName, "fusectl") == 0) result = 0x65735543; - else if (strcmp(fileSystemName, "futexfs") == 0) result = 0x0BAD1DEA; - else if (strcmp(fileSystemName, "gfsgfs2") == 0) result = 0x1161970; - else if (strcmp(fileSystemName, "gfs2") == 0) result = 0x01161970; - else if (strcmp(fileSystemName, "gpfs") == 0) result = 0x47504653; - else if (strcmp(fileSystemName, "hfs") == 0) result = 0x4244; - else if (strcmp(fileSystemName, "hfsplus") == 0) result = 0x482B; - else if (strcmp(fileSystemName, "hpfs") == 0) result = 0xF995E849; - else if (strcmp(fileSystemName, "hugetlbfs") == 0) result = 0x958458F6; - else if (strcmp(fileSystemName, "inodefs") == 0) result = 0x11307854; - else if (strcmp(fileSystemName, "inotifyfs") == 0) result = 0x2BAD1DEA; - else if (strcmp(fileSystemName, "isofs") == 0) result = 0x9660; - else if (strcmp(fileSystemName, "jffs") == 0) result = 0x07C0; - else if (strcmp(fileSystemName, "jffs2") == 0) result = 0x72B6; - else if (strcmp(fileSystemName, "jfs") == 0) result = 0x3153464A; - else if (strcmp(fileSystemName, "kafs") == 0) result = 0x6B414653; - else if (strcmp(fileSystemName, "lofs") == 0) result = 0xEF53; - else if (strcmp(fileSystemName, "logfs") == 0) result = 0xC97E8168; - else if (strcmp(fileSystemName, "lustre") == 0) result = 0x0BD00BD0; - else if (strcmp(fileSystemName, "minix_old") == 0) result = 0x137F; - else if (strcmp(fileSystemName, "minix") == 0) result = 0x138F; - else if (strcmp(fileSystemName, "minix2") == 0) result = 0x2468; - else if (strcmp(fileSystemName, "minix2v2") == 0) result = 0x2478; - else if (strcmp(fileSystemName, "minix3") == 0) result = 0x4D5A; - else if (strcmp(fileSystemName, "mntfs") == 0) result = 0x01021994; - else if (strcmp(fileSystemName, "mqueue") == 0) result = 0x19800202; - else if (strcmp(fileSystemName, "msdos") == 0) result = 0x4D44; - else if (strcmp(fileSystemName, "nfs") == 0) result = 0x6969; - else if (strcmp(fileSystemName, "nfsd") == 0) result = 0x6E667364; - else if (strcmp(fileSystemName, "nilfs") == 0) result = 0x3434; - else if (strcmp(fileSystemName, "novell") == 0) result = 0x564C; - else if (strcmp(fileSystemName, "ntfs") == 0) result = 0x5346544E; - else if (strcmp(fileSystemName, "objfs") == 0) result = 0x01021994; - else if (strcmp(fileSystemName, "ocfs2") == 0) result = 0x7461636F; - else if (strcmp(fileSystemName, "openprom") == 0) result = 0x9FA1; - else if (strcmp(fileSystemName, "omfs") == 0) result = 0xC2993D87; - else if (strcmp(fileSystemName, "overlay") == 0) result = 0x794C7630; - else if (strcmp(fileSystemName, "overlayfs") == 0) result = 0x794C764F; - else if (strcmp(fileSystemName, "panfs") == 0) result = 0xAAD7AAEA; - else if (strcmp(fileSystemName, "pipefs") == 0) result = 0x50495045; - else if (strcmp(fileSystemName, "proc") == 0) result = 0x9FA0; - else if (strcmp(fileSystemName, "pstorefs") == 0) result = 0x6165676C; - else if (strcmp(fileSystemName, "qnx4") == 0) result = 0x002F; - else if (strcmp(fileSystemName, "qnx6") == 0) result = 0x68191122; - else if (strcmp(fileSystemName, "ramfs") == 0) result = 0x858458F6; - else if (strcmp(fileSystemName, "reiserfs") == 0) result = 0x52654973; - else if (strcmp(fileSystemName, "romfs") == 0) result = 0x7275; - else if (strcmp(fileSystemName, "rootfs") == 0) result = 0x53464846; - else if (strcmp(fileSystemName, "rpc_pipefs") == 0) result = 0x67596969; - else if (strcmp(fileSystemName, "samba") == 0) result = 0x517B; - else if (strcmp(fileSystemName, "sdcardfs") == 0) result = 0x5DCA2DF5; - else if (strcmp(fileSystemName, "securityfs") == 0) result = 0x73636673; - else if (strcmp(fileSystemName, "selinux") == 0) result = 0xF97CFF8C; - else if (strcmp(fileSystemName, "sffs") == 0) result = 0x786F4256; - else if (strcmp(fileSystemName, "sharefs") == 0) result = 0x01021994; else if (strcmp(fileSystemName, "smb") == 0) result = 0x517B; else if (strcmp(fileSystemName, "smb2") == 0) result = 0xFE534D42; - else if (strcmp(fileSystemName, "sockfs") == 0) result = 0x534F434B; - else if (strcmp(fileSystemName, "squashfs") == 0) result = 0x73717368; - else if (strcmp(fileSystemName, "sysfs") == 0) result = 0x62656572; - else if (strcmp(fileSystemName, "sysv2") == 0) result = 0x012FF7B6; - else if (strcmp(fileSystemName, "sysv4") == 0) result = 0x012FF7B5; - else if (strcmp(fileSystemName, "tmpfs") == 0) result = 0x01021994; - else if (strcmp(fileSystemName, "tracefs") == 0) result = 0x74726163; - else if (strcmp(fileSystemName, "ubifs") == 0) result = 0x24051905; - else if (strcmp(fileSystemName, "udf") == 0) result = 0x15013346; - else if (strcmp(fileSystemName, "ufs") == 0) result = 0x00011954; - else if (strcmp(fileSystemName, "ufscigam") == 0) result = 0x54190100; - else if (strcmp(fileSystemName, "ufs2") == 0) result = 0x19540119; - else if (strcmp(fileSystemName, "usbdevice") == 0) result = 0x9FA2; - else if (strcmp(fileSystemName, "v9fs") == 0) result = 0x01021997; - else if (strcmp(fileSystemName, "vagrant") == 0) result = 0x786F4256; - else if (strcmp(fileSystemName, "vboxfs") == 0) result = 0x786F4256; - else if (strcmp(fileSystemName, "vmhgfs") == 0) result = 0xBACBACBC; - else if (strcmp(fileSystemName, "vxfs") == 0) result = 0xA501FCF5; - else if (strcmp(fileSystemName, "vzfs") == 0) result = 0x565A4653; - else if (strcmp(fileSystemName, "xenfs") == 0) result = 0xABBA1974; - else if (strcmp(fileSystemName, "xenix") == 0) result = 0x012FF7B4; - else if (strcmp(fileSystemName, "xfs") == 0) result = 0x58465342; - else if (strcmp(fileSystemName, "xia") == 0) result = 0x012FD16D; - else if (strcmp(fileSystemName, "udev") == 0) result = 0x01021994; - else if (strcmp(fileSystemName, "zfs") == 0) result = 0x2FC12FC1; - - assert(result != 0); + return result; } #endif From 1da80aaee0ca102d5463a1117c786f7e601b4093 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Wed, 7 Jan 2026 18:01:45 +0100 Subject: [PATCH 2/8] Replace SystemNative_GetFileSystemType by a method that returns if we can lock. --- .../Interop.FileSystemSupportsLocking.cs | 15 +++++ .../Interop.MountPoints.FormatInfo.cs | 12 ---- .../Interop.UnixFileSystemTypes.cs | 38 ------------ .../Common/tests/Common.Tests.csproj | 2 - .../src/System.Diagnostics.Process.csproj | 2 - .../src/System.IO.FileSystem.DriveInfo.csproj | 2 - .../Win32/SafeHandles/SafeFileHandle.Unix.cs | 15 +---- .../System.Private.CoreLib.Shared.projitems | 4 +- ...opServices.RuntimeInformation.Tests.csproj | 2 - src/native/libs/System.Native/entrypoints.c | 2 +- src/native/libs/System.Native/pal_io.c | 61 ++++++++++--------- src/native/libs/System.Native/pal_io.h | 4 +- 12 files changed, 55 insertions(+), 104 deletions(-) create mode 100644 src/libraries/Common/src/Interop/Unix/System.Native/Interop.FileSystemSupportsLocking.cs delete mode 100644 src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.FileSystemSupportsLocking.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.FileSystemSupportsLocking.cs new file mode 100644 index 00000000000000..19f095e859418a --- /dev/null +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.FileSystemSupportsLocking.cs @@ -0,0 +1,15 @@ +// 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 + { + [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_FileSystemSupportsLocking")] + [return: MarshalAs(UnmanagedType.Bool)] + internal static partial bool FileSystemSupportsLocking(SafeFileHandle fd); + } +} 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 17305bcb5678e7..4c2a9c6678bf0f 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 @@ -10,17 +10,6 @@ internal static partial class Interop { internal static partial class Sys { -#if DEBUG - static Sys() - { - foreach (string name in Enum.GetNames()) - { - System.Diagnostics.Debug.Assert(GetDriveType(name) != DriveType.Unknown, - $"Expected {nameof(UnixFileSystemTypes)}.{name} to have an entry in {nameof(GetDriveType)}."); - } - } -#endif - private const int MountPointFormatBufferSizeInBytes = 32; [StructLayout(LayoutKind.Sequential)] @@ -92,7 +81,6 @@ private static DriveType GetDriveType(string fileSystemName) // This list is based primarily on "man fs", "man mount", "mntent.h", "/proc/filesystems", coreutils "stat.c", // and "wiki.debian.org/FileSystem". It can be extended over time as we find additional file systems that should // be recognized as a particular drive type. - // Keep this in sync with the UnixFileSystemTypes enum in Interop.UnixFileSystemTypes.cs switch (fileSystemName) { case "cddafs": 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 deleted file mode 100644 index 14ac769d5dc142..00000000000000 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.UnixFileSystemTypes.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Diagnostics; -using System.Runtime.InteropServices; -using Microsoft.Win32.SafeHandles; - -internal static partial class Interop -{ - internal static partial class Sys - { - /// - /// FileSystem types used for special handling. - /// - /// - /// As values, we use Linux magic numbers. These values are Linux specific. Mapping for other platforms happens in PAL. - /// - internal enum UnixFileSystemTypes : uint - { - nfs = 0x6969, - cifs = 0xFF534D42, - smb = 0x517B, - smb2 = 0xFE534D42, - } - - [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetFileSystemType")] - private static partial uint GetFileSystemType(SafeFileHandle fd); - - internal static bool TryGetFileSystemType(SafeFileHandle fd, out UnixFileSystemTypes fileSystemType) - { - uint fstatfsResult = GetFileSystemType(fd); - fileSystemType = (UnixFileSystemTypes)fstatfsResult; - Debug.Assert(Enum.IsDefined(fileSystemType) || fstatfsResult == 0, $"GetFileSystemType returned {fstatfsResult}"); - return fstatfsResult != 0; - } - } -} diff --git a/src/libraries/Common/tests/Common.Tests.csproj b/src/libraries/Common/tests/Common.Tests.csproj index df0afcee4cd29a..8e842889a3d23f 100644 --- a/src/libraries/Common/tests/Common.Tests.csproj +++ b/src/libraries/Common/tests/Common.Tests.csproj @@ -123,8 +123,6 @@ Link="System\PasteArguments.Windows.cs" /> - diff --git a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj index 1207ea97a10aef..ecf85971bb7f35 100644 --- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj +++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj @@ -313,8 +313,6 @@ Link="Common\Interop\Linux\procfs\Interop.ProcMountInfo.cs" /> - - Common\Interop\Unix\System.Native\Interop.ErrNo.cs - - Common\Interop\Unix\System.Native\Interop.UnixFileSystemTypes.cs + + Common\Interop\Unix\System.Native\Interop.FileSystemSupportsLocking.cs Common\Interop\Unix\System.Native\Interop.FLock.cs diff --git a/src/libraries/System.Runtime/tests/System.Runtime.InteropServices.RuntimeInformation.Tests/System.Runtime.InteropServices.RuntimeInformation.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.InteropServices.RuntimeInformation.Tests/System.Runtime.InteropServices.RuntimeInformation.Tests.csproj index dc394f37d65800..b21850df267dfa 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.InteropServices.RuntimeInformation.Tests/System.Runtime.InteropServices.RuntimeInformation.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.InteropServices.RuntimeInformation.Tests/System.Runtime.InteropServices.RuntimeInformation.Tests.csproj @@ -29,7 +29,5 @@ Link="Common\Interop\Unix\System.Native\Interop.MountPoints.FormatInfo.cs" /> - diff --git a/src/native/libs/System.Native/entrypoints.c b/src/native/libs/System.Native/entrypoints.c index d5121676bbf642..aecab9a6a71831 100644 --- a/src/native/libs/System.Native/entrypoints.c +++ b/src/native/libs/System.Native/entrypoints.c @@ -115,7 +115,7 @@ static const Entry s_sysNative[] = DllImportEntry(SystemNative_INotifyRemoveWatch) DllImportEntry(SystemNative_RealPath) DllImportEntry(SystemNative_GetPeerID) - DllImportEntry(SystemNative_GetFileSystemType) + DllImportEntry(SystemNative_FileSystemSupportsLocking) DllImportEntry(SystemNative_LockFileRegion) DllImportEntry(SystemNative_LChflags) DllImportEntry(SystemNative_LChflagsCanSetHiddenFlag) diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index 2474448d542db6..3972d3696a7d93 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -70,6 +70,10 @@ extern int getpeereid(int, uid_t *__restrict__, gid_t *__restrict__); #include #endif +#if defined(TARGET_LINUX) +#include +#endif + #ifdef __linux__ #include @@ -1560,26 +1564,27 @@ static int16_t ConvertLockType(int16_t managedLockType) } } -#if !HAVE_NON_LEGACY_STATFS || defined(TARGET_APPLE) || defined(TARGET_FREEBSD) -// Maps OS file system names to values from the managed UnixFileSystemTypes enum. -// UnixFileSystemTypes only includes values .NET wants to handle specifically. -static uint32_t MapFileSystemNameToEnum(const char* fileSystemName) +#if HAVE_STATFS_FSTYPENAME || HAVE_STATVFS_BASETYPE +static uint32_t FileSystemNameSupportsLocking(const char* fileSystemName) { - uint32_t result = 0; - - if (strcmp(fileSystemName, "nfs") == 0) result = 0x6969; - else if (strcmp(fileSystemName, "cifs") == 0) result = 0xFF534D42; - else if (strcmp(fileSystemName, "smb") == 0) result = 0x517B; - else if (strcmp(fileSystemName, "smb2") == 0) result = 0xFE534D42; - - return result; + if (strcmp(fileSystemName, "nfs") == 0 || + strcmp(fileSystemName, "cifs") == 0 || + strcmp(fileSystemName, "smb") == 0 || + strcmp(fileSystemName, "smb2") == 0) + { + return 0; + } + return 1; } #endif #endif /* TARGET_WASI */ -uint32_t SystemNative_GetFileSystemType(intptr_t fd) +uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd) { -#if HAVE_STATFS_VFS || HAVE_STATFS_MOUNT + // This method returns false when we identify the file system to be nfs (#44546), samba/cifs (#53182). +#if defined(TARGET_WASI) + return 0; // WASI doesn't support locking. +#elif HAVE_STATFS_FSTYPENAME || defined(TARGET_LINUX) int statfsRes; struct statfs statfsArgs; // for our needs (get file system type) statfs is always enough and there is no need to use statfs64 @@ -1587,27 +1592,25 @@ uint32_t SystemNative_GetFileSystemType(intptr_t fd) while ((statfsRes = fstatfs(ToFileDescriptor(fd), &statfsArgs)) == -1 && errno == EINTR) ; if (statfsRes == -1) return 0; -#if defined(TARGET_APPLE) || defined(TARGET_FREEBSD) - // * On OSX-like systems, f_type is version-specific. Don't use it, just map the name. - // * Specifically, on FreeBSD with ZFS, f_type may return a value like 0xDE when emulating - // FreeBSD on macOS (e.g., FreeBSD-x64 on macOS ARM64). Therefore, we use f_fstypename to - // get the correct filesystem type. - return MapFileSystemNameToEnum(statfsArgs.f_fstypename); -#else - // On Linux, f_type is signed. This causes some filesystem types to be represented as - // negative numbers on 32-bit platforms. We cast to uint32_t to make them positive. - uint32_t result = (uint32_t)statfsArgs.f_type; - return result; +#if HAVE_STATFS_FSTYPENAME + return FileSystemNameSupportsLocking(statfsArgs.f_fstypename); +#elif defined(TARGET_LINUX) + if (statfsArgs.f_type == NFS_SUPER_MAGIC || + statfsArgs.f_type == CIFS_SUPER_MAGIC || + statfsArgs.f_type == SMB_SUPER_MAGIC || + statfsArgs.f_type == SMB2_SUPER_MAGIC) + { + return 0; + } + return 1; #endif -#elif defined(TARGET_WASI) - return EINTR; -#elif !HAVE_NON_LEGACY_STATFS +#elif HAVE_STATVFS_BASETYPE int statfsRes; struct statvfs statfsArgs; while ((statfsRes = fstatvfs(ToFileDescriptor(fd), &statfsArgs)) == -1 && errno == EINTR) ; if (statfsRes == -1) return 0; - return MapFileSystemNameToEnum(statfsArgs.f_basetype); + return FileSystemNameSupportsLocking(statfsArgs.f_basetype); #else #error "Platform doesn't support fstatfs or fstatvfs" #endif diff --git a/src/native/libs/System.Native/pal_io.h b/src/native/libs/System.Native/pal_io.h index 330fa2997b9f20..4072413f2cae42 100644 --- a/src/native/libs/System.Native/pal_io.h +++ b/src/native/libs/System.Native/pal_io.h @@ -764,9 +764,9 @@ 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 0 on error. +* Returns whether file system associated with the handle supports .NET compatible locking. */ -PALEXPORT uint32_t SystemNative_GetFileSystemType(intptr_t fd); +PALEXPORT uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd); /** * Attempts to lock/unlock the region of the file "fd" specified by the offset and length. lockType From da213618fe65adb1fd42519f2f7af9199d46e031 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Wed, 7 Jan 2026 18:53:04 +0100 Subject: [PATCH 3/8] Fix CI build failure. --- src/native/libs/System.Native/pal_io.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index 3972d3696a7d93..d90bc2b841b583 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -70,10 +70,6 @@ extern int getpeereid(int, uid_t *__restrict__, gid_t *__restrict__); #include #endif -#if defined(TARGET_LINUX) -#include -#endif - #ifdef __linux__ #include @@ -1595,10 +1591,10 @@ uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd) #if HAVE_STATFS_FSTYPENAME return FileSystemNameSupportsLocking(statfsArgs.f_fstypename); #elif defined(TARGET_LINUX) - if (statfsArgs.f_type == NFS_SUPER_MAGIC || - statfsArgs.f_type == CIFS_SUPER_MAGIC || - statfsArgs.f_type == SMB_SUPER_MAGIC || - statfsArgs.f_type == SMB2_SUPER_MAGIC) + if (statfsArgs.f_type == 0x6969 || // NFS_SUPER_MAGIC + statfsArgs.f_type == 0xFF534D42 || // CIFS_SUPER_MAGIC + statfsArgs.f_type == 0x517B || // SMB_SUPER_MAGIC + statfsArgs.f_type == 0xFE534D42) // SMB2_SUPER_MAGIC { return 0; } From 9809b7cf82f5ecb6bf17371a0e90cf0b03def90a Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Wed, 7 Jan 2026 19:20:35 +0100 Subject: [PATCH 4/8] Simplify CanLockTheFile. --- .../src/Microsoft/Win32/SafeHandles/SafeFileHandle.Unix.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) 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 fa10c954fdf467..d0f8a4f5e862db 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 @@ -471,12 +471,7 @@ private bool CanLockTheFile(Interop.Sys.LockOperations lockOperation, FileAccess return true; // LOCK_SH is always OK when reading } - if (!Interop.Sys.FileSystemSupportsLocking(this)) - { - return false; - } - - return true; + return Interop.Sys.FileSystemSupportsLocking(this); } private void FStatCheckIO(string path, ref Interop.Sys.FileStatus status, ref bool statusHasValue) From d05c8992010abff4101b303a27d477b7e51e5966 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Wed, 7 Jan 2026 19:34:22 +0100 Subject: [PATCH 5/8] Handle f_type as an unsigned int. --- src/native/libs/System.Native/pal_io.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index d90bc2b841b583..bcfbe23264d462 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -1591,10 +1591,11 @@ uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd) #if HAVE_STATFS_FSTYPENAME return FileSystemNameSupportsLocking(statfsArgs.f_fstypename); #elif defined(TARGET_LINUX) - if (statfsArgs.f_type == 0x6969 || // NFS_SUPER_MAGIC - statfsArgs.f_type == 0xFF534D42 || // CIFS_SUPER_MAGIC - statfsArgs.f_type == 0x517B || // SMB_SUPER_MAGIC - statfsArgs.f_type == 0xFE534D42) // SMB2_SUPER_MAGIC + unsigned int f_type = (unsigned int)statfsArgs.f_type; + if (f_type == 0x6969 || // NFS_SUPER_MAGIC + f_type == 0xFF534D42 || // CIFS_SUPER_MAGIC + f_type == 0x517B || // SMB_SUPER_MAGIC + f_type == 0xFE534D42) // SMB2_SUPER_MAGIC { return 0; } From 2554fe2b78f9a7040bd4cfcc6d3daa1f287155c3 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Wed, 7 Jan 2026 20:14:36 +0100 Subject: [PATCH 6/8] Fix CI build errors. --- src/native/libs/System.Native/pal_io.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index bcfbe23264d462..7795a638ff58ea 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -1578,9 +1578,9 @@ static uint32_t FileSystemNameSupportsLocking(const char* fileSystemName) uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd) { // This method returns false when we identify the file system to be nfs (#44546), samba/cifs (#53182). -#if defined(TARGET_WASI) - return 0; // WASI doesn't support locking. -#elif HAVE_STATFS_FSTYPENAME || defined(TARGET_LINUX) +#if defined(TARGET_WASI) || defined(TARGET_WASM) + return 0; // WASI/WASM doesn't support locking. +#elif HAVE_STATFS_FSTYPENAME || defined(TARGET_LINUX) || defined(TARGET_ANDROID) int statfsRes; struct statfs statfsArgs; // for our needs (get file system type) statfs is always enough and there is no need to use statfs64 @@ -1590,7 +1590,7 @@ uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd) #if HAVE_STATFS_FSTYPENAME return FileSystemNameSupportsLocking(statfsArgs.f_fstypename); -#elif defined(TARGET_LINUX) +#elif defined(TARGET_LINUX) || defined(TARGET_ANDROID) unsigned int f_type = (unsigned int)statfsArgs.f_type; if (f_type == 0x6969 || // NFS_SUPER_MAGIC f_type == 0xFF534D42 || // CIFS_SUPER_MAGIC From 1b6f3ef7c380666773d3e65a35885d16db31fd8e Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Mon, 12 Jan 2026 05:23:24 +0100 Subject: [PATCH 7/8] Move the lockOperation and fileAccess check to pal. Add a descriptive comment. --- .../Interop.FileSystemSupportsLocking.cs | 2 +- .../Win32/SafeHandles/SafeFileHandle.Unix.cs | 10 +--------- src/native/libs/System.Native/pal_io.c | 14 +++++++++++--- src/native/libs/System.Native/pal_io.h | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.FileSystemSupportsLocking.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.FileSystemSupportsLocking.cs index 19f095e859418a..9ed81bb1835e11 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.FileSystemSupportsLocking.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.FileSystemSupportsLocking.cs @@ -10,6 +10,6 @@ internal static partial class Sys { [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_FileSystemSupportsLocking")] [return: MarshalAs(UnmanagedType.Bool)] - internal static partial bool FileSystemSupportsLocking(SafeFileHandle fd); + internal static partial bool FileSystemSupportsLocking(SafeFileHandle fd, LockOperations lockOperation, [MarshalAs(UnmanagedType.Bool)] bool accessWrite); } } 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 d0f8a4f5e862db..196ec738116e6a 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 @@ -462,16 +462,8 @@ private bool CanLockTheFile(Interop.Sys.LockOperations lockOperation, FileAccess { 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 - } - return Interop.Sys.FileSystemSupportsLocking(this); + return Interop.Sys.FileSystemSupportsLocking(this, lockOperation, accessWrite: (access & FileAccess.Write) != 0); } private void FStatCheckIO(string path, ref Interop.Sys.FileStatus status, ref bool statusHasValue) diff --git a/src/native/libs/System.Native/pal_io.c b/src/native/libs/System.Native/pal_io.c index 7795a638ff58ea..e39190b767bacb 100644 --- a/src/native/libs/System.Native/pal_io.c +++ b/src/native/libs/System.Native/pal_io.c @@ -1575,12 +1575,19 @@ static uint32_t FileSystemNameSupportsLocking(const char* fileSystemName) #endif #endif /* TARGET_WASI */ -uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd) +// LOCK_SH does not work well for write access on nfs/cifs/samba. For example, writes are dropped silently. +// See https://github.com/dotnet/runtime/issues/44546 and https://github.com/dotnet/runtime/issues/53182. +uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd, int32_t lockOperation, int32_t accessWrite) { - // This method returns false when we identify the file system to be nfs (#44546), samba/cifs (#53182). + assert(lockOperation == PAL_LOCK_SH || lockOperation == PAL_LOCK_EX); #if defined(TARGET_WASI) || defined(TARGET_WASM) return 0; // WASI/WASM doesn't support locking. -#elif HAVE_STATFS_FSTYPENAME || defined(TARGET_LINUX) || defined(TARGET_ANDROID) +#else + if (lockOperation == PAL_LOCK_EX || accessWrite == 0) + { + return 1; + } +#if HAVE_STATFS_FSTYPENAME || defined(TARGET_LINUX) || defined(TARGET_ANDROID) int statfsRes; struct statfs statfsArgs; // for our needs (get file system type) statfs is always enough and there is no need to use statfs64 @@ -1611,6 +1618,7 @@ uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd) #else #error "Platform doesn't support fstatfs or fstatvfs" #endif +#endif } int32_t SystemNative_LockFileRegion(intptr_t fd, int64_t offset, int64_t length, int16_t lockType) diff --git a/src/native/libs/System.Native/pal_io.h b/src/native/libs/System.Native/pal_io.h index 4072413f2cae42..58faa9c5a7c9d6 100644 --- a/src/native/libs/System.Native/pal_io.h +++ b/src/native/libs/System.Native/pal_io.h @@ -766,7 +766,7 @@ PALEXPORT int32_t SystemNative_GetPeerID(intptr_t socket, uid_t* euid); /** * Returns whether file system associated with the handle supports .NET compatible locking. */ -PALEXPORT uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd); +PALEXPORT uint32_t SystemNative_FileSystemSupportsLocking(intptr_t fd, int32_t lockOperation, int32_t accessWrite); /** * Attempts to lock/unlock the region of the file "fd" specified by the offset and length. lockType From e02e1b95fe02cbd510ce4ec4802dfdf85af5f010 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Thu, 22 Jan 2026 11:26:07 +0100 Subject: [PATCH 8/8] Update wasm callhelpers-pinvoke.cpp for SystemNative_FileSystemSupportsLocking. --- src/coreclr/vm/wasm/callhelpers-pinvoke.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/wasm/callhelpers-pinvoke.cpp b/src/coreclr/vm/wasm/callhelpers-pinvoke.cpp index 3396280a122505..50487f83a2a844 100644 --- a/src/coreclr/vm/wasm/callhelpers-pinvoke.cpp +++ b/src/coreclr/vm/wasm/callhelpers-pinvoke.cpp @@ -90,7 +90,7 @@ extern "C" { void * SystemNative_GetCwd (void *, int32_t); void * SystemNative_GetDefaultSearchOrderPseudoHandle (); int32_t SystemNative_GetErrNo (); - uint32_t SystemNative_GetFileSystemType (void *); + uint32_t SystemNative_FileSystemSupportsLocking (void *, int32_t, int32_t); int32_t SystemNative_GetIPv4Address (void *, int32_t, void *); int32_t SystemNative_GetIPv6Address (void *, int32_t, void *, int32_t, void *); void * SystemNative_GetLoadLibraryError (); @@ -238,7 +238,7 @@ static const Entry s_libSystem_Native [] = { DllImportEntry(SystemNative_GetCwd) // System.Private.CoreLib DllImportEntry(SystemNative_GetDefaultSearchOrderPseudoHandle) // System.Private.CoreLib DllImportEntry(SystemNative_GetErrNo) // System.Private.CoreLib - DllImportEntry(SystemNative_GetFileSystemType) // System.Private.CoreLib + DllImportEntry(SystemNative_FileSystemSupportsLocking) // System.Private.CoreLib DllImportEntry(SystemNative_GetIPv4Address) // System.Net.Primitives DllImportEntry(SystemNative_GetIPv6Address) // System.Net.Primitives DllImportEntry(SystemNative_GetLoadLibraryError) // System.Private.CoreLib