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:
|
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,
|
return Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters,
|
||||||
protocol, ref buffer, timeout, out duration, out sense);
|
protocol, ref buffer, timeout, out duration, out sense);
|
||||||
}
|
}
|
||||||
@@ -177,6 +194,23 @@ namespace DiscImageChef.Devices
|
|||||||
{
|
{
|
||||||
case Interop.PlatformID.Win32NT:
|
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,
|
return Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters,
|
||||||
protocol, ref buffer, timeout, out duration, out sense);
|
protocol, ref buffer, timeout, out duration, out sense);
|
||||||
}
|
}
|
||||||
@@ -210,6 +244,7 @@ namespace DiscImageChef.Devices
|
|||||||
{
|
{
|
||||||
case Interop.PlatformID.Win32NT:
|
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,
|
return Windows.Command.SendAtaCommand((SafeFileHandle)fd, registers, out errorRegisters,
|
||||||
protocol, ref buffer, timeout, out duration, out sense);
|
protocol, ref buffer, timeout, out duration, out sense);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -363,6 +363,124 @@ namespace DiscImageChef.Devices.Windows
|
|||||||
|
|
||||||
return error;
|
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>
|
/// </summary>
|
||||||
IOCTL_SCSI_GET_ADDRESS = 0x41018,
|
IOCTL_SCSI_GET_ADDRESS = 0x41018,
|
||||||
IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400,
|
IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400,
|
||||||
|
IOCTL_IDE_PASS_THROUGH = 0x4D028,
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
|||||||
@@ -84,7 +84,19 @@ namespace DiscImageChef.Devices.Windows
|
|||||||
uint nOutBufferSize,
|
uint nOutBufferSize,
|
||||||
ref uint pBytesReturned,
|
ref uint pBytesReturned,
|
||||||
IntPtr Overlapped
|
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)]
|
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
internal static extern bool CloseHandle(SafeFileHandle hDevice);
|
internal static extern bool CloseHandle(SafeFileHandle hDevice);
|
||||||
|
|||||||
@@ -194,5 +194,23 @@ namespace DiscImageChef.Devices.Windows
|
|||||||
public uint RawPropertiesLength;
|
public uint RawPropertiesLength;
|
||||||
public byte[] RawDeviceProperties;
|
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