mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Move OS specific command implementation to OS specific device class.
This commit is contained in:
@@ -51,6 +51,7 @@ using Aaru.Decoders.SCSI;
|
||||
using Aaru.Decoders.Xbox;
|
||||
using Aaru.Devices;
|
||||
using Schemas;
|
||||
using Device = Aaru.Devices.Remote.Device;
|
||||
using PlatformID = Aaru.CommonTypes.Interop.PlatformID;
|
||||
using TrackType = Aaru.CommonTypes.Enums.TrackType;
|
||||
using Version = Aaru.CommonTypes.Interop.Version;
|
||||
@@ -82,7 +83,7 @@ partial class Dump
|
||||
|
||||
if(DetectOS.GetRealPlatformID() != PlatformID.Win32NT)
|
||||
{
|
||||
bool isAdmin = _dev.IsRemote ? _dev.IsRemoteAdmin : DetectOS.IsAdmin;
|
||||
bool isAdmin = _dev is Device remoteDev ? remoteDev.IsAdmin : DetectOS.IsAdmin;
|
||||
|
||||
if(!isAdmin)
|
||||
{
|
||||
|
||||
@@ -114,17 +114,18 @@ public sealed class DumpLog
|
||||
|
||||
_logSw.WriteLine();
|
||||
|
||||
if(dev.IsRemote)
|
||||
if(dev is Aaru.Devices.Remote.Device remoteDev)
|
||||
{
|
||||
_logSw.WriteLine("################# Remote information #################");
|
||||
_logSw.WriteLine("Server: {0}", dev.RemoteApplication);
|
||||
_logSw.WriteLine("Version: {0}", dev.RemoteVersion);
|
||||
_logSw.WriteLine("Server: {0}", remoteDev.RemoteApplication);
|
||||
_logSw.WriteLine("Version: {0}", remoteDev.RemoteVersion);
|
||||
|
||||
_logSw.WriteLine("Operating system: {0} {1}", dev.RemoteOperatingSystem, dev.RemoteOperatingSystemVersion);
|
||||
_logSw.WriteLine("Operating system: {0} {1}", remoteDev.RemoteOperatingSystem,
|
||||
remoteDev.RemoteOperatingSystemVersion);
|
||||
|
||||
_logSw.WriteLine("Architecture: {0}", dev.RemoteArchitecture);
|
||||
_logSw.WriteLine("Protocol version: {0}", dev.RemoteProtocolVersion);
|
||||
_logSw.WriteLine("Running as superuser: {0}", dev.IsRemoteAdmin ? "Yes" : "No");
|
||||
_logSw.WriteLine("Architecture: {0}", remoteDev.RemoteArchitecture);
|
||||
_logSw.WriteLine("Protocol version: {0}", remoteDev.RemoteProtocolVersion);
|
||||
_logSw.WriteLine("Running as superuser: {0}", remoteDev.IsAdmin ? "Yes" : "No");
|
||||
_logSw.WriteLine("######################################################");
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
<Compile Include="Linux\Structs.cs" />
|
||||
<Compile Include="Linux\Enums.cs" />
|
||||
<Compile Include="Enums.cs" />
|
||||
<Compile Include="Remote\Command.cs" />
|
||||
<Compile Include="Remote\Consts.cs" />
|
||||
<Compile Include="Remote\Device.cs" />
|
||||
<Compile Include="Remote\Enums.cs" />
|
||||
@@ -77,7 +78,6 @@
|
||||
<Compile Include="Windows\Enums.cs" />
|
||||
<Compile Include="Windows\Command.cs" />
|
||||
<Compile Include="Linux\Command.cs" />
|
||||
<Compile Include="Command.cs" />
|
||||
<Compile Include="Device\Constructor.cs" />
|
||||
<Compile Include="Device\Variables.cs" />
|
||||
<Compile Include="Device\Destructor.cs" />
|
||||
|
||||
@@ -1,434 +0,0 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Command.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Direct device access.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// High level commands used to directly access devices.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General internal License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General internal License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2022 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
namespace Aaru.Devices;
|
||||
|
||||
using System;
|
||||
using Aaru.CommonTypes.Interop;
|
||||
using Aaru.Decoders.ATA;
|
||||
using Aaru.Devices.Windows;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using PlatformID = Aaru.CommonTypes.Interop.PlatformID;
|
||||
|
||||
static class Command
|
||||
{
|
||||
/// <summary>Sends a SCSI command</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="cdb">SCSI CDB</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="senseBuffer">Buffer with the SCSI sense</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="direction">SCSI command transfer direction</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense">
|
||||
/// <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI
|
||||
/// sense
|
||||
/// </param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendScsiCommand(object fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||
ScsiDirection direction, out double duration, out bool sense)
|
||||
{
|
||||
PlatformID ptId = DetectOS.GetRealPlatformID();
|
||||
|
||||
return SendScsiCommand(ptId, fd, cdb, ref buffer, out senseBuffer, timeout, direction, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <summary>Sends a SCSI command</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="ptId">Platform ID for executing the command</param>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="cdb">SCSI CDB</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="senseBuffer">Buffer with the SCSI sense</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="direction">SCSI command transfer direction</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense">
|
||||
/// <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI
|
||||
/// sense
|
||||
/// </param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendScsiCommand(PlatformID ptId, object fd, byte[] cdb, ref byte[] buffer,
|
||||
out byte[] senseBuffer, uint timeout, ScsiDirection direction,
|
||||
out double duration, out bool sense)
|
||||
{
|
||||
switch(ptId)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
{
|
||||
ScsiIoctlDirection dir;
|
||||
|
||||
switch(direction)
|
||||
{
|
||||
case ScsiDirection.In:
|
||||
dir = ScsiIoctlDirection.In;
|
||||
|
||||
break;
|
||||
case ScsiDirection.Out:
|
||||
dir = ScsiIoctlDirection.Out;
|
||||
|
||||
break;
|
||||
default:
|
||||
dir = ScsiIoctlDirection.Unspecified;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return Windows.Command.SendScsiCommand((SafeFileHandle)fd, cdb, ref buffer, out senseBuffer, timeout,
|
||||
dir, out duration, out sense);
|
||||
}
|
||||
case PlatformID.Linux:
|
||||
{
|
||||
Linux.ScsiIoctlDirection dir;
|
||||
|
||||
switch(direction)
|
||||
{
|
||||
case ScsiDirection.In:
|
||||
dir = Linux.ScsiIoctlDirection.In;
|
||||
|
||||
break;
|
||||
case ScsiDirection.Out:
|
||||
dir = Linux.ScsiIoctlDirection.Out;
|
||||
|
||||
break;
|
||||
case ScsiDirection.Bidirectional:
|
||||
dir = Linux.ScsiIoctlDirection.Unspecified;
|
||||
|
||||
break;
|
||||
case ScsiDirection.None:
|
||||
dir = Linux.ScsiIoctlDirection.None;
|
||||
|
||||
break;
|
||||
default:
|
||||
dir = Linux.ScsiIoctlDirection.Unknown;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return Linux.Command.SendScsiCommand((int)fd, cdb, ref buffer, out senseBuffer, timeout, dir,
|
||||
out duration, out sense);
|
||||
}
|
||||
default: throw new InvalidOperationException($"Platform {ptId} not yet supported.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in CHS format</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(object fd, AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
PlatformID ptId = DetectOS.GetRealPlatformID();
|
||||
|
||||
return SendAtaCommand(ptId, fd, registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout,
|
||||
transferBlocks, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in CHS format</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="ptId">Platform ID for executing the command</param>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(PlatformID ptId, object fd, AtaRegistersChs registers,
|
||||
out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
switch(ptId)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
{
|
||||
if(Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 1 &&
|
||||
Environment.OSVersion.ServicePack is "Service Pack 1" or "" ||
|
||||
Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0)
|
||||
throw new InvalidOperationException("Windows XP or earlier is not supported.");
|
||||
|
||||
// Windows NT 4 or earlier, requires special ATA pass thru SCSI. But Aaru 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);
|
||||
}
|
||||
case PlatformID.Linux:
|
||||
{
|
||||
return Linux.Command.SendAtaCommand((int)fd, registers, out errorRegisters, protocol, transferRegister,
|
||||
ref buffer, timeout, transferBlocks, out duration, out sense);
|
||||
}
|
||||
default: throw new InvalidOperationException($"Platform {ptId} not yet supported.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in CHS format</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(object fd, AtaRegistersLba28 registers,
|
||||
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
PlatformID ptId = DetectOS.GetRealPlatformID();
|
||||
|
||||
return SendAtaCommand(ptId, fd, registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout,
|
||||
transferBlocks, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in 28-bit LBA format</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="ptId">Platform ID for executing the command</param>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(PlatformID ptId, object fd, AtaRegistersLba28 registers,
|
||||
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
switch(ptId)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
{
|
||||
if(Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 1 &&
|
||||
Environment.OSVersion.ServicePack is "Service Pack 1" or "" ||
|
||||
Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor == 0)
|
||||
throw new InvalidOperationException("Windows XP or earlier is not supported.");
|
||||
|
||||
// Windows NT 4 or earlier, requires special ATA pass thru SCSI. But Aaru 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);
|
||||
}
|
||||
case PlatformID.Linux:
|
||||
{
|
||||
return Linux.Command.SendAtaCommand((int)fd, registers, out errorRegisters, protocol, transferRegister,
|
||||
ref buffer, timeout, transferBlocks, out duration, out sense);
|
||||
}
|
||||
default: throw new InvalidOperationException($"Platform {ptId} not yet supported.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in 48-bit LBA format</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(object fd, AtaRegistersLba48 registers,
|
||||
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
PlatformID ptId = DetectOS.GetRealPlatformID();
|
||||
|
||||
return SendAtaCommand(ptId, fd, registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout,
|
||||
transferBlocks, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in 48-bit format</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="ptId">Platform ID for executing the command</param>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to the device</param>
|
||||
/// <param name="errorRegisters">Registers returned by the device</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">What register contains the transfer length</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer length is in block, otherwise it is in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendAtaCommand(PlatformID ptId, object fd, AtaRegistersLba48 registers,
|
||||
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
switch(ptId)
|
||||
{
|
||||
case 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);
|
||||
case PlatformID.Linux:
|
||||
return Linux.Command.SendAtaCommand((int)fd, registers, out errorRegisters, protocol, transferRegister,
|
||||
ref buffer, timeout, transferBlocks, out duration, out sense);
|
||||
default: throw new InvalidOperationException($"Platform {ptId} not yet supported.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Sends a MMC/SD command</summary>
|
||||
/// <returns>The result of the command.</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="command">MMC/SD opcode</param>
|
||||
/// <param name="buffer">Buffer for MMC/SD command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if MMC/SD returned non-OK status</param>
|
||||
/// <param name="write"><c>True</c> if data is sent from host to card</param>
|
||||
/// <param name="isApplication"><c>True</c> if command should be preceded with CMD55</param>
|
||||
/// <param name="flags">Flags indicating kind and place of response</param>
|
||||
/// <param name="blocks">How many blocks to transfer</param>
|
||||
/// <param name="argument">Command argument</param>
|
||||
/// <param name="response">Response registers</param>
|
||||
/// <param name="blockSize">Size of block in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendMmcCommand(object fd, MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||
uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||
out uint[] response, out double duration, out bool sense, uint timeout = 0)
|
||||
{
|
||||
PlatformID ptId = DetectOS.GetRealPlatformID();
|
||||
|
||||
return SendMmcCommand(ptId, (int)fd, command, write, isApplication, flags, argument, blockSize, blocks,
|
||||
ref buffer, out response, out duration, out sense, timeout);
|
||||
}
|
||||
|
||||
/// <summary>Sends a MMC/SD command</summary>
|
||||
/// <returns>The result of the command.</returns>
|
||||
/// <param name="ptId">Platform ID for executing the command</param>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="command">MMC/SD opcode</param>
|
||||
/// <param name="buffer">Buffer for MMC/SD command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if MMC/SD returned non-OK status</param>
|
||||
/// <param name="write"><c>True</c> if data is sent from host to card</param>
|
||||
/// <param name="isApplication"><c>True</c> if command should be preceded with CMD55</param>
|
||||
/// <param name="flags">Flags indicating kind and place of response</param>
|
||||
/// <param name="blocks">How many blocks to transfer</param>
|
||||
/// <param name="argument">Command argument</param>
|
||||
/// <param name="response">Response registers</param>
|
||||
/// <param name="blockSize">Size of block in bytes</param>
|
||||
/// <exception cref="InvalidOperationException">If the specified platform is not supported</exception>
|
||||
internal static int SendMmcCommand(PlatformID ptId, object fd, MmcCommands command, bool write, bool isApplication,
|
||||
MmcFlags flags, uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||
out uint[] response, out double duration, out bool sense, uint timeout = 0)
|
||||
{
|
||||
switch(ptId)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
return Windows.Command.SendMmcCommand((SafeFileHandle)fd, command, write, isApplication, flags,
|
||||
argument, blockSize, blocks, ref buffer, out response,
|
||||
out duration, out sense, timeout);
|
||||
case PlatformID.Linux:
|
||||
return Linux.Command.SendMmcCommand((int)fd, command, write, isApplication, flags, argument, blockSize,
|
||||
blocks, ref buffer, out response, out duration, out sense, timeout);
|
||||
default: throw new InvalidOperationException($"Platform {ptId} not yet supported.");
|
||||
}
|
||||
}
|
||||
|
||||
internal static int SendMultipleMmcCommands(PlatformID ptId, object fd, Device.MmcSingleCommand[] commands,
|
||||
out double duration, out bool sense, uint timeout = 0)
|
||||
{
|
||||
switch(ptId)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
return Windows.Command.SendMultipleMmcCommands((SafeFileHandle)fd, commands, out duration, out sense,
|
||||
timeout);
|
||||
case PlatformID.Linux:
|
||||
return Linux.Command.SendMultipleMmcCommands((int)fd, commands, out duration, out sense, timeout);
|
||||
default: throw new InvalidOperationException($"Platform {ptId} not yet supported.");
|
||||
}
|
||||
}
|
||||
|
||||
internal static int ReOpen(PlatformID ptId, string devicePath, object fd, out object newFd)
|
||||
{
|
||||
switch(ptId)
|
||||
{
|
||||
case PlatformID.Win32NT: return Windows.Command.ReOpen(devicePath, (SafeFileHandle)fd, out newFd);
|
||||
case PlatformID.Linux: return Linux.Command.ReOpen(devicePath, (int)fd, out newFd);
|
||||
default: throw new InvalidOperationException($"Platform {ptId} not yet supported.");
|
||||
}
|
||||
}
|
||||
|
||||
internal static int BufferedOsRead(PlatformID ptId, object fd, out byte[] buffer, long offset, uint length,
|
||||
out double duration)
|
||||
{
|
||||
switch(ptId)
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
return Windows.Command.BufferedOsRead((SafeFileHandle)fd, out buffer, offset, length, out duration);
|
||||
case PlatformID.Linux:
|
||||
return Linux.Command.BufferedOsRead((int)fd, out buffer, offset, length, out duration);
|
||||
default: throw new InvalidOperationException($"Platform {ptId} not yet supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,6 @@
|
||||
|
||||
namespace Aaru.Devices;
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Aaru.Decoders.ATA;
|
||||
|
||||
@@ -51,19 +50,14 @@ public partial class Device
|
||||
/// <c>True</c> if SCSI command returned non-OK status and <paramref name="senseBuffer" /> contains
|
||||
/// SCSI sense
|
||||
/// </param>
|
||||
public int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||
ScsiDirection direction, out double duration, out bool sense)
|
||||
public virtual int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||
ScsiDirection direction, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
duration = 0;
|
||||
sense = true;
|
||||
senseBuffer = null;
|
||||
|
||||
if(!(_remote is null))
|
||||
return _remote.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, direction, out duration,
|
||||
out sense);
|
||||
|
||||
return Command.SendScsiCommand(PlatformId, FileHandle, cdb, ref buffer, out senseBuffer, timeout, direction,
|
||||
out duration, out sense);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA/ATAPI command to this device using CHS addressing</summary>
|
||||
@@ -80,20 +74,15 @@ public partial class Device
|
||||
/// </param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA/ATAPI command returned non-OK status</param>
|
||||
public int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol,
|
||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
||||
bool transferBlocks, out double duration, out bool sense)
|
||||
public virtual int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
duration = 0;
|
||||
sense = true;
|
||||
errorRegisters = default(AtaErrorRegistersChs);
|
||||
|
||||
if(!(_remote is null))
|
||||
return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer,
|
||||
timeout, transferBlocks, out duration, out sense);
|
||||
|
||||
return Command.SendAtaCommand(PlatformId, FileHandle, registers, out errorRegisters, protocol, transferRegister,
|
||||
ref buffer, timeout, transferBlocks, out duration, out sense);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA/ATAPI command to this device using 28-bit LBA addressing</summary>
|
||||
@@ -110,20 +99,15 @@ public partial class Device
|
||||
/// </param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA/ATAPI command returned non-OK status</param>
|
||||
public int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
public virtual int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
errorRegisters = default(AtaErrorRegistersLba28);
|
||||
duration = 0;
|
||||
sense = true;
|
||||
|
||||
if(!(_remote is null))
|
||||
return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer,
|
||||
timeout, transferBlocks, out duration, out sense);
|
||||
|
||||
return Command.SendAtaCommand(PlatformId, FileHandle, registers, out errorRegisters, protocol, transferRegister,
|
||||
ref buffer, timeout, transferBlocks, out duration, out sense);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA/ATAPI command to this device using 48-bit LBA addressing</summary>
|
||||
@@ -140,20 +124,15 @@ public partial class Device
|
||||
/// </param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA/ATAPI command returned non-OK status</param>
|
||||
public int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
public virtual int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
errorRegisters = default(AtaErrorRegistersLba48);
|
||||
duration = 0;
|
||||
sense = true;
|
||||
|
||||
if(!(_remote is null))
|
||||
return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer,
|
||||
timeout, transferBlocks, out duration, out sense);
|
||||
|
||||
return Command.SendAtaCommand(PlatformId, FileHandle, registers, out errorRegisters, protocol, transferRegister,
|
||||
ref buffer, timeout, transferBlocks, out duration, out sense);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>Sends a MMC/SD command to this device</summary>
|
||||
@@ -170,74 +149,15 @@ public partial class Device
|
||||
/// <param name="argument">Command argument</param>
|
||||
/// <param name="response">Response registers</param>
|
||||
/// <param name="blockSize">Size of block in bytes</param>
|
||||
public int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, uint argument,
|
||||
uint blockSize, uint blocks, ref byte[] buffer, out uint[] response, out double duration,
|
||||
out bool sense, uint timeout = 15)
|
||||
public virtual int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||
uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||
out uint[] response, out double duration, out bool sense, uint timeout = 15)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
response = null;
|
||||
duration = 0;
|
||||
sense = true;
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case MmcCommands.SendCid when _cachedCid != null:
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
buffer = new byte[_cachedCid.Length];
|
||||
Array.Copy(_cachedCid, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
DateTime end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case MmcCommands.SendCsd when _cachedCid != null:
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
buffer = new byte[_cachedCsd.Length];
|
||||
Array.Copy(_cachedCsd, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
DateTime end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null:
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
buffer = new byte[_cachedScr.Length];
|
||||
Array.Copy(_cachedScr, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
DateTime end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null:
|
||||
case MmcCommands.SendOpCond when _cachedOcr != null:
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
buffer = new byte[_cachedOcr.Length];
|
||||
Array.Copy(_cachedOcr, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
DateTime end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return _remote is null
|
||||
? Command.SendMmcCommand(PlatformId, FileHandle, command, write, isApplication, flags, argument,
|
||||
blockSize, blocks, ref buffer, out response, out duration, out sense,
|
||||
timeout) : _remote.SendMmcCommand(command, write, isApplication, flags,
|
||||
argument, blockSize, blocks, ref buffer,
|
||||
out response, out duration, out sense,
|
||||
timeout);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>Encapsulates a single MMC command to send in a queue</summary>
|
||||
@@ -273,59 +193,18 @@ public partial class Device
|
||||
/// <param name="sense">Set to <c>true</c> if any of the commands returned an error status, <c>false</c> otherwise</param>
|
||||
/// <param name="timeout">Maximum allowed time to execute a single command</param>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
public int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense,
|
||||
uint timeout = 15)
|
||||
public virtual int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense,
|
||||
uint timeout = 15)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
if(_remote is null)
|
||||
return Command.SendMultipleMmcCommands(PlatformId, FileHandle, commands, out duration, out sense, timeout);
|
||||
|
||||
if(_remote.ServerProtocolVersion >= 2)
|
||||
return _remote.SendMultipleMmcCommands(commands, out duration, out sense, timeout);
|
||||
|
||||
var error = 0;
|
||||
duration = 0;
|
||||
sense = false;
|
||||
sense = true;
|
||||
|
||||
foreach(MmcSingleCommand command in commands)
|
||||
{
|
||||
int singleError = _remote.SendMmcCommand(command.command, command.write, command.isApplication,
|
||||
command.flags, command.argument, command.blockSize, command.blocks,
|
||||
ref command.buffer, out command.response, out double cmdDuration,
|
||||
out bool cmdSense, timeout);
|
||||
|
||||
if(error == 0 &&
|
||||
singleError != 0)
|
||||
error = singleError;
|
||||
|
||||
duration += cmdDuration;
|
||||
|
||||
if(cmdSense)
|
||||
sense = true;
|
||||
}
|
||||
|
||||
return error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>Closes then immediately reopens a device</summary>
|
||||
/// <returns>Returned error number if any</returns>
|
||||
public bool ReOpen()
|
||||
{
|
||||
if(!(_remote is null))
|
||||
return _remote.ReOpen();
|
||||
|
||||
int ret = Command.ReOpen(PlatformId, _devicePath, FileHandle, out object newFileHandle);
|
||||
|
||||
FileHandle = newFileHandle;
|
||||
|
||||
Error = ret != 0;
|
||||
LastError = ret;
|
||||
|
||||
return Error;
|
||||
}
|
||||
public virtual bool ReOpen() => false;
|
||||
|
||||
/// <summary>Reads data using operating system buffers.</summary>
|
||||
/// <param name="buffer">Data buffer</param>
|
||||
@@ -333,16 +212,11 @@ public partial class Device
|
||||
/// <param name="length">Number of bytes to read</param>
|
||||
/// <param name="duration">Total time in milliseconds the reading took</param>
|
||||
/// <returns><c>true</c> if there was an error, <c>false</c> otherwise</returns>
|
||||
public bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration)
|
||||
public virtual bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration)
|
||||
{
|
||||
if(!(_remote is null))
|
||||
return _remote.BufferedOsRead(out buffer, offset, length, out duration);
|
||||
buffer = null;
|
||||
duration = 0;
|
||||
|
||||
int ret = Command.BufferedOsRead(PlatformId, FileHandle, out buffer, offset, length, out duration);
|
||||
|
||||
Error = ret != 0;
|
||||
LastError = ret;
|
||||
|
||||
return Error;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -55,10 +55,6 @@ public partial class Device
|
||||
/// <value>The Platform ID</value>
|
||||
public PlatformID PlatformId { get; private protected set; }
|
||||
|
||||
/// <summary>Gets the file handle representing this device</summary>
|
||||
/// <value>The file handle</value>
|
||||
public object FileHandle { get; private protected set; }
|
||||
|
||||
/// <summary>Gets or sets the standard timeout for commands sent to this device</summary>
|
||||
/// <value>The timeout in seconds</value>
|
||||
public uint Timeout { get; set; }
|
||||
@@ -162,33 +158,5 @@ public partial class Device
|
||||
/// <summary>Contains the PCMCIA CIS if applicable</summary>
|
||||
public byte[] Cis { get; private protected set; }
|
||||
|
||||
private protected Remote.Remote _remote;
|
||||
bool? _isRemoteAdmin;
|
||||
private protected string _devicePath;
|
||||
|
||||
/// <summary>Returns if remote is running under administrative (aka root) privileges</summary>
|
||||
public bool IsRemoteAdmin
|
||||
{
|
||||
get
|
||||
{
|
||||
_isRemoteAdmin ??= _remote.IsRoot;
|
||||
|
||||
return _isRemoteAdmin == true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Current device is remote</summary>
|
||||
public bool IsRemote => _remote != null;
|
||||
/// <summary>Remote application</summary>
|
||||
public string RemoteApplication => _remote?.ServerApplication;
|
||||
/// <summary>Remote application server</summary>
|
||||
public string RemoteVersion => _remote?.ServerVersion;
|
||||
/// <summary>Remote operating system name</summary>
|
||||
public string RemoteOperatingSystem => _remote?.ServerOperatingSystem;
|
||||
/// <summary>Remote operating system version</summary>
|
||||
public string RemoteOperatingSystemVersion => _remote?.ServerOperatingSystemVersion;
|
||||
/// <summary>Remote architecture</summary>
|
||||
public string RemoteArchitecture => _remote?.ServerArchitecture;
|
||||
/// <summary>Remote protocol version</summary>
|
||||
public int RemoteProtocolVersion => _remote?.ServerProtocolVersion ?? 0;
|
||||
}
|
||||
@@ -39,24 +39,16 @@ using System.Text;
|
||||
using Aaru.CommonTypes.Interop;
|
||||
using Aaru.Decoders.ATA;
|
||||
|
||||
static class Command
|
||||
partial class Device
|
||||
{
|
||||
/// <summary>Sends a SCSI command</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="cdb">SCSI CDB</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="senseBuffer">Buffer with the SCSI sense</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="direction">SCSI command transfer direction</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense">
|
||||
/// <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI
|
||||
/// sense
|
||||
/// </param>
|
||||
internal static int SendScsiCommand(int fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||
ScsiIoctlDirection direction, out double duration, out bool sense)
|
||||
/// <inheritdoc />
|
||||
public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||
ScsiDirection direction, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
senseBuffer = null;
|
||||
duration = 0;
|
||||
sense = false;
|
||||
@@ -64,6 +56,32 @@ static class Command
|
||||
if(buffer == null)
|
||||
return -1;
|
||||
|
||||
ScsiIoctlDirection dir;
|
||||
|
||||
switch(direction)
|
||||
{
|
||||
case ScsiDirection.In:
|
||||
dir = ScsiIoctlDirection.In;
|
||||
|
||||
break;
|
||||
case ScsiDirection.Out:
|
||||
dir = ScsiIoctlDirection.Out;
|
||||
|
||||
break;
|
||||
case ScsiDirection.Bidirectional:
|
||||
dir = ScsiIoctlDirection.Unspecified;
|
||||
|
||||
break;
|
||||
case ScsiDirection.None:
|
||||
dir = ScsiIoctlDirection.None;
|
||||
|
||||
break;
|
||||
default:
|
||||
dir = ScsiIoctlDirection.Unknown;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
var ioHdr = new SgIoHdrT();
|
||||
|
||||
senseBuffer = new byte[64];
|
||||
@@ -71,7 +89,7 @@ static class Command
|
||||
ioHdr.interface_id = 'S';
|
||||
ioHdr.cmd_len = (byte)cdb.Length;
|
||||
ioHdr.mx_sb_len = (byte)senseBuffer.Length;
|
||||
ioHdr.dxfer_direction = direction;
|
||||
ioHdr.dxfer_direction = dir;
|
||||
ioHdr.dxfer_len = (uint)buffer.Length;
|
||||
ioHdr.dxferp = Marshal.AllocHGlobal(buffer.Length);
|
||||
ioHdr.cmdp = Marshal.AllocHGlobal(cdb.Length);
|
||||
@@ -84,7 +102,7 @@ static class Command
|
||||
Marshal.Copy(senseBuffer, 0, ioHdr.sbp, senseBuffer.Length);
|
||||
|
||||
DateTime start = DateTime.UtcNow;
|
||||
int error = Extern.ioctlSg(fd, LinuxIoctl.SgIo, ref ioHdr);
|
||||
int error = Extern.ioctlSg(_fileDescriptor, LinuxIoctl.SgIo, ref ioHdr);
|
||||
DateTime end = DateTime.UtcNow;
|
||||
|
||||
if(error < 0)
|
||||
@@ -108,7 +126,7 @@ static class Command
|
||||
/// <summary>Converts ATA protocol to SG_IO direction</summary>
|
||||
/// <param name="protocol">ATA protocol</param>
|
||||
/// <returns>SG_IO direction</returns>
|
||||
static ScsiIoctlDirection AtaProtocolToScsiDirection(AtaProtocol protocol)
|
||||
static ScsiDirection AtaProtocolToScsiDirection(AtaProtocol protocol)
|
||||
{
|
||||
switch(protocol)
|
||||
{
|
||||
@@ -117,31 +135,24 @@ static class Command
|
||||
case AtaProtocol.HardReset:
|
||||
case AtaProtocol.NonData:
|
||||
case AtaProtocol.SoftReset:
|
||||
case AtaProtocol.ReturnResponse: return ScsiIoctlDirection.None;
|
||||
case AtaProtocol.ReturnResponse: return ScsiDirection.None;
|
||||
case AtaProtocol.PioIn:
|
||||
case AtaProtocol.UDmaIn: return ScsiIoctlDirection.In;
|
||||
case AtaProtocol.UDmaIn: return ScsiDirection.In;
|
||||
case AtaProtocol.PioOut:
|
||||
case AtaProtocol.UDmaOut: return ScsiIoctlDirection.Out;
|
||||
default: return ScsiIoctlDirection.Unspecified;
|
||||
case AtaProtocol.UDmaOut: return ScsiDirection.Out;
|
||||
default: return ScsiDirection.Unspecified;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in CHS mode</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">Which register contains the transfer count</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
|
||||
internal static int SendAtaCommand(int fd, AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||
/// <inheritdoc />
|
||||
public override int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
duration = 0;
|
||||
sense = false;
|
||||
errorRegisters = new AtaErrorRegistersChs();
|
||||
@@ -185,7 +196,7 @@ static class Command
|
||||
cdb[13] = registers.DeviceHead;
|
||||
cdb[14] = registers.Command;
|
||||
|
||||
int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout,
|
||||
int error = SendScsiCommand(cdb, ref buffer, out byte[] senseBuffer, timeout,
|
||||
AtaProtocolToScsiDirection(protocol), out duration, out sense);
|
||||
|
||||
if(senseBuffer.Length < 22 ||
|
||||
@@ -206,22 +217,15 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in 28-bit LBA mode</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">Which register contains the transfer count</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
|
||||
internal static int SendAtaCommand(int fd, AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
||||
/// <inheritdoc />
|
||||
public override int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
duration = 0;
|
||||
sense = false;
|
||||
errorRegisters = new AtaErrorRegistersLba28();
|
||||
@@ -265,7 +269,7 @@ static class Command
|
||||
cdb[13] = registers.DeviceHead;
|
||||
cdb[14] = registers.Command;
|
||||
|
||||
int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout,
|
||||
int error = SendScsiCommand(cdb, ref buffer, out byte[] senseBuffer, timeout,
|
||||
AtaProtocolToScsiDirection(protocol), out duration, out sense);
|
||||
|
||||
if(senseBuffer.Length < 22 ||
|
||||
@@ -286,22 +290,15 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in 48-bit LBA mode</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
/// <param name="transferRegister">Which register contains the transfer count</param>
|
||||
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
|
||||
internal static int SendAtaCommand(int fd, AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
||||
/// <inheritdoc />
|
||||
public override int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
duration = 0;
|
||||
sense = false;
|
||||
errorRegisters = new AtaErrorRegistersLba48();
|
||||
@@ -351,7 +348,7 @@ static class Command
|
||||
cdb[13] = registers.DeviceHead;
|
||||
cdb[14] = registers.Command;
|
||||
|
||||
int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout,
|
||||
int error = SendScsiCommand(cdb, ref buffer, out byte[] senseBuffer, timeout,
|
||||
AtaProtocolToScsiDirection(protocol), out duration, out sense);
|
||||
|
||||
if(senseBuffer.Length < 22 ||
|
||||
@@ -377,25 +374,71 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>Sends a MMC/SD command</summary>
|
||||
/// <returns>The result of the command.</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="command">MMC/SD opcode</param>
|
||||
/// <param name="buffer">Buffer for MMC/SD command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if MMC/SD returned non-OK status</param>
|
||||
/// <param name="write"><c>True</c> if data is sent from host to card</param>
|
||||
/// <param name="isApplication"><c>True</c> if command should be preceded with CMD55</param>
|
||||
/// <param name="flags">Flags indicating kind and place of response</param>
|
||||
/// <param name="blocks">How many blocks to transfer</param>
|
||||
/// <param name="argument">Command argument</param>
|
||||
/// <param name="response">Response registers</param>
|
||||
/// <param name="blockSize">Size of block in bytes</param>
|
||||
internal static int SendMmcCommand(int fd, MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||
/// <inheritdoc />
|
||||
public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||
uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||
out uint[] response, out double duration, out bool sense, uint timeout = 0)
|
||||
out uint[] response, out double duration, out bool sense, uint timeout = 15)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
DateTime start;
|
||||
DateTime end;
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case MmcCommands.SendCid when _cachedCid != null:
|
||||
{
|
||||
start = DateTime.Now;
|
||||
buffer = new byte[_cachedCid.Length];
|
||||
Array.Copy(_cachedCid, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case MmcCommands.SendCsd when _cachedCid != null:
|
||||
{
|
||||
start = DateTime.Now;
|
||||
buffer = new byte[_cachedCsd.Length];
|
||||
Array.Copy(_cachedCsd, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null:
|
||||
{
|
||||
start = DateTime.Now;
|
||||
buffer = new byte[_cachedScr.Length];
|
||||
Array.Copy(_cachedScr, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null:
|
||||
case MmcCommands.SendOpCond when _cachedOcr != null:
|
||||
{
|
||||
start = DateTime.Now;
|
||||
buffer = new byte[_cachedOcr.Length];
|
||||
Array.Copy(_cachedOcr, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
response = null;
|
||||
duration = 0;
|
||||
sense = false;
|
||||
@@ -425,9 +468,9 @@ static class Command
|
||||
|
||||
Marshal.Copy(buffer, 0, bufPtr, buffer.Length);
|
||||
|
||||
DateTime start = DateTime.UtcNow;
|
||||
int error = Extern.ioctlMmc(fd, LinuxIoctl.MmcIocCmd, ref ioCmd);
|
||||
DateTime end = DateTime.UtcNow;
|
||||
start = DateTime.UtcNow;
|
||||
int error = Extern.ioctlMmc(_fileDescriptor, LinuxIoctl.MmcIocCmd, ref ioCmd);
|
||||
end = DateTime.UtcNow;
|
||||
|
||||
sense |= error < 0;
|
||||
|
||||
@@ -444,9 +487,14 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
internal static int SendMultipleMmcCommands(int fd, Device.MmcSingleCommand[] commands, out double duration,
|
||||
out bool sense, uint timeout = 0)
|
||||
/// <inheritdoc />
|
||||
public override int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense,
|
||||
uint timeout = 15)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
duration = 0;
|
||||
sense = false;
|
||||
int off;
|
||||
@@ -506,7 +554,7 @@ static class Command
|
||||
|
||||
// Send command
|
||||
DateTime start = DateTime.UtcNow;
|
||||
int error = Extern.ioctlMmcMulti(fd, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr);
|
||||
int error = Extern.ioctlMmcMulti(_fileDescriptor, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr);
|
||||
DateTime end = DateTime.UtcNow;
|
||||
|
||||
sense |= error < 0;
|
||||
@@ -549,35 +597,61 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
internal static int ReOpen(string devicePath, int fd, out object newFd)
|
||||
{
|
||||
newFd = -1;
|
||||
/// <inheritdoc />
|
||||
public override bool ReOpen()
|
||||
|
||||
int ret = Extern.close(fd);
|
||||
{
|
||||
int ret = Extern.close(_fileDescriptor);
|
||||
|
||||
if(ret < 0)
|
||||
return Marshal.GetLastWin32Error();
|
||||
{
|
||||
LastError = Marshal.GetLastWin32Error();
|
||||
Error = true;
|
||||
|
||||
newFd = Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew);
|
||||
return true;
|
||||
}
|
||||
|
||||
if((int)newFd >= 0)
|
||||
return 0;
|
||||
int newFd = Extern.open(_devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew);
|
||||
|
||||
if(newFd >= 0)
|
||||
{
|
||||
Error = false;
|
||||
_fileDescriptor = newFd;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int error = Marshal.GetLastWin32Error();
|
||||
|
||||
if(error != 13 &&
|
||||
error != 30)
|
||||
return Marshal.GetLastWin32Error();
|
||||
{
|
||||
LastError = Marshal.GetLastWin32Error();
|
||||
Error = true;
|
||||
|
||||
newFd = Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking);
|
||||
return true;
|
||||
}
|
||||
|
||||
return (int)newFd < 0 ? Marshal.GetLastWin32Error() : 0;
|
||||
newFd = Extern.open(_devicePath, FileFlags.Readonly | FileFlags.NonBlocking);
|
||||
|
||||
if(newFd < 0)
|
||||
{
|
||||
LastError = Marshal.GetLastWin32Error();
|
||||
Error = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Error = false;
|
||||
_fileDescriptor = newFd;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>Reads the contents of a symbolic link</summary>
|
||||
/// <param name="path">Path to the symbolic link</param>
|
||||
/// <returns>Contents of the symbolic link</returns>
|
||||
internal static string ReadLink(string path)
|
||||
static string ReadLink(string path)
|
||||
{
|
||||
IntPtr buf = Marshal.AllocHGlobal(4096);
|
||||
int resultSize;
|
||||
@@ -608,13 +682,15 @@ static class Command
|
||||
return Encoding.ASCII.GetString(resultString);
|
||||
}
|
||||
|
||||
internal static int BufferedOsRead(int fd, out byte[] buffer, long offset, uint length, out double duration)
|
||||
/// <inheritdoc />
|
||||
public override bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration)
|
||||
|
||||
{
|
||||
buffer = new byte[length];
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
long sense = Extern.lseek(fd, offset, SeekWhence.Begin);
|
||||
long sense = Extern.lseek(_fileDescriptor, offset, SeekWhence.Begin);
|
||||
|
||||
DateTime end = DateTime.Now;
|
||||
|
||||
@@ -622,10 +698,14 @@ static class Command
|
||||
{
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return Marshal.GetLastWin32Error();
|
||||
Error = true;
|
||||
LastError = Marshal.GetLastWin32Error();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sense = DetectOS.Is64Bit ? Extern.read64(fd, buffer, length) : Extern.read(fd, buffer, (int)length);
|
||||
sense = DetectOS.Is64Bit ? Extern.read64(_fileDescriptor, buffer, length)
|
||||
: Extern.read(_fileDescriptor, buffer, (int)length);
|
||||
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
@@ -637,6 +717,9 @@ static class Command
|
||||
else if(errno == 0)
|
||||
errno = -22;
|
||||
|
||||
return errno;
|
||||
LastError = errno;
|
||||
Error = errno == 0;
|
||||
|
||||
return errno != 0;
|
||||
}
|
||||
}
|
||||
@@ -46,31 +46,34 @@ using VendorString = Aaru.Decoders.MMC.VendorString;
|
||||
|
||||
/// <inheritdoc />
|
||||
[SupportedOSPlatform("linux")]
|
||||
public class Device : Devices.Device
|
||||
partial class Device : Devices.Device
|
||||
{
|
||||
/// <summary>Gets the file handle representing this device</summary>
|
||||
/// <value>The file handle</value>
|
||||
int _fileDescriptor;
|
||||
|
||||
Device() {}
|
||||
|
||||
public new static Device Create(string devicePath)
|
||||
internal new static Device Create(string devicePath)
|
||||
{
|
||||
var dev = new Device
|
||||
{
|
||||
PlatformId = DetectOS.GetRealPlatformID(),
|
||||
Timeout = 15,
|
||||
Error = false,
|
||||
IsRemovable = false
|
||||
PlatformId = DetectOS.GetRealPlatformID(),
|
||||
Timeout = 15,
|
||||
Error = false,
|
||||
IsRemovable = false,
|
||||
_fileDescriptor = Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew)
|
||||
};
|
||||
|
||||
dev.FileHandle = Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew);
|
||||
|
||||
if((int)dev.FileHandle < 0)
|
||||
if(dev._fileDescriptor < 0)
|
||||
{
|
||||
dev.LastError = Marshal.GetLastWin32Error();
|
||||
|
||||
if(dev.LastError is 13 or 30) // EACCES or EROFS
|
||||
{
|
||||
dev.FileHandle = Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking);
|
||||
dev._fileDescriptor = Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking);
|
||||
|
||||
if((int)dev.FileHandle < 0)
|
||||
if(dev._fileDescriptor < 0)
|
||||
{
|
||||
dev.Error = true;
|
||||
dev.LastError = Marshal.GetLastWin32Error();
|
||||
@@ -92,23 +95,22 @@ public class Device : Devices.Device
|
||||
dev.Type = DeviceType.Unknown;
|
||||
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
||||
|
||||
byte[] ataBuf;
|
||||
byte[] inqBuf = null;
|
||||
|
||||
if(dev.Error)
|
||||
throw new DeviceException(dev.LastError);
|
||||
|
||||
string devPath;
|
||||
|
||||
if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
|
||||
devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
||||
devicePath.StartsWith("/dev/st", StringComparison.Ordinal) ||
|
||||
devicePath.StartsWith("/dev/sg", StringComparison.Ordinal))
|
||||
if(!dev.ScsiInquiry(out inqBuf, out _))
|
||||
if(!dev.ScsiInquiry(out byte[] _, out _))
|
||||
dev.Type = DeviceType.SCSI;
|
||||
|
||||
// MultiMediaCard and SecureDigital go here
|
||||
else if(devicePath.StartsWith("/dev/mmcblk", StringComparison.Ordinal))
|
||||
{
|
||||
string devPath = devicePath.Substring(5);
|
||||
devPath = devicePath[5..];
|
||||
|
||||
if(File.Exists("/sys/block/" + devPath + "/device/csd"))
|
||||
{
|
||||
@@ -179,21 +181,23 @@ public class Device : Devices.Device
|
||||
#endregion SecureDigital / MultiMediaCard
|
||||
|
||||
#region USB
|
||||
string resolvedLink;
|
||||
|
||||
if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
|
||||
devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
||||
devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
|
||||
{
|
||||
string devPath = devicePath.Substring(5);
|
||||
devPath = devicePath[5..];
|
||||
|
||||
if(Directory.Exists("/sys/block/" + devPath))
|
||||
{
|
||||
string resolvedLink = Command.ReadLink("/sys/block/" + devPath);
|
||||
resolvedLink = ReadLink("/sys/block/" + devPath);
|
||||
|
||||
if(!string.IsNullOrEmpty(resolvedLink))
|
||||
{
|
||||
resolvedLink = "/sys" + resolvedLink.Substring(2);
|
||||
resolvedLink = "/sys" + resolvedLink[2..];
|
||||
|
||||
while(resolvedLink.Contains("usb"))
|
||||
while(resolvedLink?.Contains("usb") == true)
|
||||
{
|
||||
resolvedLink = Path.GetDirectoryName(resolvedLink);
|
||||
|
||||
@@ -257,128 +261,121 @@ public class Device : Devices.Device
|
||||
#endregion USB
|
||||
|
||||
#region FireWire
|
||||
{
|
||||
if(true)
|
||||
{
|
||||
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(Directory.Exists("/sys/block/" + devPath))
|
||||
{
|
||||
string resolvedLink = Command.ReadLink("/sys/block/" + devPath);
|
||||
resolvedLink = "/sys" + resolvedLink.Substring(2);
|
||||
|
||||
if(!string.IsNullOrEmpty(resolvedLink))
|
||||
while(resolvedLink.Contains("firewire"))
|
||||
{
|
||||
resolvedLink = Path.GetDirectoryName(resolvedLink);
|
||||
|
||||
if(!File.Exists(resolvedLink + "/model") ||
|
||||
!File.Exists(resolvedLink + "/vendor") ||
|
||||
!File.Exists(resolvedLink + "/guid"))
|
||||
continue;
|
||||
|
||||
var fwSr = new StreamReader(resolvedLink + "/model");
|
||||
string fwTemp = fwSr.ReadToEnd();
|
||||
|
||||
uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out dev._firewireModel);
|
||||
|
||||
fwSr.Close();
|
||||
|
||||
fwSr = new StreamReader(resolvedLink + "/vendor");
|
||||
fwTemp = fwSr.ReadToEnd();
|
||||
|
||||
uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out dev._firewireVendor);
|
||||
|
||||
fwSr.Close();
|
||||
|
||||
fwSr = new StreamReader(resolvedLink + "/guid");
|
||||
fwTemp = fwSr.ReadToEnd();
|
||||
|
||||
ulong.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out dev._firewireGuid);
|
||||
|
||||
fwSr.Close();
|
||||
|
||||
if(File.Exists(resolvedLink + "/model_name"))
|
||||
{
|
||||
fwSr = new StreamReader(resolvedLink + "/model_name");
|
||||
dev.FireWireModelName = fwSr.ReadToEnd().Trim();
|
||||
fwSr.Close();
|
||||
}
|
||||
|
||||
if(File.Exists(resolvedLink + "/vendor_name"))
|
||||
{
|
||||
fwSr = new StreamReader(resolvedLink + "/vendor_name");
|
||||
dev.FireWireVendorName = fwSr.ReadToEnd().Trim();
|
||||
fwSr.Close();
|
||||
}
|
||||
|
||||
dev.IsFireWire = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement for other operating systems
|
||||
else
|
||||
dev.IsFireWire = false;
|
||||
}
|
||||
#endregion FireWire
|
||||
|
||||
#region PCMCIA
|
||||
if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
|
||||
devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
||||
devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
|
||||
{
|
||||
string devPath = devicePath.Substring(5);
|
||||
devPath = devicePath[5..];
|
||||
|
||||
if(Directory.Exists("/sys/block/" + devPath))
|
||||
{
|
||||
string resolvedLink = Command.ReadLink("/sys/block/" + devPath);
|
||||
resolvedLink = "/sys" + resolvedLink.Substring(2);
|
||||
resolvedLink = ReadLink("/sys/block/" + devPath);
|
||||
resolvedLink = "/sys" + resolvedLink[2..];
|
||||
|
||||
if(!string.IsNullOrEmpty(resolvedLink))
|
||||
while(resolvedLink.Contains("/sys/devices"))
|
||||
while(resolvedLink?.Contains("firewire") == true)
|
||||
{
|
||||
resolvedLink = Path.GetDirectoryName(resolvedLink);
|
||||
|
||||
if(!Directory.Exists(resolvedLink + "/pcmcia_socket"))
|
||||
if(!File.Exists(resolvedLink + "/model") ||
|
||||
!File.Exists(resolvedLink + "/vendor") ||
|
||||
!File.Exists(resolvedLink + "/guid"))
|
||||
continue;
|
||||
|
||||
string[] subdirs = Directory.GetDirectories(resolvedLink + "/pcmcia_socket", "pcmcia_socket*",
|
||||
SearchOption.TopDirectoryOnly);
|
||||
var fwSr = new StreamReader(resolvedLink + "/model");
|
||||
string fwTemp = fwSr.ReadToEnd();
|
||||
|
||||
if(subdirs.Length <= 0)
|
||||
continue;
|
||||
uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out dev._firewireModel);
|
||||
|
||||
string possibleDir = Path.Combine(resolvedLink, "pcmcia_socket", subdirs[0]);
|
||||
fwSr.Close();
|
||||
|
||||
if(!File.Exists(possibleDir + "/card_type") ||
|
||||
!File.Exists(possibleDir + "/cis"))
|
||||
continue;
|
||||
fwSr = new StreamReader(resolvedLink + "/vendor");
|
||||
fwTemp = fwSr.ReadToEnd();
|
||||
|
||||
var cisFs = new FileStream(possibleDir + "/cis", FileMode.Open, FileAccess.Read);
|
||||
uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out dev._firewireVendor);
|
||||
|
||||
var cisBuf = new byte[65536];
|
||||
int cisCount = cisFs.Read(cisBuf, 0, 65536);
|
||||
dev.Cis = new byte[cisCount];
|
||||
Array.Copy(cisBuf, 0, dev.Cis, 0, cisCount);
|
||||
cisFs.Close();
|
||||
fwSr.Close();
|
||||
|
||||
dev.IsPcmcia = true;
|
||||
fwSr = new StreamReader(resolvedLink + "/guid");
|
||||
fwTemp = fwSr.ReadToEnd();
|
||||
|
||||
ulong.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out dev._firewireGuid);
|
||||
|
||||
fwSr.Close();
|
||||
|
||||
if(File.Exists(resolvedLink + "/model_name"))
|
||||
{
|
||||
fwSr = new StreamReader(resolvedLink + "/model_name");
|
||||
dev.FireWireModelName = fwSr.ReadToEnd().Trim();
|
||||
fwSr.Close();
|
||||
}
|
||||
|
||||
if(File.Exists(resolvedLink + "/vendor_name"))
|
||||
{
|
||||
fwSr = new StreamReader(resolvedLink + "/vendor_name");
|
||||
dev.FireWireVendorName = fwSr.ReadToEnd().Trim();
|
||||
fwSr.Close();
|
||||
}
|
||||
|
||||
dev.IsFireWire = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion FireWire
|
||||
|
||||
#region PCMCIA
|
||||
if(!devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) &&
|
||||
!devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) &&
|
||||
!devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
|
||||
return dev;
|
||||
|
||||
devPath = devicePath[5..];
|
||||
|
||||
if(!Directory.Exists("/sys/block/" + devPath))
|
||||
return dev;
|
||||
|
||||
resolvedLink = ReadLink("/sys/block/" + devPath);
|
||||
resolvedLink = "/sys" + resolvedLink[2..];
|
||||
|
||||
if(string.IsNullOrEmpty(resolvedLink))
|
||||
return dev;
|
||||
|
||||
while(resolvedLink.Contains("/sys/devices"))
|
||||
{
|
||||
resolvedLink = Path.GetDirectoryName(resolvedLink);
|
||||
|
||||
if(!Directory.Exists(resolvedLink + "/pcmcia_socket"))
|
||||
continue;
|
||||
|
||||
string[] subdirs = Directory.GetDirectories(resolvedLink + "/pcmcia_socket", "pcmcia_socket*",
|
||||
SearchOption.TopDirectoryOnly);
|
||||
|
||||
if(subdirs.Length <= 0)
|
||||
continue;
|
||||
|
||||
string possibleDir = Path.Combine(resolvedLink, "pcmcia_socket", subdirs[0]);
|
||||
|
||||
if(!File.Exists(possibleDir + "/card_type") ||
|
||||
!File.Exists(possibleDir + "/cis"))
|
||||
continue;
|
||||
|
||||
var cisFs = new FileStream(possibleDir + "/cis", FileMode.Open, FileAccess.Read);
|
||||
|
||||
var cisBuf = new byte[65536];
|
||||
int cisCount = cisFs.Read(cisBuf, 0, 65536);
|
||||
dev.Cis = new byte[cisCount];
|
||||
Array.Copy(cisBuf, 0, dev.Cis, 0, cisCount);
|
||||
cisFs.Close();
|
||||
|
||||
dev.IsPcmcia = true;
|
||||
|
||||
break;
|
||||
}
|
||||
#endregion PCMCIA
|
||||
|
||||
return dev;
|
||||
@@ -399,11 +396,11 @@ public class Device : Devices.Device
|
||||
/// <inheritdoc />
|
||||
public override void Close()
|
||||
{
|
||||
if(FileHandle == null)
|
||||
if(_fileDescriptor == 0)
|
||||
return;
|
||||
|
||||
Extern.close((int)FileHandle);
|
||||
Extern.close(_fileDescriptor);
|
||||
|
||||
FileHandle = null;
|
||||
_fileDescriptor = 0;
|
||||
}
|
||||
}
|
||||
199
Aaru.Devices/Remote/Command.cs
Normal file
199
Aaru.Devices/Remote/Command.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Commands.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Direct device access.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Sends commands to devices.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 2.1 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2022 Natalia Portillo
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace Aaru.Devices.Remote;
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Aaru.Decoders.ATA;
|
||||
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
public partial class Device
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||
ScsiDirection direction, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
return _remote.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, direction, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout,
|
||||
transferBlocks, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout,
|
||||
transferBlocks, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, timeout,
|
||||
transferBlocks, out duration, out sense);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||
uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||
out uint[] response, out double duration, out bool sense, uint timeout = 15)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case MmcCommands.SendCid when _cachedCid != null:
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
buffer = new byte[_cachedCid.Length];
|
||||
Array.Copy(_cachedCid, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
DateTime end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case MmcCommands.SendCsd when _cachedCid != null:
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
buffer = new byte[_cachedCsd.Length];
|
||||
Array.Copy(_cachedCsd, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
DateTime end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null:
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
buffer = new byte[_cachedScr.Length];
|
||||
Array.Copy(_cachedScr, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
DateTime end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null:
|
||||
case MmcCommands.SendOpCond when _cachedOcr != null:
|
||||
{
|
||||
DateTime start = DateTime.Now;
|
||||
buffer = new byte[_cachedOcr.Length];
|
||||
Array.Copy(_cachedOcr, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
DateTime end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return _remote.SendMmcCommand(command, write, isApplication, flags, argument, blockSize, blocks, ref buffer,
|
||||
out response, out duration, out sense, timeout);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense,
|
||||
uint timeout = 15)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
if(_remote.ServerProtocolVersion >= 2)
|
||||
return _remote.SendMultipleMmcCommands(commands, out duration, out sense, timeout);
|
||||
|
||||
var error = 0;
|
||||
duration = 0;
|
||||
sense = false;
|
||||
|
||||
foreach(MmcSingleCommand command in commands)
|
||||
{
|
||||
int singleError = _remote.SendMmcCommand(command.command, command.write, command.isApplication,
|
||||
command.flags, command.argument, command.blockSize, command.blocks,
|
||||
ref command.buffer, out command.response, out double cmdDuration,
|
||||
out bool cmdSense, timeout);
|
||||
|
||||
if(error == 0 &&
|
||||
singleError != 0)
|
||||
error = singleError;
|
||||
|
||||
duration += cmdDuration;
|
||||
|
||||
if(cmdSense)
|
||||
sense = true;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool ReOpen() => _remote.ReOpen();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration) =>
|
||||
_remote.BufferedOsRead(out buffer, offset, length, out duration);
|
||||
}
|
||||
@@ -39,14 +39,43 @@ using Aaru.CommonTypes.Structs.Devices.SCSI;
|
||||
using Aaru.Decoders.SecureDigital;
|
||||
|
||||
/// <inheritdoc />
|
||||
public sealed class Device : Devices.Device
|
||||
public sealed partial class Device : Devices.Device
|
||||
{
|
||||
Remote _remote;
|
||||
|
||||
/// <summary>Returns if remote is running under administrative (aka root) privileges</summary>
|
||||
public bool IsAdmin
|
||||
{
|
||||
get
|
||||
{
|
||||
_isRemoteAdmin ??= _remote.IsRoot;
|
||||
|
||||
return _isRemoteAdmin == true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Current device is remote</summary>
|
||||
public bool IsRemote => _remote != null;
|
||||
/// <summary>Remote application</summary>
|
||||
public string RemoteApplication => _remote?.ServerApplication;
|
||||
/// <summary>Remote application server</summary>
|
||||
public string RemoteVersion => _remote?.ServerVersion;
|
||||
/// <summary>Remote operating system name</summary>
|
||||
public string RemoteOperatingSystem => _remote?.ServerOperatingSystem;
|
||||
/// <summary>Remote operating system version</summary>
|
||||
public string RemoteOperatingSystemVersion => _remote?.ServerOperatingSystemVersion;
|
||||
/// <summary>Remote architecture</summary>
|
||||
public string RemoteArchitecture => _remote?.ServerArchitecture;
|
||||
/// <summary>Remote protocol version</summary>
|
||||
public int RemoteProtocolVersion => _remote?.ServerProtocolVersion ?? 0;
|
||||
bool? _isRemoteAdmin;
|
||||
|
||||
Device() {}
|
||||
|
||||
/// <summary>Opens the device for sending direct commands</summary>
|
||||
/// <param name="aaruUri">AaruRemote URI</param>
|
||||
/// <returns>Device</returns>
|
||||
public static Device Create(Uri aaruUri)
|
||||
internal static Device Create(Uri aaruUri)
|
||||
{
|
||||
var dev = new Device
|
||||
{
|
||||
@@ -83,9 +112,6 @@ public sealed class Device : Devices.Device
|
||||
dev.Type = DeviceType.Unknown;
|
||||
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
||||
|
||||
byte[] ataBuf;
|
||||
byte[] inqBuf = null;
|
||||
|
||||
if(dev.Error)
|
||||
throw new DeviceException(dev.LastError);
|
||||
|
||||
@@ -93,11 +119,6 @@ public sealed class Device : Devices.Device
|
||||
|
||||
switch(dev.Type)
|
||||
{
|
||||
case DeviceType.ATAPI:
|
||||
case DeviceType.SCSI:
|
||||
bool scsiSense = dev.ScsiInquiry(out inqBuf, out _);
|
||||
|
||||
break;
|
||||
case DeviceType.SecureDigital:
|
||||
case DeviceType.MMC:
|
||||
if(!dev._remote.GetSdhciRegisters(out dev._cachedCsd, out dev._cachedCid, out dev._cachedOcr,
|
||||
|
||||
@@ -40,24 +40,16 @@ using Aaru.Decoders.ATA;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
[SuppressMessage("ReSharper", "UnusedParameter.Global")]
|
||||
static class Command
|
||||
partial class Device
|
||||
{
|
||||
/// <summary>Sends a SCSI command</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="cdb">SCSI CDB</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="senseBuffer">Buffer with the SCSI sense</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="direction">SCSI command transfer direction</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense">
|
||||
/// <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI
|
||||
/// sense
|
||||
/// </param>
|
||||
internal static int SendScsiCommand(SafeFileHandle fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer,
|
||||
uint timeout, ScsiIoctlDirection direction, out double duration, out bool sense)
|
||||
/// <inheritdoc />
|
||||
public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||
ScsiDirection direction, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
senseBuffer = null;
|
||||
duration = 0;
|
||||
sense = false;
|
||||
@@ -65,6 +57,24 @@ static class Command
|
||||
if(buffer == null)
|
||||
return -1;
|
||||
|
||||
ScsiIoctlDirection dir;
|
||||
|
||||
switch(direction)
|
||||
{
|
||||
case ScsiDirection.In:
|
||||
dir = ScsiIoctlDirection.In;
|
||||
|
||||
break;
|
||||
case ScsiDirection.Out:
|
||||
dir = ScsiIoctlDirection.Out;
|
||||
|
||||
break;
|
||||
default:
|
||||
dir = ScsiIoctlDirection.Unspecified;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
var sptdSb = new ScsiPassThroughDirectAndSenseBuffer
|
||||
{
|
||||
SenseBuf = new byte[32],
|
||||
@@ -73,7 +83,7 @@ static class Command
|
||||
Cdb = new byte[16],
|
||||
CdbLength = (byte)cdb.Length,
|
||||
SenseInfoLength = 32,
|
||||
DataIn = direction,
|
||||
DataIn = dir,
|
||||
DataTransferLength = (uint)buffer.Length,
|
||||
TimeOutValue = timeout,
|
||||
DataBuffer = Marshal.AllocHGlobal(buffer.Length)
|
||||
@@ -91,7 +101,7 @@ static class Command
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
bool hasError = !Extern.DeviceIoControlScsi(fd, WindowsIoctl.IoctlScsiPassThroughDirect, ref sptdSb,
|
||||
bool hasError = !Extern.DeviceIoControlScsi(_fileHandle, WindowsIoctl.IoctlScsiPassThroughDirect, ref sptdSb,
|
||||
(uint)Marshal.SizeOf(sptdSb), ref sptdSb,
|
||||
(uint)Marshal.SizeOf(sptdSb), ref k, IntPtr.Zero);
|
||||
|
||||
@@ -114,20 +124,15 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in CHS mode</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersChs registers,
|
||||
out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol, ref byte[] buffer,
|
||||
uint timeout, out double duration, out bool sense)
|
||||
/// <inheritdoc />
|
||||
public override int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
duration = 0;
|
||||
sense = false;
|
||||
errorRegisters = new AtaErrorRegistersChs();
|
||||
@@ -191,7 +196,7 @@ static class Command
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
|
||||
sense = !Extern.DeviceIoControlAta(_fileHandle, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
|
||||
(uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
|
||||
IntPtr.Zero);
|
||||
|
||||
@@ -219,20 +224,15 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in 28-bit LBA mode</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersLba28 registers,
|
||||
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
/// <inheritdoc />
|
||||
public override int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
duration = 0;
|
||||
sense = false;
|
||||
errorRegisters = new AtaErrorRegistersLba28();
|
||||
@@ -296,7 +296,7 @@ static class Command
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
|
||||
sense = !Extern.DeviceIoControlAta(_fileHandle, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
|
||||
(uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
|
||||
IntPtr.Zero);
|
||||
|
||||
@@ -324,20 +324,15 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
/// <summary>Sends an ATA command in 48-bit LBA mode</summary>
|
||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
||||
/// <param name="registers">Registers to send to drive</param>
|
||||
/// <param name="errorRegisters">Registers returned by drive</param>
|
||||
/// <param name="protocol">ATA protocol to use</param>
|
||||
internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersLba48 registers,
|
||||
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
|
||||
ref byte[] buffer, uint timeout, out double duration, out bool sense)
|
||||
/// <inheritdoc />
|
||||
public override int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
duration = 0;
|
||||
sense = false;
|
||||
errorRegisters = new AtaErrorRegistersLba48();
|
||||
@@ -410,7 +405,7 @@ static class Command
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
|
||||
sense = !Extern.DeviceIoControlAta(_fileHandle, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd,
|
||||
(uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
|
||||
IntPtr.Zero);
|
||||
|
||||
@@ -458,25 +453,67 @@ static class Command
|
||||
queryData1.protocolGuid.Equals(Consts.GuidSffProtocolMmc);
|
||||
}
|
||||
|
||||
/// <summary>Sends a MMC/SD command</summary>
|
||||
/// <returns>The result of the command.</returns>
|
||||
/// <param name="fd">File handle</param>
|
||||
/// <param name="command">MMC/SD opcode</param>
|
||||
/// <param name="buffer">Buffer for MMC/SD command response</param>
|
||||
/// <param name="timeout">Timeout in seconds</param>
|
||||
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
||||
/// <param name="sense"><c>True</c> if MMC/SD returned non-OK status</param>
|
||||
/// <param name="write"><c>True</c> if data is sent from host to card</param>
|
||||
/// <param name="isApplication"><c>True</c> if command should be preceded with CMD55</param>
|
||||
/// <param name="flags">Flags indicating kind and place of response</param>
|
||||
/// <param name="blocks">How many blocks to transfer</param>
|
||||
/// <param name="argument">Command argument</param>
|
||||
/// <param name="response">Response registers</param>
|
||||
/// <param name="blockSize">Size of block in bytes</param>
|
||||
internal static int SendMmcCommand(SafeFileHandle fd, MmcCommands command, bool write, bool isApplication,
|
||||
MmcFlags flags, uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||
out uint[] response, out double duration, out bool sense, uint timeout = 0)
|
||||
/// <inheritdoc />
|
||||
public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||
uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||
out uint[] response, out double duration, out bool sense, uint timeout = 15)
|
||||
{
|
||||
DateTime start;
|
||||
DateTime end;
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case MmcCommands.SendCid when _cachedCid != null:
|
||||
{
|
||||
start = DateTime.Now;
|
||||
buffer = new byte[_cachedCid.Length];
|
||||
Array.Copy(_cachedCid, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case MmcCommands.SendCsd when _cachedCid != null:
|
||||
{
|
||||
start = DateTime.Now;
|
||||
buffer = new byte[_cachedCsd.Length];
|
||||
Array.Copy(_cachedCsd, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null:
|
||||
{
|
||||
start = DateTime.Now;
|
||||
buffer = new byte[_cachedScr.Length];
|
||||
Array.Copy(_cachedScr, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null:
|
||||
case MmcCommands.SendOpCond when _cachedOcr != null:
|
||||
{
|
||||
start = DateTime.Now;
|
||||
buffer = new byte[_cachedOcr.Length];
|
||||
Array.Copy(_cachedOcr, buffer, buffer.Length);
|
||||
response = new uint[4];
|
||||
sense = false;
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
var commandData = new SffdiskDeviceCommandData();
|
||||
var commandDescriptor = new SdCmdDescriptor();
|
||||
commandData.size = (ushort)Marshal.SizeOf(commandData);
|
||||
@@ -531,13 +568,13 @@ static class Command
|
||||
Marshal.Copy(hBuf, commandB, 0, commandB.Length);
|
||||
Marshal.FreeHGlobal(hBuf);
|
||||
|
||||
var error = 0;
|
||||
DateTime start = DateTime.Now;
|
||||
var error = 0;
|
||||
start = DateTime.Now;
|
||||
|
||||
sense = !Extern.DeviceIoControl(fd, WindowsIoctl.IoctlSffdiskDeviceCommand, commandB, (uint)commandB.Length,
|
||||
commandB, (uint)commandB.Length, out _, IntPtr.Zero);
|
||||
sense = !Extern.DeviceIoControl(_fileHandle, WindowsIoctl.IoctlSffdiskDeviceCommand, commandB,
|
||||
(uint)commandB.Length, commandB, (uint)commandB.Length, out _, IntPtr.Zero);
|
||||
|
||||
DateTime end = DateTime.Now;
|
||||
end = DateTime.Now;
|
||||
|
||||
if(sense)
|
||||
error = Marshal.GetLastWin32Error();
|
||||
@@ -551,9 +588,14 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
internal static int SendMultipleMmcCommands(SafeFileHandle fd, Device.MmcSingleCommand[] commands,
|
||||
out double duration, out bool sense, uint timeout = 0)
|
||||
/// <inheritdoc />
|
||||
public override int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense,
|
||||
uint timeout = 15)
|
||||
{
|
||||
// We need a timeout
|
||||
if(timeout == 0)
|
||||
timeout = Timeout > 0 ? Timeout : 15;
|
||||
|
||||
var error = 0;
|
||||
duration = 0;
|
||||
sense = false;
|
||||
@@ -562,13 +604,13 @@ static class Command
|
||||
commands[0].command == MmcCommands.SetBlocklen &&
|
||||
commands[1].command == MmcCommands.ReadMultipleBlock &&
|
||||
commands[2].command == MmcCommands.StopTransmission)
|
||||
return SendMmcCommand(fd, commands[1].command, commands[1].write, commands[1].isApplication,
|
||||
commands[1].flags, commands[1].argument, commands[1].blockSize, commands[1].blocks,
|
||||
return SendMmcCommand(commands[1].command, commands[1].write, commands[1].isApplication, commands[1].flags,
|
||||
commands[1].argument, commands[1].blockSize, commands[1].blocks,
|
||||
ref commands[1].buffer, out commands[1].response, out duration, out sense, timeout);
|
||||
|
||||
foreach(Device.MmcSingleCommand command in commands)
|
||||
foreach(MmcSingleCommand command in commands)
|
||||
{
|
||||
int singleError = SendMmcCommand(fd, command.command, command.write, command.isApplication, command.flags,
|
||||
int singleError = SendMmcCommand(command.command, command.write, command.isApplication, command.flags,
|
||||
command.argument, command.blockSize, command.blocks, ref command.buffer,
|
||||
out command.response, out double cmdDuration, out bool cmdSense, timeout);
|
||||
|
||||
@@ -585,25 +627,36 @@ static class Command
|
||||
return error;
|
||||
}
|
||||
|
||||
internal static int ReOpen(string devicePath, SafeFileHandle fd, out object newFd)
|
||||
/// <inheritdoc />
|
||||
public override bool ReOpen()
|
||||
{
|
||||
Extern.CloseHandle(fd);
|
||||
Extern.CloseHandle(_fileHandle);
|
||||
|
||||
newFd = Extern.CreateFile(devicePath, FileAccess.GenericRead | FileAccess.GenericWrite,
|
||||
FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting,
|
||||
FileAttributes.Normal, IntPtr.Zero);
|
||||
SafeFileHandle newFd = Extern.CreateFile(_devicePath, FileAccess.GenericRead | FileAccess.GenericWrite,
|
||||
FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting,
|
||||
FileAttributes.Normal, IntPtr.Zero);
|
||||
|
||||
return ((SafeFileHandle)newFd).IsInvalid ? Marshal.GetLastWin32Error() : 0;
|
||||
if(newFd.IsInvalid)
|
||||
{
|
||||
LastError = Marshal.GetLastWin32Error();
|
||||
Error = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_fileHandle = newFd;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static int BufferedOsRead(SafeFileHandle fd, out byte[] buffer, long offset, uint length,
|
||||
out double duration)
|
||||
/// <inheritdoc />
|
||||
public override bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration)
|
||||
{
|
||||
buffer = new byte[length];
|
||||
|
||||
DateTime start = DateTime.Now;
|
||||
|
||||
bool sense = !Extern.SetFilePointerEx(fd, offset, out _, MoveMethod.Begin);
|
||||
bool sense = !Extern.SetFilePointerEx(_fileHandle, offset, out _, MoveMethod.Begin);
|
||||
|
||||
DateTime end = DateTime.Now;
|
||||
|
||||
@@ -611,14 +664,27 @@ static class Command
|
||||
{
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return Marshal.GetLastWin32Error();
|
||||
LastError = Marshal.GetLastWin32Error();
|
||||
Error = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
sense = !Extern.ReadFile(fd, buffer, length, out _, IntPtr.Zero);
|
||||
sense = !Extern.ReadFile(_fileHandle, buffer, length, out _, IntPtr.Zero);
|
||||
|
||||
end = DateTime.Now;
|
||||
duration = (end - start).TotalMilliseconds;
|
||||
|
||||
return sense ? Marshal.GetLastWin32Error() : 0;
|
||||
if(sense)
|
||||
{
|
||||
Error = true;
|
||||
LastError = Marshal.GetLastWin32Error();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Error = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -43,25 +43,28 @@ using Microsoft.Win32.SafeHandles;
|
||||
|
||||
/// <inheritdoc />
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class Device : Devices.Device
|
||||
partial class Device : Devices.Device
|
||||
{
|
||||
/// <summary>Gets the file handle representing this device</summary>
|
||||
/// <value>The file handle</value>
|
||||
SafeFileHandle _fileHandle;
|
||||
|
||||
Device() {}
|
||||
|
||||
public new static Device Create(string devicePath)
|
||||
internal new static Device Create(string devicePath)
|
||||
{
|
||||
var dev = new Device
|
||||
{
|
||||
PlatformId = DetectOS.GetRealPlatformID(),
|
||||
Timeout = 15,
|
||||
Error = false,
|
||||
IsRemovable = false
|
||||
PlatformId = DetectOS.GetRealPlatformID(),
|
||||
Timeout = 15,
|
||||
Error = false,
|
||||
IsRemovable = false,
|
||||
_fileHandle = Extern.CreateFile(devicePath, FileAccess.GenericRead | FileAccess.GenericWrite,
|
||||
FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting,
|
||||
FileAttributes.Normal, IntPtr.Zero)
|
||||
};
|
||||
|
||||
dev.FileHandle = Extern.CreateFile(devicePath, FileAccess.GenericRead | FileAccess.GenericWrite,
|
||||
FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting,
|
||||
FileAttributes.Normal, IntPtr.Zero);
|
||||
|
||||
if(((SafeFileHandle)dev.FileHandle).IsInvalid)
|
||||
if(dev._fileHandle.IsInvalid)
|
||||
{
|
||||
dev.Error = true;
|
||||
dev.LastError = Marshal.GetLastWin32Error();
|
||||
@@ -73,9 +76,6 @@ public class Device : Devices.Device
|
||||
dev.Type = DeviceType.Unknown;
|
||||
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
||||
|
||||
byte[] ataBuf;
|
||||
byte[] inqBuf = null;
|
||||
|
||||
if(dev.Error)
|
||||
throw new DeviceException(dev.LastError);
|
||||
|
||||
@@ -91,9 +91,8 @@ public class Device : Devices.Device
|
||||
uint returned = 0;
|
||||
var error = 0;
|
||||
|
||||
bool hasError = !Extern.DeviceIoControlStorageQuery((SafeFileHandle)dev.FileHandle,
|
||||
WindowsIoctl.IoctlStorageQueryProperty, ref query,
|
||||
(uint)Marshal.SizeOf(query), descriptorPtr, 1000,
|
||||
bool hasError = !Extern.DeviceIoControlStorageQuery(dev._fileHandle, WindowsIoctl.IoctlStorageQueryProperty,
|
||||
ref query, (uint)Marshal.SizeOf(query), descriptorPtr, 1000,
|
||||
ref returned, IntPtr.Zero);
|
||||
|
||||
if(hasError)
|
||||
@@ -170,7 +169,7 @@ public class Device : Devices.Device
|
||||
switch(dev.Type)
|
||||
{
|
||||
case DeviceType.ATA:
|
||||
bool atapiSense = dev.AtapiIdentify(out ataBuf, out _);
|
||||
bool atapiSense = dev.AtapiIdentify(out byte[] _, out _);
|
||||
|
||||
if(!atapiSense)
|
||||
dev.Type = DeviceType.ATAPI;
|
||||
@@ -183,13 +182,13 @@ public class Device : Devices.Device
|
||||
|
||||
Marshal.FreeHGlobal(descriptorPtr);
|
||||
|
||||
if(Command.IsSdhci((SafeFileHandle)dev.FileHandle))
|
||||
if(IsSdhci(dev._fileHandle))
|
||||
{
|
||||
var sdBuffer = new byte[16];
|
||||
|
||||
dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle, MmcCommands.SendCsd, false, false,
|
||||
MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0,
|
||||
16, 1, ref sdBuffer, out _, out _, out bool sense);
|
||||
dev.LastError = dev.SendMmcCommand(MmcCommands.SendCsd, false, false,
|
||||
MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16,
|
||||
1, ref sdBuffer, out _, out _, out bool sense);
|
||||
|
||||
if(!sense)
|
||||
{
|
||||
@@ -199,9 +198,9 @@ public class Device : Devices.Device
|
||||
|
||||
sdBuffer = new byte[16];
|
||||
|
||||
dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle, MmcCommands.SendCid, false, false,
|
||||
MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0,
|
||||
16, 1, ref sdBuffer, out _, out _, out sense);
|
||||
dev.LastError = dev.SendMmcCommand(MmcCommands.SendCid, false, false,
|
||||
MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16,
|
||||
1, ref sdBuffer, out _, out _, out sense);
|
||||
|
||||
if(!sense)
|
||||
{
|
||||
@@ -211,10 +210,9 @@ public class Device : Devices.Device
|
||||
|
||||
sdBuffer = new byte[8];
|
||||
|
||||
dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle,
|
||||
(MmcCommands)SecureDigitalCommands.SendScr, false, true,
|
||||
MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc,
|
||||
0, 8, 1, ref sdBuffer, out _, out _, out sense);
|
||||
dev.LastError = dev.SendMmcCommand((MmcCommands)SecureDigitalCommands.SendScr, false, true,
|
||||
MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, 0,
|
||||
8, 1, ref sdBuffer, out _, out _, out sense);
|
||||
|
||||
if(!sense)
|
||||
{
|
||||
@@ -224,12 +222,10 @@ public class Device : Devices.Device
|
||||
|
||||
sdBuffer = new byte[4];
|
||||
|
||||
dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle,
|
||||
dev._cachedScr != null
|
||||
? (MmcCommands)SecureDigitalCommands.SendOperatingCondition
|
||||
: MmcCommands.SendOpCond, false, true,
|
||||
MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr,
|
||||
0, 4, 1, ref sdBuffer, out _, out _, out sense);
|
||||
dev.LastError =
|
||||
dev.SendMmcCommand(dev._cachedScr != null ? (MmcCommands)SecureDigitalCommands.SendOperatingCondition : MmcCommands.SendOpCond,
|
||||
false, true, MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, 0,
|
||||
4, 1, ref sdBuffer, out _, out _, out sense);
|
||||
|
||||
if(!sense)
|
||||
{
|
||||
@@ -318,11 +314,11 @@ public class Device : Devices.Device
|
||||
/// <inheritdoc />
|
||||
public override void Close()
|
||||
{
|
||||
if(FileHandle == null)
|
||||
if(_fileHandle == null)
|
||||
return;
|
||||
|
||||
(FileHandle as SafeFileHandle)?.Close();
|
||||
_fileHandle?.Close();
|
||||
|
||||
FileHandle = null;
|
||||
_fileHandle = null;
|
||||
}
|
||||
}
|
||||
@@ -250,10 +250,11 @@ public sealed class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
var dev = Device.Create(deviceModel.Path);
|
||||
|
||||
if(dev.IsRemote)
|
||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion,
|
||||
dev.RemoteOperatingSystem, dev.RemoteOperatingSystemVersion,
|
||||
dev.RemoteArchitecture);
|
||||
if(dev is Devices.Remote.Device remoteDev)
|
||||
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||
remoteDev.RemoteOperatingSystem,
|
||||
remoteDev.RemoteOperatingSystemVersion,
|
||||
remoteDev.RemoteArchitecture);
|
||||
|
||||
if(dev.Error)
|
||||
{
|
||||
@@ -789,9 +790,10 @@ public sealed class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
var dev = Device.Create(device.Path);
|
||||
|
||||
if(dev.IsRemote)
|
||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
||||
if(dev is Devices.Remote.Device remoteDev)
|
||||
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||
remoteDev.RemoteArchitecture);
|
||||
|
||||
switch(dev.Type)
|
||||
{
|
||||
|
||||
@@ -728,9 +728,10 @@ public sealed class MediaDumpViewModel : ViewModelBase
|
||||
{
|
||||
_dev = Device.Create(_devicePath);
|
||||
|
||||
if(_dev.IsRemote)
|
||||
Statistics.AddRemote(_dev.RemoteApplication, _dev.RemoteVersion, _dev.RemoteOperatingSystem,
|
||||
_dev.RemoteOperatingSystemVersion, _dev.RemoteArchitecture);
|
||||
if(_dev is Devices.Remote.Device remoteDev)
|
||||
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||
remoteDev.RemoteArchitecture);
|
||||
|
||||
if(_dev.Error)
|
||||
{
|
||||
|
||||
@@ -330,9 +330,9 @@ public sealed class MediaScanViewModel : ViewModelBase
|
||||
|
||||
var dev = Device.Create(_devicePath);
|
||||
|
||||
if(dev.IsRemote)
|
||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
||||
if(dev is Devices.Remote.Device remoteDev)
|
||||
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, remoteDev.RemoteOperatingSystem,
|
||||
remoteDev.RemoteOperatingSystemVersion, remoteDev.RemoteArchitecture);
|
||||
|
||||
if(dev.Error)
|
||||
{
|
||||
|
||||
@@ -44,7 +44,6 @@ static partial class MainClass
|
||||
while(true)
|
||||
{
|
||||
AaruConsole.WriteLine("dev.PlatformID = {0}", dev.PlatformId);
|
||||
AaruConsole.WriteLine("dev.FileHandle = {0}", dev.FileHandle);
|
||||
AaruConsole.WriteLine("dev.Timeout = {0}", dev.Timeout);
|
||||
AaruConsole.WriteLine("dev.Error = {0}", dev.Error);
|
||||
AaruConsole.WriteLine("dev.LastError = {0}", dev.LastError);
|
||||
|
||||
@@ -130,9 +130,10 @@ sealed class DeviceReportCommand : Command
|
||||
{
|
||||
dev = Device.Create(devicePath);
|
||||
|
||||
if(dev.IsRemote)
|
||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
||||
if(dev is Devices.Remote.Device remoteDev)
|
||||
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||
remoteDev.RemoteArchitecture);
|
||||
|
||||
if(dev.Error)
|
||||
{
|
||||
@@ -150,7 +151,7 @@ sealed class DeviceReportCommand : Command
|
||||
|
||||
Statistics.AddDevice(dev);
|
||||
|
||||
bool isAdmin = dev.IsRemote ? dev.IsRemoteAdmin : DetectOS.IsAdmin;
|
||||
bool isAdmin = dev is Devices.Remote.Device remoteDev2 ? remoteDev2.IsAdmin : DetectOS.IsAdmin;
|
||||
|
||||
if(!isAdmin)
|
||||
{
|
||||
|
||||
@@ -134,9 +134,10 @@ sealed class DeviceInfoCommand : Command
|
||||
{
|
||||
dev = Device.Create(devicePath);
|
||||
|
||||
if(dev.IsRemote)
|
||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
||||
if(dev is Devices.Remote.Device remoteDev)
|
||||
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||
remoteDev.RemoteArchitecture);
|
||||
|
||||
if(dev.Error)
|
||||
{
|
||||
|
||||
@@ -546,9 +546,10 @@ sealed class DumpMediaCommand : Command
|
||||
dev = Device.Create(devicePath);
|
||||
});
|
||||
|
||||
if(dev.IsRemote)
|
||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
||||
if(dev is Devices.Remote.Device remoteDev)
|
||||
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||
remoteDev.RemoteArchitecture);
|
||||
|
||||
if(dev.Error)
|
||||
{
|
||||
|
||||
@@ -139,9 +139,10 @@ sealed class MediaInfoCommand : Command
|
||||
dev = Device.Create(devicePath);
|
||||
});
|
||||
|
||||
if(dev.IsRemote)
|
||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
||||
if(dev is Devices.Remote.Device remoteDev)
|
||||
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||
remoteDev.RemoteArchitecture);
|
||||
|
||||
if(dev.Error)
|
||||
{
|
||||
|
||||
@@ -140,9 +140,10 @@ sealed class MediaScanCommand : Command
|
||||
dev = Device.Create(devicePath);
|
||||
});
|
||||
|
||||
if(dev.IsRemote)
|
||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
||||
if(dev is Devices.Remote.Device remoteDev)
|
||||
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||
remoteDev.RemoteArchitecture);
|
||||
|
||||
if(dev.Error)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user