Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit ce056a8

Browse files
committed
Merge pull request #2412 from stephentoub/driveinfo_drivetype_unix
Fix DriveInfo.DriveType to not throw on Unix
2 parents ec6343f + 0c44f89 commit ce056a8

File tree

3 files changed

+55
-20
lines changed

3 files changed

+55
-20
lines changed

src/Common/src/Interop/Unix/libc/Interop.mountpoints.cs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
using System;
55
using System.Runtime.InteropServices;
66

7-
using uid_t = System.UInt32;
8-
97
internal static partial class Interop
108
{
119
internal static partial class libc
@@ -33,26 +31,40 @@ internal static partial class libc
3331
private static unsafe extern int get_statfs(string path, out statfs buffer);
3432

3533
/// <summary>
36-
/// Gets a statfs struct for a given mount point
34+
/// Attempts to get a statfs struct for a given mount point.
3735
/// </summary>
38-
/// <param name="name">The drive name to retrieve the statfs data for</param>
39-
/// <returns>Returns </returns>
40-
internal static unsafe statfs GetStatFsForDriveName(string name)
36+
/// <param name="name">The drive name to retrieve the statfs data for.</param>
37+
/// <param name="data">The data retrieved from the mount point.</param>
38+
/// <returns>Returns true if data was filled with the results; otherwise, false.</returns>
39+
internal static bool TryGetStatFsForDriveName(string name, out statfs data, out int errno)
4140
{
42-
statfs data = default(statfs);
43-
int result = get_statfs(name, out data);
44-
if (result < 0)
41+
data = default(statfs);
42+
errno = 0;
43+
if (get_statfs(name, out data) < 0)
4544
{
46-
int errno = Marshal.GetLastWin32Error();
47-
if (errno == Interop.Errors.ENOENT)
48-
throw new System.IO.DriveNotFoundException(SR.Format(SR.IO_DriveNotFound_Drive, name)); // match Win32 exception
49-
else
50-
throw Interop.GetExceptionForIoErrno(errno, isDirectory: true);
45+
errno = Marshal.GetLastWin32Error();
46+
return false;
5147
}
52-
else
48+
return true;
49+
}
50+
51+
/// <summary>
52+
/// Gets a statfs struct for a given mount point
53+
/// </summary>
54+
/// <param name="name">The drive name to retrieve the statfs data for.</param>
55+
/// <returns>Returns the statfs.</returns>
56+
internal static statfs GetStatFsForDriveName(string name)
57+
{
58+
statfs data;
59+
int errno;
60+
if (!TryGetStatFsForDriveName(name, out data, out errno))
5361
{
54-
return data;
62+
throw errno == Errors.ENOENT ?
63+
new System.IO.DriveNotFoundException(SR.Format(SR.IO_DriveNotFound_Drive, name)) : // match Win32 exception
64+
GetExceptionForIoErrno(errno, isDirectory: true);
5565
}
66+
return data;
5667
}
68+
5769
}
5870
}

src/System.IO.FileSystem.DriveInfo/src/System/IO/DriveInfo.Unix.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (c) Microsoft. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4-
using System.Runtime.InteropServices;
54
using System.Security;
65

76
namespace System.IO
@@ -26,8 +25,25 @@ public DriveType DriveType
2625
[SecuritySafeCritical]
2726
get
2827
{
29-
Interop.libc.statfs data = Interop.libc.GetStatFsForDriveName(Name);
30-
return GetDriveType(Interop.libc.GetMountPointFsType(data));
28+
Interop.libc.statfs data;
29+
int errno;
30+
if (Interop.libc.TryGetStatFsForDriveName(Name, out data, out errno))
31+
{
32+
return GetDriveType(Interop.libc.GetMountPointFsType(data));
33+
}
34+
35+
// This is one of the few properties that doesn't throw on failure,
36+
// instead returning a value from the enum.
37+
switch (errno)
38+
{
39+
case Interop.Errors.ELOOP:
40+
case Interop.Errors.ENAMETOOLONG:
41+
case Interop.Errors.ENOENT:
42+
case Interop.Errors.ENOTDIR:
43+
return DriveType.NoRootDirectory;
44+
default:
45+
return DriveType.Unknown;
46+
}
3147
}
3248
}
3349

src/System.IO.FileSystem.DriveInfo/tests/DriveInfo.Unix.Tests.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ public void TestGetDrives()
3030
Assert.True(drives.Length > 0, "Expected at least one drive");
3131
Assert.All(drives, d => Assert.NotNull(d));
3232
Assert.Contains(drives, d => d.Name == "/");
33+
Assert.All(drives, d =>
34+
{
35+
// None of these should throw
36+
DriveType dt = d.DriveType;
37+
bool isReady = d.IsReady;
38+
DirectoryInfo di = d.RootDirectory;
39+
});
3340
}
3441

3542
[Fact]
@@ -38,9 +45,9 @@ public void TestInvalidDriveName()
3845
{
3946
var invalidDrive = new DriveInfo("NonExistentDriveName");
4047
Assert.Throws<DriveNotFoundException>(() => { var df = invalidDrive.DriveFormat; });
41-
Assert.Throws<DriveNotFoundException>(() => { var size = invalidDrive.DriveType; });
4248
Assert.Throws<DriveNotFoundException>(() => { var size = invalidDrive.TotalFreeSpace; });
4349
Assert.Throws<DriveNotFoundException>(() => { var size = invalidDrive.TotalSize; });
50+
Assert.Equal(DriveType.NoRootDirectory, invalidDrive.DriveType);
4451
}
4552

4653
[Fact]

0 commit comments

Comments
 (0)