Skip to content

Commit

Permalink
mscorlib: Import DriveInfo.VolumeLabel from referencesource.
Browse files Browse the repository at this point in the history
  • Loading branch information
Esme Povirk committed Nov 21, 2023
1 parent 4976b75 commit 3bd823b
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 2 deletions.
37 changes: 36 additions & 1 deletion mcs/class/corlib/ReferenceSources/win32native.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace Microsoft.Win32
{
static class Win32Native
{
internal const string ADVAPI32 = "advapi32.dll";
internal const String KERNEL32 = "kernel32.dll";

// Error codes from WinError.h
internal const int ERROR_SUCCESS = 0x0;
Expand Down Expand Up @@ -79,5 +81,38 @@ internal class WIN32_FIND_DATA
internal int dwFileAttributes = 0;
internal String cFileName = null;
}

// From WinBase.h
internal const int SEM_FAILCRITICALERRORS = 1;

[DllImport(KERNEL32, CharSet=CharSet.Auto, SetLastError=true, BestFitMapping=false)]
internal static extern bool GetVolumeInformation(String drive, [Out]StringBuilder volumeName, int volumeNameBufLen, out int volSerialNumber, out int maxFileNameLen, out int fileSystemFlags, [Out]StringBuilder fileSystemName, int fileSystemNameBufLen);

[DllImport(KERNEL32, CharSet=CharSet.Auto, SetLastError=true, BestFitMapping=false)]
internal static extern bool SetVolumeLabel(String driveLetter, String volumeName);

[DllImport(KERNEL32, SetLastError=false, EntryPoint="SetErrorMode", ExactSpelling=true)]
private static extern int SetErrorMode_VistaAndOlder(int newMode);

[DllImport(KERNEL32, SetLastError=true, EntryPoint="SetThreadErrorMode")]
private static extern bool SetErrorMode_Win7AndNewer(int newMode, out int oldMode);

// RTM versions of Win7 and Windows Server 2008 R2
private static readonly Version ThreadErrorModeMinOsVersion = new Version(6, 1, 7600);

// this method uses the thread-safe version of SetErrorMode on Windows 7 / Windows Server 2008 R2 operating systems.
//
internal static int SetErrorMode(int newMode)
{
#if !FEATURE_CORESYSTEM // ARMSTUB
if (Environment.OSVersion.Version >= ThreadErrorModeMinOsVersion)
{
int oldMode;
SetErrorMode_Win7AndNewer(newMode, out oldMode);
return oldMode;
}
#endif
return SetErrorMode_VistaAndOlder(newMode);
}
}
}
}
58 changes: 57 additions & 1 deletion mcs/class/corlib/System.IO/DriveInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Text;
Expand Down Expand Up @@ -106,7 +107,61 @@ public long TotalSize {
}
}

[MonoTODO ("Currently get only works on Mono/Unix; set not implemented")]
#if PLATFORM_WINDOWS
// Null is a valid volume label.
public String VolumeLabel {
get {
// NTFS uses a limit of 32 characters for the volume label,
// as of Windows Server 2003.
const int volNameLen = 50;
StringBuilder volumeName = new StringBuilder(volNameLen);
const int fileSystemNameLen = 50;
StringBuilder fileSystemName = new StringBuilder(fileSystemNameLen);
int serialNumber, maxFileNameLen, fileSystemFlags;

int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
try {
bool r = Win32Native.GetVolumeInformation(Name, volumeName, volNameLen, out serialNumber, out maxFileNameLen, out fileSystemFlags, fileSystemName, fileSystemNameLen);
if (!r) {
int errorCode = Marshal.GetLastWin32Error();
// Win9x appears to return ERROR_INVALID_DATA when a
// drive doesn't exist.
if (errorCode == Win32Native.ERROR_INVALID_DATA)
errorCode = Win32Native.ERROR_INVALID_DRIVE;
if (errorCode == Win32Native.ERROR_PATH_NOT_FOUND || errorCode == Win32Native.ERROR_INVALID_DRIVE)
throw new DriveNotFoundException(Name);
if (errorCode != 0)
Marshal.ThrowExceptionForHR(Win32Native.MakeHRFromErrorCode(errorCode));
}
}
finally {
Win32Native.SetErrorMode(oldMode);
}
return volumeName.ToString();
}
set {
String demandPath = Name + '.';

int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
try {
bool r = Win32Native.SetVolumeLabel(Name, value);
if (!r) {
int errorCode = Marshal.GetLastWin32Error();
// Provide better message
if (errorCode == Win32Native.ERROR_ACCESS_DENIED)
throw new UnauthorizedAccessException(Environment.GetResourceString("InvalidOperation_SetVolumeLabelFailed"));
if (errorCode == Win32Native.ERROR_PATH_NOT_FOUND || errorCode == Win32Native.ERROR_INVALID_DRIVE)
throw new DriveNotFoundException(Name);
if (errorCode != 0)
Marshal.ThrowExceptionForHR(Win32Native.MakeHRFromErrorCode(errorCode));
}
}
finally {
Win32Native.SetErrorMode(oldMode);
}
}
}
#else
public string VolumeLabel {
get {
return path;
Expand All @@ -115,6 +170,7 @@ public string VolumeLabel {
throw new NotImplementedException ();
}
}
#endif

public string DriveFormat {
get {
Expand Down

0 comments on commit 3bd823b

Please sign in to comment.