mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Added support for ATA commands using Windows 2000/XP undocumented
IOCTL that predates Windows 2003 documented one.
This commit is contained in:
@@ -144,6 +144,23 @@ namespace DiscImageChef.Devices
|
||||
{
|
||||
case Interop.PlatformID.Win32NT:
|
||||
{
|
||||
if(
|
||||
( // Windows XP <= SP1
|
||||
Environment.OSVersion.Version.Major == 5 &&
|
||||
Environment.OSVersion.Version.Minor == 1 &&
|
||||
(Environment.OSVersion.ServicePack == "Service Pack 1" || Environment.OSVersion.ServicePack == "")) ||
|
||||
( // Windows 2000
|
||||
Environment.OSVersion.Version.Major == 5 &&
|
||||
Environment.OSVersion.Version.Minor == 0)
|
||||
)
|
||||
return Windows.Command.SendIdeCommand((SafeFileHandle)fd, registers, out errorRegisters,
|
||||
protocol, ref buffer, timeout, out duration, out sense);
|
||||
// Windows NT 4 or earlier, requires special ATA pass thru SCSI. But DiscImageChef cannot run there (or can it?)
|
||||
if(
|
||||
Environment.OSVersion.Version.Major <= 4
|
||||
)
|
||||
throw new InvalidOperationException("Windows NT 4.0 or earlier is not supported.");
|
||||
|
||||
return Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters,
|
||||
protocol, ref buffer, timeout, out duration, out sense);
|
||||
}
|
||||
@@ -177,6 +194,23 @@ namespace DiscImageChef.Devices
|
||||
{
|
||||
case Interop.PlatformID.Win32NT:
|
||||
{
|
||||
if(
|
||||
( // Windows XP <= SP1
|
||||
Environment.OSVersion.Version.Major == 5 &&
|
||||
Environment.OSVersion.Version.Minor == 1 &&
|
||||
(Environment.OSVersion.ServicePack == "Service Pack 1" || Environment.OSVersion.ServicePack == "")) ||
|
||||
( // Windows 2000
|
||||
Environment.OSVersion.Version.Major == 5 &&
|
||||
Environment.OSVersion.Version.Minor == 0)
|
||||
)
|
||||
return Windows.Command.SendIdeCommand((SafeFileHandle)fd, registers, out errorRegisters,
|
||||
protocol, ref buffer, timeout, out duration, out sense);
|
||||
// Windows NT 4 or earlier, requires special ATA pass thru SCSI. But DiscImageChef cannot run there (or can it?)
|
||||
if(
|
||||
Environment.OSVersion.Version.Major <= 4
|
||||
)
|
||||
throw new InvalidOperationException("Windows NT 4.0 or earlier is not supported.");
|
||||
|
||||
return Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters,
|
||||
protocol, ref buffer, timeout, out duration, out sense);
|
||||
}
|
||||
@@ -210,6 +244,7 @@ namespace DiscImageChef.Devices
|
||||
{
|
||||
case Interop.PlatformID.Win32NT:
|
||||
{
|
||||
// No check for Windows version. A 48-bit ATA disk simply does not work on earlier systems
|
||||
return Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters,
|
||||
protocol, ref buffer, timeout, out duration, out sense);
|
||||
}
|
||||
|
||||
@@ -363,6 +363,124 @@ namespace DiscImageChef.Devices.Windows
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
internal static int SendIdeCommand(SafeFileHandle fd, AtaRegistersCHS registers, out AtaErrorRegistersCHS errorRegisters,
|
||||
AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
{
|
||||
duration = 0;
|
||||
sense = false;
|
||||
errorRegisters = new AtaErrorRegistersCHS();
|
||||
|
||||
if(buffer == null || buffer.Length > 512)
|
||||
return -1;
|
||||
|
||||
IdePassThroughDirect iptd = new IdePassThroughDirect
|
||||
{
|
||||
CurrentTaskFile = new AtaTaskFile
|
||||
{
|
||||
Command = registers.command,
|
||||
CylinderHigh = registers.cylinderHigh,
|
||||
CylinderLow = registers.cylinderLow,
|
||||
DeviceHead = registers.deviceHead,
|
||||
Features = registers.feature,
|
||||
SectorCount = registers.sectorCount,
|
||||
SectorNumber = registers.sector
|
||||
},
|
||||
DataBufferSize = 512,
|
||||
DataBuffer = new byte[512],
|
||||
};
|
||||
|
||||
uint k = 0;
|
||||
int error = 0;
|
||||
|
||||
Array.Copy(buffer, 0, iptd.DataBuffer, 0, buffer.Length);
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
sense = !Extern.DeviceIoControlIde(fd, WindowsIoctl.IOCTL_IDE_PASS_THROUGH, ref iptd, (uint)Marshal.SizeOf(iptd), ref iptd,
|
||||
(uint)Marshal.SizeOf(iptd), ref k, IntPtr.Zero);
|
||||
DateTime end = DateTime.Now;
|
||||
|
||||
if(sense)
|
||||
error = Marshal.GetLastWin32Error();
|
||||
|
||||
buffer = new byte[k - 12];
|
||||
Array.Copy(iptd.DataBuffer, 0, buffer, 0, buffer.Length);
|
||||
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
errorRegisters.command = iptd.CurrentTaskFile.Command;
|
||||
errorRegisters.cylinderHigh = iptd.CurrentTaskFile.CylinderHigh;
|
||||
errorRegisters.cylinderLow = iptd.CurrentTaskFile.CylinderLow;
|
||||
errorRegisters.deviceHead = iptd.CurrentTaskFile.DeviceHead;
|
||||
errorRegisters.error = iptd.CurrentTaskFile.Error;
|
||||
errorRegisters.sector = iptd.CurrentTaskFile.SectorNumber;
|
||||
errorRegisters.sectorCount = iptd.CurrentTaskFile.SectorCount;
|
||||
errorRegisters.status = iptd.CurrentTaskFile.Status;
|
||||
|
||||
sense = errorRegisters.error != 0 || (errorRegisters.status & 0xA5) != 0;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
internal static int SendIdeCommand(SafeFileHandle fd, AtaRegistersLBA28 registers, out AtaErrorRegistersLBA28 errorRegisters,
|
||||
AtaProtocol protocol, ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
{
|
||||
duration = 0;
|
||||
sense = false;
|
||||
errorRegisters = new AtaErrorRegistersLBA28();
|
||||
|
||||
if(buffer == null)
|
||||
return -1;
|
||||
|
||||
uint offsetForBuffer = (uint)(Marshal.SizeOf(typeof(AtaPassThroughDirect)) + Marshal.SizeOf(typeof(uint)));
|
||||
|
||||
IdePassThroughDirect iptd = new IdePassThroughDirect
|
||||
{
|
||||
CurrentTaskFile = new AtaTaskFile
|
||||
{
|
||||
Command = registers.command,
|
||||
CylinderHigh = registers.lbaHigh,
|
||||
CylinderLow = registers.lbaMid,
|
||||
DeviceHead = registers.deviceHead,
|
||||
Features = registers.feature,
|
||||
SectorCount = registers.sectorCount,
|
||||
SectorNumber = registers.lbaLow
|
||||
},
|
||||
DataBufferSize = 512,
|
||||
DataBuffer = new byte[512],
|
||||
};
|
||||
|
||||
uint k = 0;
|
||||
int error = 0;
|
||||
|
||||
Array.Copy(buffer, 0, iptd.DataBuffer, 0, buffer.Length);
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
sense = !Extern.DeviceIoControlIde(fd, WindowsIoctl.IOCTL_IDE_PASS_THROUGH, ref iptd, (uint)Marshal.SizeOf(iptd), ref iptd,
|
||||
(uint)Marshal.SizeOf(iptd), ref k, IntPtr.Zero);
|
||||
DateTime end = DateTime.Now;
|
||||
|
||||
if(sense)
|
||||
error = Marshal.GetLastWin32Error();
|
||||
|
||||
buffer = new byte[k - 12];
|
||||
Array.Copy(iptd.DataBuffer, 0, buffer, 0, buffer.Length);
|
||||
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
errorRegisters.command = iptd.CurrentTaskFile.Command;
|
||||
errorRegisters.lbaHigh = iptd.CurrentTaskFile.CylinderHigh;
|
||||
errorRegisters.lbaMid = iptd.CurrentTaskFile.CylinderLow;
|
||||
errorRegisters.deviceHead = iptd.CurrentTaskFile.DeviceHead;
|
||||
errorRegisters.error = iptd.CurrentTaskFile.Error;
|
||||
errorRegisters.lbaLow = iptd.CurrentTaskFile.SectorNumber;
|
||||
errorRegisters.sectorCount = iptd.CurrentTaskFile.SectorCount;
|
||||
errorRegisters.status = iptd.CurrentTaskFile.Status;
|
||||
|
||||
sense = errorRegisters.error != 0 || (errorRegisters.status & 0xA5) != 0;
|
||||
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -270,6 +270,7 @@ namespace DiscImageChef.Devices.Windows
|
||||
/// </summary>
|
||||
IOCTL_SCSI_GET_ADDRESS = 0x41018,
|
||||
IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400,
|
||||
IOCTL_IDE_PASS_THROUGH = 0x4D028,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
||||
@@ -84,7 +84,19 @@ namespace DiscImageChef.Devices.Windows
|
||||
uint nOutBufferSize,
|
||||
ref uint pBytesReturned,
|
||||
IntPtr Overlapped
|
||||
);
|
||||
);
|
||||
|
||||
[DllImport("Kernel32.dll", SetLastError = true, EntryPoint = "DeviceIoControl", CharSet = CharSet.Auto)]
|
||||
internal static extern bool DeviceIoControlIde(
|
||||
SafeFileHandle hDevice,
|
||||
WindowsIoctl IoControlCode,
|
||||
ref IdePassThroughDirect InBuffer,
|
||||
uint nInBufferSize,
|
||||
ref IdePassThroughDirect OutBuffer,
|
||||
uint nOutBufferSize,
|
||||
ref uint pBytesReturned,
|
||||
IntPtr Overlapped
|
||||
);
|
||||
|
||||
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern bool CloseHandle(SafeFileHandle hDevice);
|
||||
|
||||
@@ -194,5 +194,23 @@ namespace DiscImageChef.Devices.Windows
|
||||
public uint RawPropertiesLength;
|
||||
public byte[] RawDeviceProperties;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
struct IdePassThroughDirect
|
||||
{
|
||||
/// <summary>
|
||||
/// ATA registers
|
||||
/// </summary>
|
||||
public AtaTaskFile CurrentTaskFile;
|
||||
/// <summary>
|
||||
/// Size of data buffer
|
||||
/// </summary>
|
||||
public uint DataBufferSize;
|
||||
/// <summary>
|
||||
/// Data buffer
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
|
||||
public byte[] DataBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user