/// <summary> /// Open the specified disk image file. /// </summary> /// <param name="imageFile">The vhd or vhdx file to open.</param> /// <param name="openReadOnly">Open as read-only.</param> /// <returns></returns> /// <remarks></remarks> public bool Open(string imageFile, bool openReadOnly) { bool OpenRet = default; string ext = Path.GetExtension(imageFile).ToLower(); VIRTUAL_STORAGE_TYPE vst; if (_Handle != IntPtr.Zero) { Close(); } var vdp1 = new OPEN_VIRTUAL_DISK_PARAMETERS_V1(); var vdp2 = new OPEN_VIRTUAL_DISK_PARAMETERS_V2(); uint r; var am = VIRTUAL_DISK_ACCESS_MASK.VIRTUAL_DISK_ACCESS_GET_INFO | VIRTUAL_DISK_ACCESS_MASK.VIRTUAL_DISK_ACCESS_DETACH; if (!openReadOnly) { am = am | VIRTUAL_DISK_ACCESS_MASK.VIRTUAL_DISK_ACCESS_ATTACH_RW; } vdp2.Version = OPEN_VIRTUAL_DISK_VERSION.OPEN_VIRTUAL_DISK_VERSION_2; vdp2.ResiliencyGuid = Guid.NewGuid(); vdp2.ReadOnly = false; vdp2.GetInfoOnly = false; vdp1.RWDepth = 1U; vdp1.Version = OPEN_VIRTUAL_DISK_VERSION.OPEN_VIRTUAL_DISK_VERSION_1; vst.VendorId = VirtDisk.VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT; switch (ext.ToLower() ?? "") { case ".vhd": vst.DeviceId = VirtDisk.VIRTUAL_STORAGE_TYPE_DEVICE_VHD; r = VirtDisk.OpenVirtualDisk(vst, imageFile, am, OPEN_VIRTUAL_DISK_FLAG.OPEN_VIRTUAL_DISK_FLAG_NONE, vdp1, ref _Handle); break; case ".vhdx": vst.DeviceId = VirtDisk.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX; r = VirtDisk.OpenVirtualDisk(vst, imageFile, am, OPEN_VIRTUAL_DISK_FLAG.OPEN_VIRTUAL_DISK_FLAG_NONE, vdp1, ref _Handle); break; default: return(false); } if (r == 0L) { _ImageFile = imageFile; } OpenRet = r == 0L; return(OpenRet); }
/// <summary> /// Dismount the drive. /// </summary> /// <returns></returns> /// <remarks></remarks> public bool Detach() { if (!Attached) { return(false); } uint r = VirtDisk.DetachVirtualDisk(_Handle, DETACH_VIRTUAL_DISK_FLAG.DETACH_VIRTUAL_DISK_FLAG_NONE, 0U); return(r == 0L); }
public override bool UnmountCurrentDiskImage() { if (mountedHandle != null) { Win32Error error = VirtDisk.DetachVirtualDisk(mountedHandle, VirtDisk.DETACH_VIRTUAL_DISK_FLAG.DETACH_VIRTUAL_DISK_FLAG_NONE, 0); if (error.Failed) { AutoMounter.Plugin.LogInfo($"WinVirtDisk: Failed to unmount disk from system {mountedHandle.ToString()}, {error.ToString()}"); AutoMounter.API.Dialogs.ShowErrorMessage("Failed to unmount disk from system", "AutoMounter"); } mountedHandle.Close(); mountedHandle = null; } return(true); }
/// <summary> /// Mount the virtual drive, permanently. The virtual drive will stay mounted beyond the lifetime of this instance. /// </summary> /// <param name="makePermanent"></param> /// <returns></returns> /// <remarks></remarks> public bool Attach(bool makePermanent) { if (_Handle == IntPtr.Zero || Attached) { return(false); } var mm = new MemPtr(8L); mm.ByteAt(0L) = 1; uint r = VirtDisk.AttachVirtualDisk(_Handle, IntPtr.Zero, makePermanent ? ATTACH_VIRTUAL_DISK_FLAG.ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME : ATTACH_VIRTUAL_DISK_FLAG.ATTACH_VIRTUAL_DISK_FLAG_NONE, 0U, mm.Handle, IntPtr.Zero); mm.Free(); return(r == 0L); }
/// <summary> /// Creates a new virtual disk device file. /// </summary> /// <param name="imageFile">Full path to the destination image, including file extension (.vhd or .vhdx)</param> /// <param name="diskSize">The virtual size of the new disk.</param> /// <param name="fixedSize">Indicates whether or not the size is fixed or virtual.</param> /// <param name="id">Receives the Guid for the new drive.</param> /// <param name="resiliencyId">The Resiliancy Guid.</param> /// <param name="blockSize">The transfer block size.</param> /// <param name="sectorSize">The virtual sector size.</param> /// <param name="sourcePath">The cloning source (if any).</param> /// <param name="sourceDiskType">The cloning source disk type (if applicable).</param> /// <returns>A new VirtualDisk object.</returns> /// <remarks></remarks> public static VirtualDisk Create(string imageFile, long diskSize, bool fixedSize, ref Guid id, ref Guid resiliencyId, int blockSize = 2097152, int sectorSize = 512, string sourcePath = null, VirtualStorageType sourceDiskType = VirtualStorageType.Unknown) { VirtualDisk CreateRet = default; string ext = Path.GetExtension(imageFile).ToLower(); var cp2 = new CREATE_VIRTUAL_DISK_PARAMETERS_V2(); var cp1 = new CREATE_VIRTUAL_DISK_PARAMETERS_V1(); VIRTUAL_STORAGE_TYPE vst; var r = default(uint); IntPtr handleNew = new IntPtr(); vst.VendorId = VirtDisk.VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT; switch (ext ?? "") { case ".vhd": { cp1.BlockSizeInBytes = (uint)blockSize; cp1.Version = CREATE_VIRTUAL_DISK_VERSION.CREATE_VIRTUAL_DISK_VERSION_1; cp1.MaximumSize = (ulong)diskSize; cp1.UniqueId = id; cp1.SourcePath = sourcePath; cp1.SectorSizeInBytes = 512; vst.DeviceId = VirtDisk.VIRTUAL_STORAGE_TYPE_DEVICE_VHD; r = VirtDisk.CreateVirtualDisk(vst, imageFile, VIRTUAL_DISK_ACCESS_MASK.VIRTUAL_DISK_ACCESS_ALL, IntPtr.Zero, fixedSize ? CREATE_VIRTUAL_DISK_FLAGS.CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION : CREATE_VIRTUAL_DISK_FLAGS.CREATE_VIRTUAL_DISK_FLAG_NONE, 0U, cp1, IntPtr.Zero, ref handleNew); break; } case ".vhdx": { cp2.BlockSizeInBytes = (uint)blockSize; cp2.Version = CREATE_VIRTUAL_DISK_VERSION.CREATE_VIRTUAL_DISK_VERSION_2; cp2.MaximumSize = (ulong)diskSize; cp2.UniqueId = id; cp2.SourcePath = sourcePath; if (sourcePath is object) { cp2.SourceVirtualStorageType.DeviceId = (uint)sourceDiskType; cp2.SourceVirtualStorageType.VendorId = VirtDisk.VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT; } int x = Marshal.SizeOf(cp2); cp2.SectorSizeInBytes = sectorSize; if (resiliencyId != Guid.Empty) { cp2.ResiliencyGuid = resiliencyId; // Else // cp2.ResiliencyGuid = Guid.NewGuid // resiliencyId = cp2.ResiliencyGuid } cp2.OpenFlags = OPEN_VIRTUAL_DISK_FLAG.OPEN_VIRTUAL_DISK_FLAG_NONE; vst.DeviceId = VirtDisk.VIRTUAL_STORAGE_TYPE_DEVICE_VHDX; r = VirtDisk.CreateVirtualDisk(vst, imageFile, VIRTUAL_DISK_ACCESS_MASK.VIRTUAL_DISK_ACCESS_NONE, IntPtr.Zero, fixedSize ? CREATE_VIRTUAL_DISK_FLAGS.CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION : CREATE_VIRTUAL_DISK_FLAGS.CREATE_VIRTUAL_DISK_FLAG_NONE, 0U, cp2, IntPtr.Zero, ref handleNew); break; } } if (r != 0L) { CreateRet = null; } else { CreateRet = new VirtualDisk(); CreateRet._Handle = handleNew; CreateRet._ImageFile = imageFile; } return(CreateRet); }
public override bool MountDiskImage() { if (Path.GetExtension(DiskImage).ToLower() != ".iso") { AutoMounter.Plugin.LogInfo($"WinVirtDisk: Failed to open ISO as VirtualDisk, not an ISO - {DiskImage}"); return(false); } // Check file exists! Probably should return some nice error message... if (!File.Exists(DiskImage)) { AutoMounter.Plugin.LogInfo($"WinVirtDisk: Failed to open ISO as VirtualDisk, ISO does not exist on disk {DiskImage}"); return(false); } if (!AutoMountHelpers.IsDriveLetterFree(RequestedDriveLetter)) { AutoMounter.Plugin.LogInfo($"WinVirtDisk: Failed to open ISO as VirtualDisk, Drive Letter in use {RequestedDriveLetter}"); AutoMounter.API.Dialogs.ShowErrorMessage("Failed to open ISO as VirtualDisk, Drive Letter is in use", "AutoMounter"); return(false); } VirtDisk.VIRTUAL_STORAGE_TYPE type = new VirtDisk.VIRTUAL_STORAGE_TYPE(VirtDisk.VIRTUAL_STORAGE_TYPE_DEVICE_TYPE.VIRTUAL_STORAGE_TYPE_DEVICE_ISO); Win32Error error = VirtDisk.OpenVirtualDisk( ref type, DiskImage, VirtDisk.VIRTUAL_DISK_ACCESS_MASK.VIRTUAL_DISK_ACCESS_READ, VirtDisk.OPEN_VIRTUAL_DISK_FLAG.OPEN_VIRTUAL_DISK_FLAG_NONE, null, out mountedHandle); // Opened successfully if (error.Succeeded) { VirtDisk.ATTACH_VIRTUAL_DISK_PARAMETERS param = VirtDisk.ATTACH_VIRTUAL_DISK_PARAMETERS.Default; // Attach disk (no drive letter) error = VirtDisk.AttachVirtualDisk( mountedHandle, NullSafeHandle.Null(), VirtDisk.ATTACH_VIRTUAL_DISK_FLAG.ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER | VirtDisk.ATTACH_VIRTUAL_DISK_FLAG.ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY, // NO_DRIVE_LETTER at a later date 0, ref param, IntPtr.Zero); if (error.Succeeded) { // Try and assign the requested drive letter to the mounted image if (AssignDriveLetter(RequestedDriveLetter, mountedHandle)) { return(true); } else { AutoMounter.Plugin.LogInfo($"WinVirtDisk: Failed to open ISO as VirtualDisk, Unable to mount to drive letter {RequestedDriveLetter}"); AutoMounter.API.Dialogs.ShowErrorMessage("Failed to open ISO as VirtualDisk, Unable to mount to assigned drive letter", "AutoMounter"); UnmountCurrentDiskImage(); return(false); } } else { AutoMounter.Plugin.LogInfo($"WinVirtDisk: Failed to open ISO as VirtualDisk {error.ToString()}, AttachVirtualDisk Fail"); AutoMounter.API.Dialogs.ShowErrorMessage("Failed to open ISO as VirtualDisk, AttachVirtualDisk Fail", "AutoMounter"); UnmountCurrentDiskImage(); return(false); } } else { AutoMounter.Plugin.LogInfo($"WinVirtDisk: Failed to open ISO as VirtualDisk {error.ToString()}, OpenVirtualDisk Fail"); AutoMounter.API.Dialogs.ShowErrorMessage("Failed to open ISO as VirtualDisk, OpenVirtualDisk Fail", "AutoMounter"); UnmountCurrentDiskImage(); return(false); } }
private bool AssignDriveLetter(string driveLetter, SafeFileHandle mountedHandle) { int buffsize = 128; StringBuilder physicalPath = new StringBuilder(128); Win32Error error = VirtDisk.GetVirtualDiskPhysicalPath(mountedHandle, ref buffsize, physicalPath); // Find number on end of physical drive string \\.\CDROM1 int driveNumber = Convert.ToInt32(Regex.Match(physicalPath.ToString(), @"\d+").Value); STORAGE_DEVICE_NUMBER deviceNumber = new STORAGE_DEVICE_NUMBER(); // driveNumber should now contain the virtual CDROM drive number StringBuilder volumeName = new StringBuilder(128); Kernel32.SafeVolumeSearchHandle srchHandle = Kernel32.FindFirstVolume(volumeName, (uint)128); bool found = false; while (!found) { if (volumeName[volumeName.Length - 1] == '\\') { volumeName.Remove(volumeName.Length - 1, 1); } SafeFileHandle fileHandle = Kernel32.CreateFile(volumeName.ToString(), Kernel32.FileAccess.FILE_LIST_DIRECTORY, FileShare.Read, null, FileMode.Open, 0); if (!fileHandle.IsInvalid) { // Valid Kernel32.DeviceIoControl <STORAGE_DEVICE_NUMBER>(fileHandle, Kernel32.IOControlCode.IOCTL_STORAGE_GET_DEVICE_NUMBER, out deviceNumber); // Check device stats, should be a CDROM drive, then we should be ok to assume the disk number is ours... if (deviceNumber.deviceType == 2) { // Is a CDROM drive if (deviceNumber.deviceNumber == driveNumber) { // Got it! break; } } } if (!Kernel32.FindNextVolume(srchHandle, volumeName, (uint)128)) { break; } } srchHandle.Close(); // volumeName is now our mounted CDROM drive // WinAPI requires backslash on back of drive letter if (!driveLetter.Contains("\\")) { driveLetter += "\\"; } bool mounted = Kernel32.SetVolumeMountPoint(driveLetter, volumeName.Append("\\").ToString()); if (mounted) { AutoMounter.Plugin.LogInfo($"WinVirtDisk: Mounted ISO to {driveLetter} on device {volumeName}"); return(true); } else { AutoMounter.Log.Info("AutoMounter: Failed setting volume mount point"); return(false); } }