diff --git a/DiscImageChef.Devices/Device/Constructor.cs b/DiscImageChef.Devices/Device/Constructor.cs
index 1f820b57..051010e0 100644
--- a/DiscImageChef.Devices/Device/Constructor.cs
+++ b/DiscImageChef.Devices/Device/Constructor.cs
@@ -33,6 +33,8 @@
using System;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
+using System.Text;
+using DiscImageChef.Console;
using DiscImageChef.Decoders.ATA;
namespace DiscImageChef.Devices
@@ -100,6 +102,7 @@ namespace DiscImageChef.Devices
throw new SystemException(string.Format("Error {0} trying device.", lastError));
bool scsiSense = true;
+ string ntDevicePath = null;
// Windows is answering SCSI INQUIRY for all device types so it needs to be detected first
if(platformID == Interop.PlatformID.Win32NT)
@@ -126,7 +129,20 @@ namespace DiscImageChef.Devices
{
Windows.StorageDeviceDescriptor descriptor = new Windows.StorageDeviceDescriptor();
+ descriptor.Version = BitConverter.ToUInt32(descriptor_b, 0);
+ descriptor.Size = BitConverter.ToUInt32(descriptor_b, 4);
+ descriptor.DeviceType = descriptor_b[8];
+ descriptor.DeviceTypeModifier= descriptor_b[9];
+ descriptor.RemovableMedia = descriptor_b[10] > 0;
+ descriptor.CommandQueueing = descriptor_b[11] > 0;
+ descriptor.VendorIdOffset = BitConverter.ToUInt32(descriptor_b, 12);
+ descriptor.ProductIdOffset = BitConverter.ToUInt32(descriptor_b, 16);
+ descriptor.ProductRevisionOffset = BitConverter.ToUInt32(descriptor_b, 20);
+ descriptor.SerialNumberOffset = BitConverter.ToUInt32(descriptor_b, 24);
descriptor.BusType = (Windows.StorageBusType)BitConverter.ToUInt32(descriptor_b, 28);
+ descriptor.RawPropertiesLength = BitConverter.ToUInt32(descriptor_b, 32);
+ descriptor.RawDeviceProperties = new byte[descriptor.RawPropertiesLength];
+ Array.Copy(descriptor_b, 36, descriptor.RawDeviceProperties, 0, descriptor.RawPropertiesLength);
switch(descriptor.BusType)
{
@@ -180,9 +196,12 @@ namespace DiscImageChef.Devices
else
manufacturer = "ATA";
}
+
// TODO: Get cached CID, CSD and SCR from kernel space
}
-
+
+ ntDevicePath = Windows.Command.GetDevicePath((SafeFileHandle)fd);
+ DicConsole.DebugWriteLine("Windows devices", "NT device path: {0}", ntDevicePath);
Marshal.FreeHGlobal(descriptorPtr);
}
else
@@ -246,9 +265,12 @@ namespace DiscImageChef.Devices
}
#region USB
- if (platformID == Interop.PlatformID.Linux)
+
+ if(platformID == Interop.PlatformID.Linux)
{
- if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
+ if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
+ devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
+ devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
{
string devPath = devicePath.Substring(5);
if(System.IO.Directory.Exists("/sys/block/" + devPath))
@@ -261,14 +283,15 @@ namespace DiscImageChef.Devices
{
resolvedLink = System.IO.Path.GetDirectoryName(resolvedLink);
if(System.IO.File.Exists(resolvedLink + "/descriptors") &&
- System.IO.File.Exists(resolvedLink + "/idProduct") &&
- System.IO.File.Exists(resolvedLink + "/idVendor"))
+ System.IO.File.Exists(resolvedLink + "/idProduct") &&
+ System.IO.File.Exists(resolvedLink + "/idVendor"))
{
System.IO.FileStream usbFs;
System.IO.StreamReader usbSr;
string usbTemp;
- usbFs = new System.IO.FileStream(resolvedLink + "/descriptors", System.IO.FileMode.Open, System.IO.FileAccess.Read);
+ usbFs = new System.IO.FileStream(resolvedLink + "/descriptors",
+ System.IO.FileMode.Open, System.IO.FileAccess.Read);
byte[] usbBuf = new byte[65536];
int usbCount = usbFs.Read(usbBuf, 0, 65536);
usbDescriptors = new byte[usbCount];
@@ -277,12 +300,14 @@ namespace DiscImageChef.Devices
usbSr = new System.IO.StreamReader(resolvedLink + "/idProduct");
usbTemp = usbSr.ReadToEnd();
- ushort.TryParse(usbTemp, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out usbProduct);
+ ushort.TryParse(usbTemp, System.Globalization.NumberStyles.HexNumber,
+ System.Globalization.CultureInfo.InvariantCulture, out usbProduct);
usbSr.Close();
usbSr = new System.IO.StreamReader(resolvedLink + "/idVendor");
usbTemp = usbSr.ReadToEnd();
- ushort.TryParse(usbTemp, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out usbVendor);
+ ushort.TryParse(usbTemp, System.Globalization.NumberStyles.HexNumber,
+ System.Globalization.CultureInfo.InvariantCulture, out usbVendor);
usbSr.Close();
if(System.IO.File.Exists(resolvedLink + "/manufacturer"))
@@ -313,6 +338,10 @@ namespace DiscImageChef.Devices
}
}
}
+ }
+ else if(platformID == Interop.PlatformID.Win32NT)
+ {
+
}
// TODO: Implement for other operating systems
else
diff --git a/DiscImageChef.Devices/Windows/Command.cs b/DiscImageChef.Devices/Windows/Command.cs
index 3452f498..8c7ec55d 100644
--- a/DiscImageChef.Devices/Windows/Command.cs
+++ b/DiscImageChef.Devices/Windows/Command.cs
@@ -32,8 +32,10 @@
// ****************************************************************************/
using System;
+using System.Net.NetworkInformation;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
+using System.Text;
using DiscImageChef.Decoders.ATA;
namespace DiscImageChef.Devices.Windows
@@ -481,6 +483,93 @@ namespace DiscImageChef.Devices.Windows
return error;
}
+
+ internal static uint GetDeviceNumber(SafeFileHandle deviceHandle)
+ {
+ StorageDeviceNumber sdn = new StorageDeviceNumber();
+ sdn.deviceNumber = - 1;
+ uint k = 0;
+ if(!Extern.DeviceIoControlGetDeviceNumber(deviceHandle, WindowsIoctl.IOCTL_STORAGE_GET_DEVICE_NUMBER, IntPtr.Zero,
+ 0, ref sdn, (uint)Marshal.SizeOf(sdn), ref k, IntPtr.Zero))
+ {
+ return uint.MaxValue;
+ }
+
+ return (uint)sdn.deviceNumber;
+ }
+
+ internal static string GetDevicePath(SafeFileHandle fd)
+ {
+ uint devNumber = GetDeviceNumber(fd);
+
+ if(devNumber == uint.MaxValue)
+ return null;
+
+ SafeFileHandle hDevInfo = Extern.SetupDiGetClassDevs(ref Consts.GUID_DEVINTERFACE_DISK, IntPtr.Zero,
+ IntPtr.Zero, DeviceGetClassFlags.Present | DeviceGetClassFlags.DeviceInterface);
+
+ if(hDevInfo.IsInvalid)
+ return null;
+
+ uint index = 0;
+ DeviceInterfaceData spdid = new DeviceInterfaceData();
+ spdid.cbSize = Marshal.SizeOf(spdid);
+
+ byte[] buffer;
+
+ while(true)
+ {
+ buffer = new byte[2048];
+
+ if(!Extern.SetupDiEnumDeviceInterfaces(hDevInfo, IntPtr.Zero, ref Consts.GUID_DEVINTERFACE_DISK, index,
+ ref spdid))
+ break;
+
+ uint size = 0;
+
+ Extern.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref spdid, IntPtr.Zero, 0, ref size, IntPtr.Zero);
+
+ if(size > 0 && size < buffer.Length)
+ {
+ buffer[0] = (byte)(IntPtr.Size == 8 ? IntPtr.Size : IntPtr.Size + Marshal.SystemDefaultCharSize); // Funny...
+
+ IntPtr pspdidd = Marshal.AllocHGlobal(buffer.Length);
+ Marshal.Copy(buffer, 0, pspdidd, buffer.Length);
+
+ bool result =
+ Extern.SetupDiGetDeviceInterfaceDetail(hDevInfo, ref spdid, pspdidd, size, ref size, IntPtr.Zero);
+
+ buffer = new byte[size];
+ Marshal.Copy(pspdidd, buffer, 0, buffer.Length);
+ Marshal.FreeHGlobal(pspdidd);
+
+ if(result)
+ {
+ string devicePath = Encoding.Unicode.GetString(buffer, 4, (int)size - 4);
+ SafeFileHandle hDrive = Extern.CreateFile(devicePath, 0, FileShare.Read | FileShare.Write,
+ IntPtr.Zero, FileMode.OpenExisting, 0, IntPtr.Zero);
+
+ if(!hDrive.IsInvalid)
+ {
+ uint newDeviceNumber = GetDeviceNumber(hDrive);
+
+ if(newDeviceNumber == devNumber)
+ {
+ Extern.CloseHandle(hDrive);
+ return devicePath;
+ }
+ }
+
+ Extern.CloseHandle(hDrive);
+ }
+ }
+
+ index++;
+ }
+
+ Extern.SetupDiDestroyDeviceInfoList(hDevInfo);
+ return null;
+ }
}
}
diff --git a/DiscImageChef.Devices/Windows/Enums.cs b/DiscImageChef.Devices/Windows/Enums.cs
index 5b54fa3b..4e371b82 100644
--- a/DiscImageChef.Devices/Windows/Enums.cs
+++ b/DiscImageChef.Devices/Windows/Enums.cs
@@ -105,7 +105,7 @@ namespace DiscImageChef.Devices.Windows
///
/// FILE_ATTRIBUTE_VIRTUAL
///
- Virtual = 0x10000
+ Virtual = 0x10000,
}
[Flags]
@@ -271,6 +271,7 @@ namespace DiscImageChef.Devices.Windows
IOCTL_SCSI_GET_ADDRESS = 0x41018,
IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400,
IOCTL_IDE_PASS_THROUGH = 0x4D028,
+ IOCTL_STORAGE_GET_DEVICE_NUMBER = 0x2D1080,
}
[Flags]
@@ -349,4 +350,34 @@ namespace DiscImageChef.Devices.Windows
FileBackedVirtual = 0xF,
NVMe = 0x11,
}
+
+ [Flags]
+ enum DeviceGetClassFlags : uint
+ {
+ ///
+ /// DIGCF_DEFAULT
+ ///
+ Default = 0x01,
+ ///
+ /// DIGCF_PRESENT
+ ///
+ Present = 0x02,
+ ///
+ /// DIGCF_ALLCLASSES
+ ///
+ AllClasses = 0x04,
+ ///
+ /// DIGCF_PROFILE
+ ///
+ Profile = 0x08,
+ ///
+ /// DIGCF_DEVICEINTERFACE
+ ///
+ DeviceInterface = 0x10,
+ }
+
+ static class Consts
+ {
+ public static Guid GUID_DEVINTERFACE_DISK = new Guid(0x53F56307, 0xB6BF, 0x11D0, 0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B);
+ }
}
diff --git a/DiscImageChef.Devices/Windows/Extern.cs b/DiscImageChef.Devices/Windows/Extern.cs
index 1356d868..44936be2 100644
--- a/DiscImageChef.Devices/Windows/Extern.cs
+++ b/DiscImageChef.Devices/Windows/Extern.cs
@@ -98,6 +98,49 @@ namespace DiscImageChef.Devices.Windows
IntPtr Overlapped
);
+
+ [DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]
+ internal static extern bool DeviceIoControlGetDeviceNumber(
+ SafeFileHandle hDevice,
+ WindowsIoctl IoControlCode,
+ IntPtr InBuffer,
+ uint nInBufferSize,
+ ref StorageDeviceNumber OutBuffer,
+ uint nOutBufferSize,
+ ref uint pBytesReturned,
+ IntPtr Overlapped
+ );
+
+ [DllImport("setupapi.dll", CharSet = CharSet.Auto)]
+ internal static extern SafeFileHandle SetupDiGetClassDevs(
+ ref Guid ClassGuid,
+ IntPtr Enumerator,
+ IntPtr hwndParent,
+ DeviceGetClassFlags Flags
+ );
+
+ [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern bool SetupDiEnumDeviceInterfaces(
+ SafeFileHandle hDevInfo,
+ IntPtr devInfo,
+ ref Guid interfaceClassGuid,
+ uint memberIndex,
+ ref DeviceInterfaceData deviceInterfaceData
+ );
+
+ [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern bool SetupDiGetDeviceInterfaceDetail(
+ SafeFileHandle hDevInfo,
+ ref DeviceInterfaceData deviceInterfaceData,
+ IntPtr deviceInterfaceDetailData,
+ UInt32 deviceInterfaceDetailDataSize,
+ ref UInt32 requiredSize,
+ IntPtr deviceInfoData
+ );
+
+ [DllImport("setupapi.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern bool SetupDiDestroyDeviceInfoList(SafeFileHandle hDevInfo);
+
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern bool CloseHandle(SafeFileHandle hDevice);
}
diff --git a/DiscImageChef.Devices/Windows/Structs.cs b/DiscImageChef.Devices/Windows/Structs.cs
index c107fd6f..627ccaba 100644
--- a/DiscImageChef.Devices/Windows/Structs.cs
+++ b/DiscImageChef.Devices/Windows/Structs.cs
@@ -212,5 +212,31 @@ namespace DiscImageChef.Devices.Windows
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] DataBuffer;
}
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct StorageDeviceNumber
+ {
+ public int deviceType;
+ public int deviceNumber;
+ public int partitionNumber;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct DeviceInfoData
+ {
+ public int cbSize;
+ public Guid classGuid;
+ public uint devInst;
+ public IntPtr reserved;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ struct DeviceInterfaceData
+ {
+ public int cbSize;
+ public Guid interfaceClassGuid;
+ public uint flags;
+ private IntPtr reserved;
+ }
}