From 56c96688d7bfdfdc0c8341c28baa027a81d48c8f Mon Sep 17 00:00:00 2001 From: dahall Date: Tue, 3 May 2022 16:49:12 -0600 Subject: [PATCH] #284 - added functionality to address multiple mount points to VirtualDisk --- VirtualDisk/VirtualDisk.cs | 79 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/VirtualDisk/VirtualDisk.cs b/VirtualDisk/VirtualDisk.cs index e0b14e62..4b8a9ae3 100644 --- a/VirtualDisk/VirtualDisk.cs +++ b/VirtualDisk/VirtualDisk.cs @@ -267,6 +267,19 @@ public partial class VirtualDisk : IDisposable, IHandle } } + /// Gets the volume GUID paths for an attached virtual disk. + public string[] VolumeGuidPaths + { + get + { + if (!Attached) + return null; + + var diskNo = GetDiskNumberFromDevicePath(PhysicalPath); + return diskNo.HasValue ? GetVolumeGuidsFromDiskNumber(diskNo.Value).ToArray() : null; + } + } + /// Gets the volume mount point for an attached virtual disk. public string VolumeMountPoint { @@ -277,6 +290,16 @@ public partial class VirtualDisk : IDisposable, IHandle } } + /// Gets the volume mount points for an attached virtual disk. + public string[] VolumeMountPoints + { + get + { + var volPath = VolumeGuidPath; + return volPath is null ? null : GetVolumeMountPoints(volPath); + } + } + /// Gets the safe handle for the current virtual disk. private SafeVIRTUAL_DISK_HANDLE Handle { get; set; } @@ -717,23 +740,51 @@ public partial class VirtualDisk : IDisposable, IHandle /// security descriptor does not grant write attributes permission for a user, Shell displays the following error when the user accesses /// the attached virtual disk: The Recycle Bin is corrupted. Do you want to empty the Recycle Bin for this drive? /// - public void Attach(string mountPoint, bool readOnly = false, bool autoDetach = true, FileSecurity access = null) + public void Attach(string mountPoint, bool readOnly = false, bool autoDetach = true, FileSecurity access = null) => + Attach(mountPoint is null ? null : new[] { mountPoint }, readOnly, autoDetach, access); + + /// + /// Attaches a virtual hard disk (VHD) or CD or DVD image file (ISO) by locating an appropriate VHD provider to accomplish the attachment. + /// + /// + /// The user-mode paths to be associated with the volume. These may be a drive letter (for example, "X:\") or a directory on another + /// volume (for example, "Y:\MountX\"). The string must end with a trailing backslash ('\'). Use "*" as the first and only entry to have + /// the system assign a drive letter or to leave the drive letter unassigned. + /// + /// Attach the virtual disk as read-only. + /// + /// If false, decouple the virtual disk lifetime from that of the VirtualDisk. The virtual disk will be attached until the Detach + /// function is called, even if all open instances of the virtual disk are disposed. + /// + /// + /// An optional pointer to a FileSecurity instance to apply to the attached virtual disk. If this parameter is , + /// the security descriptor of the virtual disk image file is used. Ensure that the security descriptor that AttachVirtualDisk applies to + /// the attached virtual disk grants the write attributes permission for the user, or that the security descriptor of the virtual disk + /// image file grants the write attributes permission for the user if you specify for this parameter. If the + /// security descriptor does not grant write attributes permission for a user, Shell displays the following error when the user accesses + /// the attached virtual disk: The Recycle Bin is corrupted. Do you want to empty the Recycle Bin for this drive? + /// + public void Attach(string[] mountPoints, bool readOnly = false, bool autoDetach = true, FileSecurity access = null) { + var vgp = VolumeGuidPaths; + if (mountPoints.Length == 0 || mountPoints.Length > vgp.Length || (mountPoints[0] != "*" && mountPoints.Any(p => p == "*"))) + throw new ArgumentException(); + ATTACH_VIRTUAL_DISK_FLAG flags = readOnly ? ATTACH_VIRTUAL_DISK_FLAG.ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY : 0; if (!autoDetach) flags |= ATTACH_VIRTUAL_DISK_FLAG.ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME; - - if (mountPoint != "*") + if (mountPoints.Length == 1 && mountPoints[0] != "*") flags |= ATTACH_VIRTUAL_DISK_FLAG.ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER; - if (access is null) flags |= ATTACH_VIRTUAL_DISK_FLAG.ATTACH_VIRTUAL_DISK_FLAG_NO_SECURITY_DESCRIPTOR; ATTACH_VIRTUAL_DISK_PARAMETERS param = ATTACH_VIRTUAL_DISK_PARAMETERS.Default; using SafePSECURITY_DESCRIPTOR sd = FileSecToSd(access); Attach(flags, param, sd); - if (mountPoint is not null and not "*") - Win32Error.ThrowLastErrorIfFalse(SetVolumeMountPoint(mountPoint, VolumeGuidPath)); + + if (mountPoints is null || mountPoints[0] is "*") return; + for (var i = 0; i < mountPoints.Length; i++) + Win32Error.ThrowLastErrorIfFalse(SetVolumeMountPoint(mountPoints[i], vgp[i])); } /// @@ -1214,13 +1265,15 @@ public partial class VirtualDisk : IDisposable, IHandle } } - private static string GetVolumeGuidFromDiskNumber(uint diskNo) => EnumVolumes().FirstOrDefault(v => - { - using var hfile = OpenDrive(v.TrimEnd('\\')); - return !hfile.IsInvalid && - DeviceIoControl(hfile, IOControlCode.IOCTL_STORAGE_GET_DEVICE_NUMBER, out STORAGE_DEVICE_NUMBER output) && - output.DeviceNumber == diskNo; - }); + private static string GetVolumeGuidFromDiskNumber(uint diskNo) => GetVolumeGuidsFromDiskNumber(diskNo).FirstOrDefault(); + + private static IEnumerable GetVolumeGuidsFromDiskNumber(uint diskNo) => EnumVolumes().Where(v => + { + using var hfile = OpenDrive(v.TrimEnd('\\')); + return !hfile.IsInvalid && + DeviceIoControl(hfile, IOControlCode.IOCTL_STORAGE_GET_DEVICE_NUMBER, out STORAGE_DEVICE_NUMBER output) && + output.DeviceNumber == diskNo; + }).ToArray(); /// Retrieves a list of drive letters and mounted folder paths for the specified volume. /// A volume GUID path for the volume. A volume GUID path is of the form "\\?\Volume{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\".