From 6c9c8344db89bfe6379c7480483e1d3195689821 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Thu, 29 May 2025 15:18:21 +0200 Subject: [PATCH 01/12] DriveInfo.Linux: use procfs mountinfo for formats and mount point paths. For the format, mountinfo includes a string 'filesystem type' field which is more granular than the statfs f_type numeric field. For example: the ext2, ext3 and ext4 are distinct mountinfo values which have the same same f_type value. For the mount paths, mountinfo provides the mount point paths relative to the process's root directory. When the process runs with changed root dir (chroot), the paths are adjusted for it. --- .../Interop/Linux/cgroups/Interop.cgroups.cs | 84 ++++------- .../Linux/procfs/Interop.ProcMountInfo.cs | 138 ++++++++++++++++++ .../Interop.MountPoints.FormatInfo.cs | 58 +++++--- .../Unix/System.Native/Interop.MountPoints.cs | 40 ++++- .../Common/tests/Common.Tests.csproj | 4 + .../Common/tests/Tests/Interop/procfsTests.cs | 22 +++ .../src/System.Diagnostics.Process.csproj | 2 + .../src/System.IO.FileSystem.DriveInfo.csproj | 2 + .../src/System/IO/DriveInfo.Unix.cs | 66 +++++---- .../System.Private.CoreLib.Shared.projitems | 2 + ...opServices.RuntimeInformation.Tests.csproj | 4 + src/native/libs/System.Native/entrypoints.c | 2 +- src/native/libs/System.Native/pal_mount.c | 35 ++--- src/native/libs/System.Native/pal_mount.h | 13 +- .../libs/System.Native/pal_mount_wasi.c | 5 +- 15 files changed, 332 insertions(+), 145 deletions(-) create mode 100644 src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs diff --git a/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs b/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs index 4d3d79f58f2e83..f8f874c3e7d5fb 100644 --- a/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs +++ b/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs @@ -26,8 +26,6 @@ internal enum CGroupVersion /// Path to cgroup filesystem that tells us which version of cgroup is in use. private const string SysFsCgroupFileSystemPath = "/sys/fs/cgroup"; - /// Path to mountinfo file in procfs for the current process. - private const string ProcMountInfoFilePath = "/proc/self/mountinfo"; /// Path to cgroup directory in procfs for the current process. private const string ProcCGroupFilePath = "/proc/self/cgroup"; @@ -209,13 +207,11 @@ internal static bool TryReadMemoryValueFromFile(string path, out ulong result) private static unsafe CGroupVersion FindCGroupVersion() { CGroupVersion cgroupVersion = CGroupVersion.None; - const int MountPointFormatBufferSizeInBytes = 32; - byte* formatBuffer = stackalloc byte[MountPointFormatBufferSizeInBytes]; // format names should be small - long numericFormat; - int result = Interop.Sys.GetFormatInfoForMountPoint(SysFsCgroupFileSystemPath, formatBuffer, MountPointFormatBufferSizeInBytes, &numericFormat); - if (result == 0) + Span buffer = stackalloc char[16]; + Interop.Error error = Interop.procfs.GetFileSystemTypeForMountPoint(SysFsCgroupFileSystemPath, buffer, out ReadOnlySpan fileSystemType); + if (error == Interop.Error.SUCCESS) { - if (numericFormat == (int)Interop.Sys.UnixFileSystemTypes.cgroup2fs) + if (fileSystemType.SequenceEqual("cgroup2")) { cgroupVersion = CGroupVersion.CGroup2; } @@ -304,7 +300,7 @@ internal static string FindCGroupPath(string hierarchyRoot, string hierarchyMoun /// true if the mount was found; otherwise, null. private static bool TryFindHierarchyMount(CGroupVersion cgroupVersion, string subsystem, [NotNullWhen(true)] out string? root, [NotNullWhen(true)] out string? path) { - return TryFindHierarchyMount(cgroupVersion, ProcMountInfoFilePath, subsystem, out root, out path); + return TryFindHierarchyMount(cgroupVersion, Interop.procfs.ProcMountInfoFilePath, subsystem, out root, out path); } /// Find the cgroup mount information for the specified subsystem. @@ -325,65 +321,41 @@ internal static bool TryFindHierarchyMount(CGroupVersion cgroupVersion, string m string? line; while ((line = reader.ReadLine()) != null) { - // Look for an entry that has cgroup as the "filesystem type" - // and, for cgroup1, that has options containing the specified subsystem - // See man page for /proc/[pid]/mountinfo for details, e.g.: - // (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) - // 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue - // but (7) is optional and could exist as multiple fields; the (8) separator marks - // the end of the optional values. - - const string Separator = " - "; - int endOfOptionalFields = line.IndexOf(Separator, StringComparison.Ordinal); - if (endOfOptionalFields == -1) + if (Interop.procfs.TryParseMountInfoLine(line, out Interop.procfs.ParsedMount mount)) { - // Malformed line. - continue; - } - - string postSeparatorLine = line.Substring(endOfOptionalFields + Separator.Length); - string[] postSeparatorlineParts = postSeparatorLine.Split(' '); - if (postSeparatorlineParts.Length < 3) - { - // Malformed line. - continue; - } - - if (cgroupVersion == CGroupVersion.CGroup1) - { - bool validCGroup1Entry = ((postSeparatorlineParts[0] == "cgroup") && - (Array.IndexOf(postSeparatorlineParts[2].Split(','), subsystem) >= 0)); - if (!validCGroup1Entry) + if (cgroupVersion == CGroupVersion.CGroup1) { - continue; + bool validCGroup1Entry = mount.FileSystemType.SequenceEqual("cgroup") && mount.SuperOptions.IndexOf(subsystem) >= 0; + if (!validCGroup1Entry) + { + continue; + } } - } - else if (cgroupVersion == CGroupVersion.CGroup2) - { - bool validCGroup2Entry = postSeparatorlineParts[0] == "cgroup2"; - if (!validCGroup2Entry) + else if (cgroupVersion == CGroupVersion.CGroup2) { - continue; - } - - } - else - { - Debug.Fail($"Unexpected cgroup version \"{cgroupVersion}\""); - } + bool validCGroup2Entry = mount.FileSystemType.SequenceEqual("cgroup2"); + if (!validCGroup2Entry) + { + continue; + } + } + else + { + Debug.Fail($"Unexpected cgroup version \"{cgroupVersion}\""); + } - string[] lineParts = line.Substring(0, endOfOptionalFields).Split(' '); - root = lineParts[3]; - path = lineParts[4]; + root = mount.Root.ToString(); + path = mount.MountPoint.ToString(); - return true; + return true; + } } } } catch (Exception e) { - Debug.Fail($"Failed to read or parse \"{ProcMountInfoFilePath}\": {e}"); + Debug.Fail($"Failed to read or parse \"{mountInfoFilePath}\": {e}"); } } diff --git a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs new file mode 100644 index 00000000000000..effeed4b60fc67 --- /dev/null +++ b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs @@ -0,0 +1,138 @@ +// 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.IO; + +internal static partial class Interop +{ + internal static partial class @procfs + { + internal const string ProcMountInfoFilePath = "/proc/self/mountinfo"; + + internal ref struct ParsedMount + { + public required ReadOnlySpan Root { get; init; } + public required ReadOnlySpan MountPoint { get; init; } + public required ReadOnlySpan FileSystemType { get; init; } + public required ReadOnlySpan SuperOptions { get; init; } + } + + internal static Error GetFileSystemTypeForMountPoint(string name, Span buffer, out ReadOnlySpan format) + { + format = default; + + if (File.Exists(ProcMountInfoFilePath)) + { + try + { + using StreamReader reader = new(ProcMountInfoFilePath); + + string? line; + while ((line = reader.ReadLine()) is not null) + { + if (TryParseMountInfoLine(line, out ParsedMount mount)) + { + if (mount.MountPoint.SequenceEqual(name)) + { + if (buffer.Length >= mount.FileSystemType.Length) + { + mount.FileSystemType.CopyTo(buffer); + format = buffer.Slice(0, mount.FileSystemType.Length); + } + else + { + format = mount.FileSystemType.ToString(); + } + return Error.SUCCESS; + } + } + } + + return Error.ENOENT; + } + catch (Exception e) + { + Debug.Fail($"Failed to read \"{ProcMountInfoFilePath}\": {e}"); + } + } + + return Error.ENOTSUP; + } + + internal static bool TryParseMountInfoLine(ReadOnlySpan line, out ParsedMount result) + { + result = default; + + // See man page for /proc/[pid]/mountinfo for details, e.g.: + // (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) + // 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue + // but (7) is optional and could exist as multiple fields; the (8) separator marks + // the end of the optional values. + + MemoryExtensions.SpanSplitEnumerator fields = line.Split(' '); + + // (1) mount ID + // (2) parent ID + // (3) major:minor + if (!fields.MoveNext() || !fields.MoveNext() || !fields.MoveNext()) + { + return false; + } + + // (4) root + if (!fields.MoveNext()) + { + return false; + } + ReadOnlySpan root = line[fields.Current]; + + // (5) mount point + if (!fields.MoveNext()) + { + return false; + } + ReadOnlySpan mountPoint = line[fields.Current]; + + // (8) separator + const string Separator = " - "; + int endOfOptionalFields = line.IndexOf(Separator, StringComparison.Ordinal); + if (endOfOptionalFields == -1) + { + return false; + } + line = line.Slice(endOfOptionalFields + Separator.Length); + fields = line.Split(' '); + + // (9) filesystem type + if (!fields.MoveNext()) + { + return false; + } + ReadOnlySpan fileSystemType = line[fields.Current]; + + // (10) mount source + if (!fields.MoveNext()) + { + return false; + } + + // (11) super options + if (!fields.MoveNext()) + { + return false; + } + ReadOnlySpan superOptions = line[fields.Current]; + + result = new ParsedMount() + { + Root = root, + MountPoint = mountPoint, + FileSystemType = fileSystemType, + SuperOptions = superOptions + }; + return true; + } + } +} 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 4cc682139c3a6c..9d5b288423c78f 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 @@ -33,49 +33,60 @@ internal struct MountPointInformation [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetSpaceInfoForMountPoint", SetLastError = true)] internal static partial int GetSpaceInfoForMountPoint([MarshalAs(UnmanagedType.LPUTF8Str)] string name, out MountPointInformation mpi); - [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetFormatInfoForMountPoint", SetLastError = true)] - internal static unsafe partial int GetFormatInfoForMountPoint( - [MarshalAs(UnmanagedType.LPUTF8Str)] string name, - byte* formatNameBuffer, - int bufferLength, - long* formatType); + internal static Error GetFileSystemTypeNameForMountPoint(string name, Span buffer, out ReadOnlySpan format) + { + if (OperatingSystem.IsLinux()) + { + return procfs.GetFileSystemTypeForMountPoint(name, buffer, out format); + } + else + { + return GetFileSystemTypeNameForMountPoint(name, out format); + } + } - internal static int GetFormatInfoForMountPoint(string name, out string format) + internal static Error GetFileSystemTypeNameForMountPoint(string name, out string format) { - return GetFormatInfoForMountPoint(name, out format, out _); + Span buffer = stackalloc char[16]; + Error error = GetFileSystemTypeNameForMountPoint(name, buffer, out ReadOnlySpan formatSpan); + format = error == Error.SUCCESS ? formatSpan.ToString() : ""; + return error; } - internal static int GetFormatInfoForMountPoint(string name, out DriveType type) + internal static Error GetDriveTypeForMountPoint(string name, out DriveType type) { - return GetFormatInfoForMountPoint(name, out _, out type); + Span buffer = stackalloc char[16]; + Error error = GetFileSystemTypeNameForMountPoint(name, buffer, out ReadOnlySpan format); + type = error == Error.SUCCESS ? GetDriveType(format) : DriveType.Unknown; + return error; } - private static unsafe int GetFormatInfoForMountPoint(string name, out string format, out DriveType type) + [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetFileSystemTypeNameForMountPoint", SetLastError = true)] + private static unsafe partial int GetFileSystemTypeNameForMountPoint( + [MarshalAs(UnmanagedType.LPUTF8Str)] string name, + byte* formatNameBuffer, + int bufferLength); + + private static unsafe Error GetFileSystemTypeNameForMountPoint(string name, out ReadOnlySpan format) { byte* formatBuffer = stackalloc byte[MountPointFormatBufferSizeInBytes]; // format names should be small - long numericFormat; - int result = GetFormatInfoForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes, &numericFormat); + int result = GetFileSystemTypeNameForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes); if (result == 0) { - // Check if we have a numeric answer or string - format = numericFormat != -1 ? - Enum.GetName(typeof(UnixFileSystemTypes), numericFormat) ?? string.Empty : - Marshal.PtrToStringUTF8((IntPtr)formatBuffer)!; - type = GetDriveType(format); + format = Marshal.PtrToStringUTF8((IntPtr)formatBuffer)!; + return Error.SUCCESS; } else { format = string.Empty; - type = DriveType.Unknown; + return GetLastError(); } - - return result; } /// Categorizes a file system name into a drive type. /// The name to categorize. /// The recognized drive type. - private static DriveType GetDriveType(string fileSystemName) + private static DriveType GetDriveType(ReadOnlySpan 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 @@ -261,8 +272,10 @@ private static DriveType GetDriveType(string fileSystemName) case "aptfs": case "avfs": case "bdev": + case "bpf": case "binfmt_misc": case "cgroup": + case "cgroup2": case "cgroupfs": case "cgroup2fs": case "configfs": @@ -280,6 +293,7 @@ private static DriveType GetDriveType(string fileSystemName) case "fd": case "fdesc": case "fuse.gvfsd-fuse": + case "fuse.portal": case "fusectl": case "futexfs": case "hugetlbfs": diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs index 3ac98d62f743cc..055c8d5e9f259a 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; @@ -36,17 +37,42 @@ private static unsafe void AddMountPoint(void* context, byte* name) internal static string[] GetAllMountPoints() { - AllMountPointsContext context = default; - context._results = new List(); - - unsafe + if (OperatingSystem.IsLinux()) { - GetAllMountPoints(&AddMountPoint, &context); + if (File.Exists(Interop.procfs.ProcMountInfoFilePath)) + { + List mountPoints = new(); + + using StreamReader reader = new(Interop.procfs.ProcMountInfoFilePath); + + string? line; + while ((line = reader.ReadLine()) is not null) + { + if (Interop.procfs.TryParseMountInfoLine(line, out Interop.procfs.ParsedMount mount)) + { + mountPoints.Add(mount.MountPoint.ToString()); + } + } + + return mountPoints.ToArray(); + } + + return Array.Empty(); } + else + { + AllMountPointsContext context = default; + context._results = new List(); - context._exception?.Throw(); + unsafe + { + GetAllMountPoints(&AddMountPoint, &context); + } - return context._results.ToArray(); + context._exception?.Throw(); + + return context._results.ToArray(); + } } } } diff --git a/src/libraries/Common/tests/Common.Tests.csproj b/src/libraries/Common/tests/Common.Tests.csproj index 453f93145e7178..a6d3a6ade032ab 100644 --- a/src/libraries/Common/tests/Common.Tests.csproj +++ b/src/libraries/Common/tests/Common.Tests.csproj @@ -145,6 +145,10 @@ + + diff --git a/src/libraries/Common/tests/Tests/Interop/procfsTests.cs b/src/libraries/Common/tests/Tests/Interop/procfsTests.cs index c0c2d1431dc27c..707a9f7954491a 100644 --- a/src/libraries/Common/tests/Tests/Interop/procfsTests.cs +++ b/src/libraries/Common/tests/Tests/Interop/procfsTests.cs @@ -57,5 +57,27 @@ public void ParseValidStatFiles_Success( Assert.Equal(expectedRss, result.rss); Assert.Equal(expectedRsslim, result.rsslim); } + + [Theory] + [InlineData("37 79 0:6 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=4096k,nr_inodes=4070495,mode=755,inode64", "/", "/dev", "devtmpfs", "rw,seclabel,size=4096k,nr_inodes=4070495,mode=755,inode64")] + [InlineData("42 40 0:28 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:7 - cgroup2 cgroup2 rw,seclabel,nsdelegate,memory_recursiveprot", "/", "/sys/fs/cgroup", "cgroup2", "rw,seclabel,nsdelegate,memory_recursiveprot")] + [InlineData("34 28 0:28 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,cpu,cpuacct", "/", "/sys/fs/cgroup/cpu,cpuacct", "cgroup", "rw,cpu,cpuacct")] + [InlineData("396 394 0:21 /kubepods/besteffort/pod9a18ffb8-8513-11e7-b26e-7e29fbe2a5a3/d28e0087cf8f3f0429f755d60b0de415b20fcf76736ded7bab6e30e7b739ee36 /sys/fs/cgroup/cpu ro,nosuid,nodev,noexec,relatime - cgroup cgroup rw,cpu", "/kubepods/besteffort/pod9a18ffb8-8513-11e7-b26e-7e29fbe2a5a3/d28e0087cf8f3f0429f755d60b0de415b20fcf76736ded7bab6e30e7b739ee36", "/sys/fs/cgroup/cpu", "cgroup", "rw,cpu")] + [InlineData("55 79 259:2 / /boot rw,relatime shared:111 - ext4 /dev/nvme0n1p2 rw,seclabel", "/", "/boot", "ext4", "rw,seclabel")] + public void ParseMountInfoLine_Success( + string line, + string expectedRoot, + string expectedMountPoint, + string expectedFileSystemType, + string expectedSuperOptions) + { + Interop.procfs.ParsedMount result; + Assert.True(Interop.procfs.TryParseMountInfoLine(line, out result)); + + Assert.Equal(expectedRoot, result.Root); + Assert.Equal(expectedMountPoint, result.MountPoint); + Assert.Equal(expectedFileSystemType, result.FileSystemType); + Assert.Equal(expectedSuperOptions, result.SuperOptions); + } } } 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 97e289045e324a..c7246481120413 100644 --- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj +++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj @@ -307,6 +307,8 @@ Link="Common\Interop\Linux\Interop.cgroups.cs" /> + + diff --git a/src/libraries/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Unix.cs b/src/libraries/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Unix.cs index dc42bde044b0c6..c7696a875ded1a 100644 --- a/src/libraries/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Unix.cs +++ b/src/libraries/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Unix.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; using System.Security; namespace System.IO @@ -14,27 +15,22 @@ public DriveType DriveType get { DriveType type; - int result = Interop.Sys.GetFormatInfoForMountPoint(Name, out type); - if (result == 0) - { - return type; - } - else + Interop.Error error = Interop.Sys.GetDriveTypeForMountPoint(Name, out type); + + // This is one of the few properties that doesn't throw on failure, + // instead returning a value from the enum. + switch (error) { - Interop.ErrorInfo errorInfo = Interop.Sys.GetLastErrorInfo(); + case Interop.Error.SUCCESS: + return type; - // This is one of the few properties that doesn't throw on failure, - // instead returning a value from the enum. - switch (errorInfo.Error) - { - case Interop.Error.ELOOP: - case Interop.Error.ENAMETOOLONG: - case Interop.Error.ENOENT: - case Interop.Error.ENOTDIR: - return DriveType.NoRootDirectory; - default: - return DriveType.Unknown; - } + case Interop.Error.ELOOP: + case Interop.Error.ENAMETOOLONG: + case Interop.Error.ENOENT: + case Interop.Error.ENOTDIR: + return DriveType.NoRootDirectory; + default: + return DriveType.Unknown; } } } @@ -44,7 +40,7 @@ public string DriveFormat get { string format; - CheckStatfsResultAndThrowIfNecessary(Interop.Sys.GetFormatInfoForMountPoint(Name, out format)); + CheckStatfsResultAndThrowIfNecessary(Interop.Sys.GetFileSystemTypeNameForMountPoint(Name, out format)); return format; } } @@ -79,19 +75,31 @@ public long TotalSize } } + private void CheckStatfsResultAndThrowIfNecessary(Interop.Error error) + { + if (error != Interop.Error.SUCCESS) + { + ThrowForError(error); + } + } + private void CheckStatfsResultAndThrowIfNecessary(int result) { if (result != 0) { - var errorInfo = Interop.Sys.GetLastErrorInfo(); - if (errorInfo.Error == Interop.Error.ENOENT) - { - throw new DriveNotFoundException(SR.Format(SR.IO_DriveNotFound_Drive, Name)); // match Win32 - } - else - { - throw Interop.GetExceptionForIoErrno(errorInfo); - } + ThrowForError(Interop.Sys.GetLastError()); + } + } + + private void ThrowForError(Interop.Error error) + { + if (error == Interop.Error.ENOENT) + { + throw new DriveNotFoundException(SR.Format(SR.IO_DriveNotFound_Drive, Name)); // match Win32 + } + else + { + throw Interop.GetExceptionForIoErrno(error.Info()); } } 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 cea0562929595a..532dd705ece514 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 @@ -2452,6 +2452,8 @@ Common\Interop\Unix\System.Native\Interop.MountPoints.cs + Common\Interop\Unix\System.Native\Interop.Open.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 94daeb2079a355..3a4f9c6bf01162 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 @@ -17,6 +17,10 @@ Link="Interop\Linux\os-release\Interop.OSReleaseFile.cs" /> + + 0); -#if HAVE_NON_LEGACY_STATFS +#if HAVE_STATFS_FSTYPENAME struct statfs stats; int result = statfs(name, &stats); -#else +#elif HAVE_STATVFS_FSTYPENAME struct statvfs stats; int result = statvfs(name, &stats); +#else + (void)name; // unused + (void)formatNameBuffer; // unused + (void)bufferLength; // unused + int result = -1; + errno = ENOTSUP; #endif - if (result == 0) - { #if HAVE_STATFS_FSTYPENAME || HAVE_STATVFS_FSTYPENAME + if (result == 0) + { #ifdef VFS_NAMELEN if (bufferLength < VFS_NAMELEN) #else if (bufferLength < MFSNAMELEN) #endif { - result = ERANGE; - *formatType = 0; + errno = ERANGE; + result = -1; } else { SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), stats.f_fstypename); - *formatType = -1; } -#elif HAVE_NON_LEGACY_STATFS - assert(formatType != NULL); - *formatType = (int64_t)(stats.f_type); - SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), ""); -#else - *formatType = 0; -#endif - } - else - { - *formatType = 0; } +#endif return result; } diff --git a/src/native/libs/System.Native/pal_mount.h b/src/native/libs/System.Native/pal_mount.h index 3afef9b3ca0662..6901e42b8c7f49 100644 --- a/src/native/libs/System.Native/pal_mount.h +++ b/src/native/libs/System.Native/pal_mount.h @@ -29,16 +29,11 @@ typedef void (*MountPointFound)(void* context, const char* name); PALEXPORT int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInformation* mpi); /** - * Gets the format information about the given mount point. - * We separate format info from space info because format information is given back differently per-platform - * so keep the space information simple (above) and do all the platform logic here. - * Ubuntu (and most Linux systems) will provide the mount point format as a long int in statfs while - * OS X and BSD-like systems will provide the information in a char buffer. - * Since C# is much better at enum and string handling, pass either the char buffer or the long type - * back, depending on what the platform gives us, and let C# reason on it in an easy way. + * Gets the file system type name for the given mount point. + * Returns -1 (ENOTSUP) when stat(v)fs does not provide a string representation of the file system type. */ -PALEXPORT int32_t SystemNative_GetFormatInfoForMountPoint( - const char* name, char* formatNameBuffer, int32_t bufferLength, int64_t* formatType); +PALEXPORT int32_t SystemNative_GetFileSystemTypeNameForMountPoint( + const char* name, char* formatNameBuffer, int32_t bufferLength); /** * Enumerate all mount points on the system and call the input diff --git a/src/native/libs/System.Native/pal_mount_wasi.c b/src/native/libs/System.Native/pal_mount_wasi.c index 61b776160eace6..8dbf45c1325e6d 100644 --- a/src/native/libs/System.Native/pal_mount_wasi.c +++ b/src/native/libs/System.Native/pal_mount_wasi.c @@ -11,6 +11,7 @@ int32_t SystemNative_GetAllMountPoints(MountPointFound onFound, void* context) { + errno = ENOTSUP; return -1; } @@ -18,13 +19,15 @@ int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInfor { assert(name != NULL); assert(mpi != NULL); + errno = ENOTSUP; return -1; } int32_t -SystemNative_GetFormatInfoForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength, int64_t* formatType) +SystemNative_GetFileSystemTypeNameForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength) { assert((formatNameBuffer != NULL) && (formatType != NULL)); assert(bufferLength > 0); + errno = ENOTSUP; return -1; } From 9c7b7905e8262877dfa3484d7554205a7c8ae3d1 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Thu, 29 May 2025 22:48:40 +0200 Subject: [PATCH 02/12] Remove stackalloced buffer. --- .../Interop/Linux/cgroups/Interop.cgroups.cs | 5 ++--- .../Linux/procfs/Interop.ProcMountInfo.cs | 14 +++----------- .../Interop.MountPoints.FormatInfo.cs | 17 ++++------------- 3 files changed, 9 insertions(+), 27 deletions(-) diff --git a/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs b/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs index f8f874c3e7d5fb..05842d139fdfd5 100644 --- a/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs +++ b/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs @@ -207,11 +207,10 @@ internal static bool TryReadMemoryValueFromFile(string path, out ulong result) private static unsafe CGroupVersion FindCGroupVersion() { CGroupVersion cgroupVersion = CGroupVersion.None; - Span buffer = stackalloc char[16]; - Interop.Error error = Interop.procfs.GetFileSystemTypeForMountPoint(SysFsCgroupFileSystemPath, buffer, out ReadOnlySpan fileSystemType); + Interop.Error error = Interop.procfs.GetFileSystemTypeForMountPoint(SysFsCgroupFileSystemPath, out string format); if (error == Interop.Error.SUCCESS) { - if (fileSystemType.SequenceEqual("cgroup2")) + if (format == "cgroup2") { cgroupVersion = CGroupVersion.CGroup2; } diff --git a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs index effeed4b60fc67..f358f679dc5cb0 100644 --- a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs +++ b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs @@ -19,9 +19,9 @@ internal ref struct ParsedMount public required ReadOnlySpan SuperOptions { get; init; } } - internal static Error GetFileSystemTypeForMountPoint(string name, Span buffer, out ReadOnlySpan format) + internal static Error GetFileSystemTypeForMountPoint(string name, out string format) { - format = default; + format = ""; if (File.Exists(ProcMountInfoFilePath)) { @@ -36,15 +36,7 @@ internal static Error GetFileSystemTypeForMountPoint(string name, Span buf { if (mount.MountPoint.SequenceEqual(name)) { - if (buffer.Length >= mount.FileSystemType.Length) - { - mount.FileSystemType.CopyTo(buffer); - format = buffer.Slice(0, mount.FileSystemType.Length); - } - else - { - format = mount.FileSystemType.ToString(); - } + format = mount.FileSystemType.ToString(); return Error.SUCCESS; } } 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 9d5b288423c78f..9ae1fb7db93f5b 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 @@ -33,11 +33,11 @@ internal struct MountPointInformation [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetSpaceInfoForMountPoint", SetLastError = true)] internal static partial int GetSpaceInfoForMountPoint([MarshalAs(UnmanagedType.LPUTF8Str)] string name, out MountPointInformation mpi); - internal static Error GetFileSystemTypeNameForMountPoint(string name, Span buffer, out ReadOnlySpan format) + internal static Error GetFileSystemTypeNameForMountPoint(string name, out string format) { if (OperatingSystem.IsLinux()) { - return procfs.GetFileSystemTypeForMountPoint(name, buffer, out format); + return procfs.GetFileSystemTypeForMountPoint(name, out format); } else { @@ -45,18 +45,9 @@ internal static Error GetFileSystemTypeNameForMountPoint(string name, Span } } - internal static Error GetFileSystemTypeNameForMountPoint(string name, out string format) - { - Span buffer = stackalloc char[16]; - Error error = GetFileSystemTypeNameForMountPoint(name, buffer, out ReadOnlySpan formatSpan); - format = error == Error.SUCCESS ? formatSpan.ToString() : ""; - return error; - } - internal static Error GetDriveTypeForMountPoint(string name, out DriveType type) { - Span buffer = stackalloc char[16]; - Error error = GetFileSystemTypeNameForMountPoint(name, buffer, out ReadOnlySpan format); + Error error = GetFileSystemTypeNameForMountPoint(name, out string format); type = error == Error.SUCCESS ? GetDriveType(format) : DriveType.Unknown; return error; } @@ -86,7 +77,7 @@ private static unsafe Error GetFileSystemTypeNameForMountPoint(string name, out /// Categorizes a file system name into a drive type. /// The name to categorize. /// The recognized drive type. - private static DriveType GetDriveType(ReadOnlySpan fileSystemName) + 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 From 7f679e048c5c95685ea36be06e5f65321e7f86a7 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Thu, 29 May 2025 23:57:31 +0200 Subject: [PATCH 03/12] Resolve symbolic links. --- .../Interop/Linux/cgroups/Interop.cgroups.cs | 2 +- .../Linux/procfs/Interop.ProcMountInfo.cs | 34 ++++++++++++++++--- .../Interop.MountPoints.FormatInfo.cs | 10 +++++- .../Common/tests/Common.Tests.csproj | 2 ++ .../src/System.Diagnostics.Process.csproj | 2 ++ .../src/System.IO.FileSystem.DriveInfo.csproj | 2 ++ ...opServices.RuntimeInformation.Tests.csproj | 2 ++ 7 files changed, 48 insertions(+), 6 deletions(-) diff --git a/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs b/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs index 05842d139fdfd5..973d4c63573e70 100644 --- a/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs +++ b/src/libraries/Common/src/Interop/Linux/cgroups/Interop.cgroups.cs @@ -207,7 +207,7 @@ internal static bool TryReadMemoryValueFromFile(string path, out ulong result) private static unsafe CGroupVersion FindCGroupVersion() { CGroupVersion cgroupVersion = CGroupVersion.None; - Interop.Error error = Interop.procfs.GetFileSystemTypeForMountPoint(SysFsCgroupFileSystemPath, out string format); + Interop.Error error = Interop.procfs.GetFileSystemTypeForRealPath(SysFsCgroupFileSystemPath, out string format); if (error == Interop.Error.SUCCESS) { if (format == "cgroup2") diff --git a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs index f358f679dc5cb0..a7e40ccdbdf2ab 100644 --- a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs +++ b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs @@ -19,7 +19,7 @@ internal ref struct ParsedMount public required ReadOnlySpan SuperOptions { get; init; } } - internal static Error GetFileSystemTypeForMountPoint(string name, out string format) + internal static Error GetFileSystemTypeForRealPath(string path, out string format) { format = ""; @@ -27,6 +27,9 @@ internal static Error GetFileSystemTypeForMountPoint(string name, out string for { try { + ReadOnlySpan currentFormat = default; + int currentBestLength = 0; + using StreamReader reader = new(ProcMountInfoFilePath); string? line; @@ -34,14 +37,37 @@ internal static Error GetFileSystemTypeForMountPoint(string name, out string for { if (TryParseMountInfoLine(line, out ParsedMount mount)) { - if (mount.MountPoint.SequenceEqual(name)) + if (mount.MountPoint.Length < currentBestLength) + { + continue; + } + + if (!path.StartsWith(mount.MountPoint)) + { + continue; + } + + if (mount.MountPoint.Length == path.Length) { - format = mount.FileSystemType.ToString(); - return Error.SUCCESS; + currentFormat = mount.FileSystemType; + break; } + + if (path[mount.MountPoint.Length] != '/') + { + continue; + } + + currentBestLength = mount.MountPoint.Length; + currentFormat = mount.FileSystemType; } } + if (currentFormat.Length > 0) + { + format = currentFormat.ToString(); + return Error.SUCCESS; + } return Error.ENOENT; } catch (Exception e) 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 9ae1fb7db93f5b..b9b10ff2875401 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 @@ -37,7 +37,15 @@ internal static Error GetFileSystemTypeNameForMountPoint(string name, out string { if (OperatingSystem.IsLinux()) { - return procfs.GetFileSystemTypeForMountPoint(name, out format); + // Resolve symbolic links. + string? path = Sys.RealPath(name); + if (path is null) + { + format = ""; + return GetLastError(); + } + + return procfs.GetFileSystemTypeForRealPath(path, out format); } else { diff --git a/src/libraries/Common/tests/Common.Tests.csproj b/src/libraries/Common/tests/Common.Tests.csproj index a6d3a6ade032ab..3dd291eaaedacb 100644 --- a/src/libraries/Common/tests/Common.Tests.csproj +++ b/src/libraries/Common/tests/Common.Tests.csproj @@ -130,6 +130,8 @@ Link="Common\Interop\Unix\Interop.PathConf.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 3a4f9c6bf01162..02de31f9605c8a 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 @@ -25,6 +25,8 @@ Link="Common\Interop\Unix\Interop.Libraries.cs" /> + From 83995f0a543d79829e814d7b906483395a019410 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Fri, 30 May 2025 08:12:13 +0200 Subject: [PATCH 04/12] Fix Common.Tests build on non-Linux. --- ...rop.ProcMountInfo.TryParseMountInfoLine.cs | 92 +++++++++++++++++++ .../Linux/procfs/Interop.ProcMountInfo.cs | 82 ----------------- .../Interop.MountPoints.FormatInfo.cs | 2 +- .../Common/tests/Common.Tests.csproj | 10 +- .../src/System.Diagnostics.Process.csproj | 2 + .../src/System.IO.FileSystem.DriveInfo.csproj | 2 + .../System.Private.CoreLib.Shared.projitems | 2 + ...opServices.RuntimeInformation.Tests.csproj | 2 + 8 files changed, 107 insertions(+), 87 deletions(-) create mode 100644 src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.TryParseMountInfoLine.cs diff --git a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.TryParseMountInfoLine.cs b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.TryParseMountInfoLine.cs new file mode 100644 index 00000000000000..dc89ddb285e78a --- /dev/null +++ b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.TryParseMountInfoLine.cs @@ -0,0 +1,92 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +internal static partial class Interop +{ + internal static partial class @procfs + { + internal ref struct ParsedMount + { + public required ReadOnlySpan Root { get; init; } + public required ReadOnlySpan MountPoint { get; init; } + public required ReadOnlySpan FileSystemType { get; init; } + public required ReadOnlySpan SuperOptions { get; init; } + } + + internal static bool TryParseMountInfoLine(ReadOnlySpan line, out ParsedMount result) + { + result = default; + + // See man page for /proc/[pid]/mountinfo for details, e.g.: + // (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) + // 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue + // but (7) is optional and could exist as multiple fields; the (8) separator marks + // the end of the optional values. + + MemoryExtensions.SpanSplitEnumerator fields = line.Split(' '); + + // (1) mount ID + // (2) parent ID + // (3) major:minor + if (!fields.MoveNext() || !fields.MoveNext() || !fields.MoveNext()) + { + return false; + } + + // (4) root + if (!fields.MoveNext()) + { + return false; + } + ReadOnlySpan root = line[fields.Current]; + + // (5) mount point + if (!fields.MoveNext()) + { + return false; + } + ReadOnlySpan mountPoint = line[fields.Current]; + + // (8) separator + const string Separator = " - "; + int endOfOptionalFields = line.IndexOf(Separator, StringComparison.Ordinal); + if (endOfOptionalFields == -1) + { + return false; + } + line = line.Slice(endOfOptionalFields + Separator.Length); + fields = line.Split(' '); + + // (9) filesystem type + if (!fields.MoveNext()) + { + return false; + } + ReadOnlySpan fileSystemType = line[fields.Current]; + + // (10) mount source + if (!fields.MoveNext()) + { + return false; + } + + // (11) super options + if (!fields.MoveNext()) + { + return false; + } + ReadOnlySpan superOptions = line[fields.Current]; + + result = new ParsedMount() + { + Root = root, + MountPoint = mountPoint, + FileSystemType = fileSystemType, + SuperOptions = superOptions + }; + return true; + } + } +} diff --git a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs index a7e40ccdbdf2ab..185f418bd5cbbc 100644 --- a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs +++ b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs @@ -11,14 +11,6 @@ internal static partial class @procfs { internal const string ProcMountInfoFilePath = "/proc/self/mountinfo"; - internal ref struct ParsedMount - { - public required ReadOnlySpan Root { get; init; } - public required ReadOnlySpan MountPoint { get; init; } - public required ReadOnlySpan FileSystemType { get; init; } - public required ReadOnlySpan SuperOptions { get; init; } - } - internal static Error GetFileSystemTypeForRealPath(string path, out string format) { format = ""; @@ -78,79 +70,5 @@ internal static Error GetFileSystemTypeForRealPath(string path, out string forma return Error.ENOTSUP; } - - internal static bool TryParseMountInfoLine(ReadOnlySpan line, out ParsedMount result) - { - result = default; - - // See man page for /proc/[pid]/mountinfo for details, e.g.: - // (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) - // 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue - // but (7) is optional and could exist as multiple fields; the (8) separator marks - // the end of the optional values. - - MemoryExtensions.SpanSplitEnumerator fields = line.Split(' '); - - // (1) mount ID - // (2) parent ID - // (3) major:minor - if (!fields.MoveNext() || !fields.MoveNext() || !fields.MoveNext()) - { - return false; - } - - // (4) root - if (!fields.MoveNext()) - { - return false; - } - ReadOnlySpan root = line[fields.Current]; - - // (5) mount point - if (!fields.MoveNext()) - { - return false; - } - ReadOnlySpan mountPoint = line[fields.Current]; - - // (8) separator - const string Separator = " - "; - int endOfOptionalFields = line.IndexOf(Separator, StringComparison.Ordinal); - if (endOfOptionalFields == -1) - { - return false; - } - line = line.Slice(endOfOptionalFields + Separator.Length); - fields = line.Split(' '); - - // (9) filesystem type - if (!fields.MoveNext()) - { - return false; - } - ReadOnlySpan fileSystemType = line[fields.Current]; - - // (10) mount source - if (!fields.MoveNext()) - { - return false; - } - - // (11) super options - if (!fields.MoveNext()) - { - return false; - } - ReadOnlySpan superOptions = line[fields.Current]; - - result = new ParsedMount() - { - Root = root, - MountPoint = mountPoint, - FileSystemType = fileSystemType, - SuperOptions = superOptions - }; - return true; - } } } 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 b9b10ff2875401..5c3f79a186f18c 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 @@ -37,7 +37,7 @@ internal static Error GetFileSystemTypeNameForMountPoint(string name, out string { if (OperatingSystem.IsLinux()) { - // Resolve symbolic links. + // Canonicalize and resolve symbolic links. string? path = Sys.RealPath(name); if (path is null) { diff --git a/src/libraries/Common/tests/Common.Tests.csproj b/src/libraries/Common/tests/Common.Tests.csproj index 3dd291eaaedacb..dab6d98a4ebd7d 100644 --- a/src/libraries/Common/tests/Common.Tests.csproj +++ b/src/libraries/Common/tests/Common.Tests.csproj @@ -15,6 +15,8 @@ Link="Common\Interop\Linux\Interop.ProcFsStat.TryReadStatusFile.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 d22accd6c394c6..ba226f7bc0da27 100644 --- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj +++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj @@ -311,6 +311,8 @@ Link="Common\Interop\Unix\Interop.RealPath.cs" /> + + 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 532dd705ece514..3d9b4a5366e20d 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 @@ -2454,6 +2454,8 @@ + Common\Interop\Unix\System.Native\Interop.Open.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 02de31f9605c8a..df9f5e30f4d780 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 @@ -19,6 +19,8 @@ Link="Common\Interop\Linux\Interop.cgroups.cs" /> + Date: Fri, 30 May 2025 12:22:43 +0200 Subject: [PATCH 05/12] Add test that gets the DriveFormat for /tmp. --- .../tests/DriveInfo.Unix.Tests.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs b/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs index cdcf872c365b5d..e99a4378eb37f6 100644 --- a/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs +++ b/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs @@ -94,5 +94,21 @@ public void SetVolumeLabel_Throws_PlatformNotSupportedException() var root = new DriveInfo("/"); Assert.Throws(() => root.VolumeLabel = root.Name); } + + [Theory] + [PlatformSpecific(TestPlatforms.AnyUnix)] + [InlineData(false)] + [InlineData(true)] + public void CanGetTempPathDriveFormat(bool trimSeparator) + { + string path = Path.GetTempPath(); + if (trimSeparator) + { + path = path.TrimEnd('/'); + } + var driveInfo = new DriveInfo(path); + + string format = driveInfo.DriveFormat; + } } } From 72dff4826fbb222b49ab5dc79ff212fbf2ab5574 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Fri, 30 May 2025 13:36:58 +0200 Subject: [PATCH 06/12] Use test to debug CI failure. --- .../tests/DriveInfo.Unix.Tests.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs b/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs index e99a4378eb37f6..3f578a5ef162ba 100644 --- a/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs +++ b/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs @@ -108,7 +108,14 @@ public void CanGetTempPathDriveFormat(bool trimSeparator) } var driveInfo = new DriveInfo(path); - string format = driveInfo.DriveFormat; + try + { + string format = driveInfo.DriveFormat; + } + catch (Exception ex) when (PlatformDetection.IsLinux) + { + throw new Exception($"Failed to find {path} in \n{File.ReadAllText("/proc/self/mountinfo")}", ex); + } } } } From d86e0af4e6b05b60acde4ef40f0edbb992587534 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Fri, 30 May 2025 14:33:53 +0200 Subject: [PATCH 07/12] Fix check for root mount path. --- .../Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs index 185f418bd5cbbc..de68fe04013a03 100644 --- a/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs +++ b/src/libraries/Common/src/Interop/Linux/procfs/Interop.ProcMountInfo.cs @@ -45,7 +45,7 @@ internal static Error GetFileSystemTypeForRealPath(string path, out string forma break; } - if (path[mount.MountPoint.Length] != '/') + if (mount.MountPoint.Length > 1 && path[mount.MountPoint.Length] != '/') { continue; } From a8cc5cb27f16f6ce458bcafe712c72894cbc13b5 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Fri, 30 May 2025 14:50:17 +0200 Subject: [PATCH 08/12] pal_mount: use buffer length based on API used. --- src/native/libs/System.Native/pal_mount.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/native/libs/System.Native/pal_mount.c b/src/native/libs/System.Native/pal_mount.c index 1ed68592c0d4f7..b61e62bc87239d 100644 --- a/src/native/libs/System.Native/pal_mount.c +++ b/src/native/libs/System.Native/pal_mount.c @@ -154,10 +154,10 @@ SystemNative_GetFileSystemTypeNameForMountPoint(const char* name, char* formatNa #if HAVE_STATFS_FSTYPENAME || HAVE_STATVFS_FSTYPENAME if (result == 0) { -#ifdef VFS_NAMELEN - if (bufferLength < VFS_NAMELEN) -#else +#ifdef HAVE_STATFS_FSTYPENAME if (bufferLength < MFSNAMELEN) +#elif HAVE_STATVFS_FSTYPENAME + if (bufferLength < VFS_NAMELEN) #endif { errno = ERANGE; From 7c7ebb23e67a1a5600c6b58ef39f6e3988951dc7 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Fri, 30 May 2025 16:31:51 +0200 Subject: [PATCH 09/12] Fix not calling native GetFileSystemTypeNameForMountPoint on non-Linux. --- .../Interop.MountPoints.FormatInfo.cs | 31 ++++++++----------- .../tests/DriveInfo.Unix.Tests.cs | 24 ++++---------- src/native/libs/System.Native/pal_mount.c | 4 +-- 3 files changed, 21 insertions(+), 38 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 5c3f79a186f18c..8a542ab2b5230a 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 @@ -33,7 +33,7 @@ internal struct MountPointInformation [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetSpaceInfoForMountPoint", SetLastError = true)] internal static partial int GetSpaceInfoForMountPoint([MarshalAs(UnmanagedType.LPUTF8Str)] string name, out MountPointInformation mpi); - internal static Error GetFileSystemTypeNameForMountPoint(string name, out string format) + internal static unsafe Error GetFileSystemTypeNameForMountPoint(string name, out string format) { if (OperatingSystem.IsLinux()) { @@ -49,7 +49,18 @@ internal static Error GetFileSystemTypeNameForMountPoint(string name, out string } else { - return GetFileSystemTypeNameForMountPoint(name, out format); + byte* formatBuffer = stackalloc byte[MountPointFormatBufferSizeInBytes]; // format names should be small + int result = GetFileSystemTypeNameForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes); + if (result == 0) + { + format = Marshal.PtrToStringUTF8((IntPtr)formatBuffer)!; + return Error.SUCCESS; + } + else + { + format = string.Empty; + return GetLastError(); + } } } @@ -66,22 +77,6 @@ private static unsafe partial int GetFileSystemTypeNameForMountPoint( byte* formatNameBuffer, int bufferLength); - private static unsafe Error GetFileSystemTypeNameForMountPoint(string name, out ReadOnlySpan format) - { - byte* formatBuffer = stackalloc byte[MountPointFormatBufferSizeInBytes]; // format names should be small - int result = GetFileSystemTypeNameForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes); - if (result == 0) - { - format = Marshal.PtrToStringUTF8((IntPtr)formatBuffer)!; - return Error.SUCCESS; - } - else - { - format = string.Empty; - return GetLastError(); - } - } - /// Categorizes a file system name into a drive type. /// The name to categorize. /// The recognized drive type. diff --git a/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs b/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs index 3f578a5ef162ba..d9c4fa7ef7d4bd 100644 --- a/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs +++ b/src/libraries/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs @@ -95,27 +95,15 @@ public void SetVolumeLabel_Throws_PlatformNotSupportedException() Assert.Throws(() => root.VolumeLabel = root.Name); } - [Theory] + [Fact] [PlatformSpecific(TestPlatforms.AnyUnix)] - [InlineData(false)] - [InlineData(true)] - public void CanGetTempPathDriveFormat(bool trimSeparator) + public void CanGetTempPathDriveFormat() { - string path = Path.GetTempPath(); - if (trimSeparator) - { - path = path.TrimEnd('/'); - } - var driveInfo = new DriveInfo(path); + var driveInfo = new DriveInfo(Path.GetTempPath()); - try - { - string format = driveInfo.DriveFormat; - } - catch (Exception ex) when (PlatformDetection.IsLinux) - { - throw new Exception($"Failed to find {path} in \n{File.ReadAllText("/proc/self/mountinfo")}", ex); - } + string format = driveInfo.DriveFormat; + Assert.NotNull(driveInfo.DriveFormat); + Assert.NotEmpty(driveInfo.DriveFormat); } } } diff --git a/src/native/libs/System.Native/pal_mount.c b/src/native/libs/System.Native/pal_mount.c index b61e62bc87239d..2c7dbfe658d026 100644 --- a/src/native/libs/System.Native/pal_mount.c +++ b/src/native/libs/System.Native/pal_mount.c @@ -155,9 +155,9 @@ SystemNative_GetFileSystemTypeNameForMountPoint(const char* name, char* formatNa if (result == 0) { #ifdef HAVE_STATFS_FSTYPENAME - if (bufferLength < MFSNAMELEN) + if (bufferLength < (MFSNAMELEN + 1)) // MFSNAMELEN does not include the null byte #elif HAVE_STATVFS_FSTYPENAME - if (bufferLength < VFS_NAMELEN) + if (bufferLength < VFS_NAMELEN) // VFS_NAMELEN includes the null byte #endif { errno = ERANGE; From a18f0974a2aa659f3b6373d0b39a099a5fc8da36 Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Mon, 2 Jun 2025 14:09:43 +0200 Subject: [PATCH 10/12] Add back using 'f_type' when 'f_fstypename' is not available. --- .../Interop.MountPoints.FormatInfo.cs | 35 +++++++++++-------- .../Unix/System.Native/Interop.MountPoints.cs | 23 ++++++------ src/native/libs/System.Native/pal_mount.c | 30 ++++++++-------- src/native/libs/System.Native/pal_mount.h | 8 +++-- 4 files changed, 51 insertions(+), 45 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 8a542ab2b5230a..f462d938b1399f 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 @@ -45,22 +45,28 @@ internal static unsafe Error GetFileSystemTypeNameForMountPoint(string name, out return GetLastError(); } - return procfs.GetFileSystemTypeForRealPath(path, out format); + Error error = procfs.GetFileSystemTypeForRealPath(path, out format); + + // When there is no procfs mountinfo fall through. + if (error != Error.ENOTSUP) + { + return error; + } + } + + long formatType; + byte* formatBuffer = stackalloc byte[MountPointFormatBufferSizeInBytes]; // format names should be small + int result = GetFileSystemTypeNameForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes, &formatType); + if (result == 0) + { + format = formatType == -1 ? Marshal.PtrToStringUTF8((IntPtr)formatBuffer)! + : (Enum.GetName(typeof(UnixFileSystemTypes), formatType) ?? ""); + return Error.SUCCESS; } else { - byte* formatBuffer = stackalloc byte[MountPointFormatBufferSizeInBytes]; // format names should be small - int result = GetFileSystemTypeNameForMountPoint(name, formatBuffer, MountPointFormatBufferSizeInBytes); - if (result == 0) - { - format = Marshal.PtrToStringUTF8((IntPtr)formatBuffer)!; - return Error.SUCCESS; - } - else - { - format = string.Empty; - return GetLastError(); - } + format = string.Empty; + return GetLastError(); } } @@ -75,7 +81,8 @@ internal static Error GetDriveTypeForMountPoint(string name, out DriveType type) private static unsafe partial int GetFileSystemTypeNameForMountPoint( [MarshalAs(UnmanagedType.LPUTF8Str)] string name, byte* formatNameBuffer, - int bufferLength); + int bufferLength, + long* formatType); /// Categorizes a file system name into a drive type. /// The name to categorize. diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs index 055c8d5e9f259a..fe154e180cdaf6 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs @@ -37,6 +37,7 @@ private static unsafe void AddMountPoint(void* context, byte* name) internal static string[] GetAllMountPoints() { + // Prefer using proc mountinfo as the mount point paths are relative to the process's root. if (OperatingSystem.IsLinux()) { if (File.Exists(Interop.procfs.ProcMountInfoFilePath)) @@ -56,23 +57,19 @@ internal static string[] GetAllMountPoints() return mountPoints.ToArray(); } - - return Array.Empty(); } - else - { - AllMountPointsContext context = default; - context._results = new List(); - - unsafe - { - GetAllMountPoints(&AddMountPoint, &context); - } - context._exception?.Throw(); + AllMountPointsContext context = default; + context._results = new List(); - return context._results.ToArray(); + unsafe + { + GetAllMountPoints(&AddMountPoint, &context); } + + context._exception?.Throw(); + + return context._results.ToArray(); } } } diff --git a/src/native/libs/System.Native/pal_mount.c b/src/native/libs/System.Native/pal_mount.c index 2c7dbfe658d026..255ec49aba3b60 100644 --- a/src/native/libs/System.Native/pal_mount.c +++ b/src/native/libs/System.Native/pal_mount.c @@ -132,28 +132,22 @@ int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInfor } int32_t -SystemNative_GetFileSystemTypeNameForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength) +SystemNative_GetFileSystemTypeNameForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength, int64_t* formatType) { assert(formatNameBuffer != NULL); assert(bufferLength > 0); -#if HAVE_STATFS_FSTYPENAME +#if HAVE_NON_LEGACY_STATFS struct statfs stats; int result = statfs(name, &stats); -#elif HAVE_STATVFS_FSTYPENAME +#else struct statvfs stats; int result = statvfs(name, &stats); -#else - (void)name; // unused - (void)formatNameBuffer; // unused - (void)bufferLength; // unused - int result = -1; - errno = ENOTSUP; #endif -#if HAVE_STATFS_FSTYPENAME || HAVE_STATVFS_FSTYPENAME if (result == 0) { +#if HAVE_STATFS_FSTYPENAME || HAVE_STATVFS_FSTYPENAME #ifdef HAVE_STATFS_FSTYPENAME if (bufferLength < (MFSNAMELEN + 1)) // MFSNAMELEN does not include the null byte #elif HAVE_STATVFS_FSTYPENAME @@ -163,12 +157,18 @@ SystemNative_GetFileSystemTypeNameForMountPoint(const char* name, char* formatNa errno = ERANGE; result = -1; } - else - { - SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), stats.f_fstypename); - } - } + SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), stats.f_fstypename); + *formatType = -1; +#else + SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), ""); + *formatType = (int64_t)(stats.f_type); #endif + } + else + { + SafeStringCopy(formatNameBuffer, Int32ToSizeT(bufferLength), ""); + *formatType = -1; + } return result; } diff --git a/src/native/libs/System.Native/pal_mount.h b/src/native/libs/System.Native/pal_mount.h index 6901e42b8c7f49..3d6120f2935b88 100644 --- a/src/native/libs/System.Native/pal_mount.h +++ b/src/native/libs/System.Native/pal_mount.h @@ -29,11 +29,13 @@ typedef void (*MountPointFound)(void* context, const char* name); PALEXPORT int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInformation* mpi); /** - * Gets the file system type name for the given mount point. - * Returns -1 (ENOTSUP) when stat(v)fs does not provide a string representation of the file system type. + * Gets the file system type about the given path. + * Returns 0 on success, and -1 (with errno set) on failure. + * If the platform supports returning a string representation it is stored in formatNameBuffer and formatType is set to -1. + * Otherwise the formatType is set the platform specific magic constant for the file system type. */ PALEXPORT int32_t SystemNative_GetFileSystemTypeNameForMountPoint( - const char* name, char* formatNameBuffer, int32_t bufferLength); + const char* name, char* formatNameBuffer, int32_t bufferLength, int64_t* formatType); /** * Enumerate all mount points on the system and call the input From efd1dfd88cc505666fedfe68a08ffeb01a78f53e Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Mon, 2 Jun 2025 14:14:54 +0200 Subject: [PATCH 11/12] UnixFileSystemTypes: prefer Linux file system type strings as names, and remove duplicate value members. --- .../Interop.UnixFileSystemTypes.cs | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) 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 a41cb65ad066ba..dd4ef23319febe 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,12 +11,13 @@ internal static partial class Interop internal static partial class Sys { /// - /// Internal FileSystem names and magic numbers taken from man(2) statfs + /// FileSystem magic numbers used to turn numbers into a DriveInfo.DriveFormat string representation. /// /// /// 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. + /// 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. /// internal enum UnixFileSystemTypes : uint { @@ -29,25 +30,25 @@ internal enum UnixFileSystemTypes : uint autofs = 0x0187, autofs4 = 0x6D4A556D, befs = 0x42465331, - bdevfs = 0x62646576, + bdev = 0x62646576, bfs = 0x1BADFACE, bpf_fs = 0xCAFE4A11, binfmt_misc = 0x42494E4D, bootfs = 0xA56D3FF9, btrfs = 0x9123683E, ceph = 0x00C36400, - cgroupfs = 0x0027E0EB, - cgroup2fs = 0x63677270, + cgroup = 0x0027E0EB, + cgroup2 = 0x63677270, cifs = 0xFF534D42, coda = 0x73757245, coherent = 0x012FF7B7, configfs = 0x62656570, - cpuset = 0x01021994, // same as tmpfs + // cpuset = 0x01021994, // same as tmpfs cramfs = 0x28CD3D45, - ctfs = 0x01021994, // same as tmpfs + // ctfs = 0x01021994, // same as tmpfs debugfs = 0x64626720, - dev = 0x1373, // same as devfs - devfs = 0x1373, + dev = 0x1373, + // devfs = 0x1373, // same as dev devpts = 0x1CD1, ecryptfs = 0xF15F, efs = 0x00414A53, @@ -55,17 +56,17 @@ internal enum UnixFileSystemTypes : uint ext = 0x137D, ext2_old = 0xEF51, ext2 = 0xEF53, - ext3 = 0xEF53, - ext4 = 0xEF53, + // ext3 = 0xEF53, // same as ext2 + // ext4 = 0xEF53, // same as ext2 f2fs = 0xF2F52010, fat = 0x4006, fd = 0xF00D1E, fhgfs = 0x19830326, fuse = 0x65735546, - fuseblk = 0x65735546, + // fuseblk = 0x65735546, // same as fuse fusectl = 0x65735543, futexfs = 0x0BAD1DEA, - gfsgfs2 = 0x1161970, + // gfsgfs2 = 0x1161970, // same as gfs2 gfs2 = 0x01161970, gpfs = 0x47504653, hfs = 0x4244, @@ -81,7 +82,7 @@ internal enum UnixFileSystemTypes : uint jffs2 = 0x72B6, jfs = 0x3153464A, kafs = 0x6B414653, - lofs = 0xEF53, /* loopback filesystem, magic same as ext2 */ + // lofs = 0xEF53, same as ext2 logfs = 0xC97E8168, lustre = 0x0BD00BD0, minix_old = 0x137F, /* orig. minix */ @@ -89,7 +90,7 @@ internal enum UnixFileSystemTypes : uint minix2 = 0x2468, /* minix V2 */ minix2v2 = 0x2478, /* MINIX V2, 30 char names */ minix3 = 0x4D5A, - mntfs = 0x01021994, // same as tmpfs + // mntfs = 0x01021994, // same as tmpfs mqueue = 0x19800202, msdos = 0x4D44, nfs = 0x6969, @@ -97,7 +98,7 @@ internal enum UnixFileSystemTypes : uint nilfs = 0x3434, novell = 0x564C, ntfs = 0x5346544E, - objfs = 0x01021994, // same as tmpfs + // objfs = 0x01021994, // same as tmpfs ocfs2 = 0x7461636F, openprom = 0x9FA1, omfs = 0xC2993D87, @@ -106,7 +107,7 @@ internal enum UnixFileSystemTypes : uint panfs = 0xAAD7AAEA, pipefs = 0x50495045, proc = 0x9FA0, - pstorefs = 0x6165676C, + pstore = 0x6165676C, qnx4 = 0x002F, qnx6 = 0x68191122, ramfs = 0x858458F6, @@ -114,12 +115,12 @@ internal enum UnixFileSystemTypes : uint romfs = 0x7275, rootfs = 0x53464846, rpc_pipefs = 0x67596969, - samba = 0x517B, + // samba = 0x517B, // same as smb sdcardfs = 0x5DCA2DF5, securityfs = 0x73636673, - selinux = 0xF97CFF8C, - sffs = 0x786F4256, // same as vboxfs - sharefs = 0x01021994, // same as tmpfs + selinuxfs = 0xF97CFF8C, + // sffs = 0x786F4256, // same as vboxfs + // sharefs = 0x01021994, // same as tmpfs smb = 0x517B, smb2 = 0xFE534D42, sockfs = 0x534F434B, @@ -136,7 +137,7 @@ internal enum UnixFileSystemTypes : uint ufs2 = 0x19540119, usbdevice = 0x9FA2, v9fs = 0x01021997, - vagrant = 0x786F4256, // same as vboxfs + // vagrant = 0x786F4256, // same as vboxfs vboxfs = 0x786F4256, vmhgfs = 0xBACBACBC, vxfs = 0xA501FCF5, @@ -145,7 +146,7 @@ internal enum UnixFileSystemTypes : uint xenix = 0x012FF7B4, xfs = 0x58465342, xia = 0x012FD16D, - udev = 0x01021994, // same as tmpfs + // udev = 0x01021994, // same as tmpfs zfs = 0x2FC12FC1, } From 4f7e3f29ced3f643b7c35e20771cf4fe830a061c Mon Sep 17 00:00:00 2001 From: Tom Deseyn Date: Mon, 2 Jun 2025 14:53:59 +0200 Subject: [PATCH 12/12] Fix wasi build breakage. --- src/native/libs/System.Native/pal_mount.c | 2 +- src/native/libs/System.Native/pal_mount_wasi.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/libs/System.Native/pal_mount.c b/src/native/libs/System.Native/pal_mount.c index 255ec49aba3b60..758575e6954f33 100644 --- a/src/native/libs/System.Native/pal_mount.c +++ b/src/native/libs/System.Native/pal_mount.c @@ -134,7 +134,7 @@ int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInfor int32_t SystemNative_GetFileSystemTypeNameForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength, int64_t* formatType) { - assert(formatNameBuffer != NULL); + assert((formatNameBuffer != NULL) && (formatType != NULL)); assert(bufferLength > 0); #if HAVE_NON_LEGACY_STATFS diff --git a/src/native/libs/System.Native/pal_mount_wasi.c b/src/native/libs/System.Native/pal_mount_wasi.c index 8dbf45c1325e6d..e9be8ee62a71e6 100644 --- a/src/native/libs/System.Native/pal_mount_wasi.c +++ b/src/native/libs/System.Native/pal_mount_wasi.c @@ -24,7 +24,7 @@ int32_t SystemNative_GetSpaceInfoForMountPoint(const char* name, MountPointInfor } int32_t -SystemNative_GetFileSystemTypeNameForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength) +SystemNative_GetFileSystemTypeNameForMountPoint(const char* name, char* formatNameBuffer, int32_t bufferLength, int64_t* formatType) { assert((formatNameBuffer != NULL) && (formatType != NULL)); assert(bufferLength > 0);