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.Decoders.Xbox;
|
||||||
using Aaru.Devices;
|
using Aaru.Devices;
|
||||||
using Schemas;
|
using Schemas;
|
||||||
|
using Device = Aaru.Devices.Remote.Device;
|
||||||
using PlatformID = Aaru.CommonTypes.Interop.PlatformID;
|
using PlatformID = Aaru.CommonTypes.Interop.PlatformID;
|
||||||
using TrackType = Aaru.CommonTypes.Enums.TrackType;
|
using TrackType = Aaru.CommonTypes.Enums.TrackType;
|
||||||
using Version = Aaru.CommonTypes.Interop.Version;
|
using Version = Aaru.CommonTypes.Interop.Version;
|
||||||
@@ -82,7 +83,7 @@ partial class Dump
|
|||||||
|
|
||||||
if(DetectOS.GetRealPlatformID() != PlatformID.Win32NT)
|
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)
|
if(!isAdmin)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -114,17 +114,18 @@ public sealed class DumpLog
|
|||||||
|
|
||||||
_logSw.WriteLine();
|
_logSw.WriteLine();
|
||||||
|
|
||||||
if(dev.IsRemote)
|
if(dev is Aaru.Devices.Remote.Device remoteDev)
|
||||||
{
|
{
|
||||||
_logSw.WriteLine("################# Remote information #################");
|
_logSw.WriteLine("################# Remote information #################");
|
||||||
_logSw.WriteLine("Server: {0}", dev.RemoteApplication);
|
_logSw.WriteLine("Server: {0}", remoteDev.RemoteApplication);
|
||||||
_logSw.WriteLine("Version: {0}", dev.RemoteVersion);
|
_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("Architecture: {0}", remoteDev.RemoteArchitecture);
|
||||||
_logSw.WriteLine("Protocol version: {0}", dev.RemoteProtocolVersion);
|
_logSw.WriteLine("Protocol version: {0}", remoteDev.RemoteProtocolVersion);
|
||||||
_logSw.WriteLine("Running as superuser: {0}", dev.IsRemoteAdmin ? "Yes" : "No");
|
_logSw.WriteLine("Running as superuser: {0}", remoteDev.IsAdmin ? "Yes" : "No");
|
||||||
_logSw.WriteLine("######################################################");
|
_logSw.WriteLine("######################################################");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,7 @@
|
|||||||
<Compile Include="Linux\Structs.cs" />
|
<Compile Include="Linux\Structs.cs" />
|
||||||
<Compile Include="Linux\Enums.cs" />
|
<Compile Include="Linux\Enums.cs" />
|
||||||
<Compile Include="Enums.cs" />
|
<Compile Include="Enums.cs" />
|
||||||
|
<Compile Include="Remote\Command.cs" />
|
||||||
<Compile Include="Remote\Consts.cs" />
|
<Compile Include="Remote\Consts.cs" />
|
||||||
<Compile Include="Remote\Device.cs" />
|
<Compile Include="Remote\Device.cs" />
|
||||||
<Compile Include="Remote\Enums.cs" />
|
<Compile Include="Remote\Enums.cs" />
|
||||||
@@ -77,7 +78,6 @@
|
|||||||
<Compile Include="Windows\Enums.cs" />
|
<Compile Include="Windows\Enums.cs" />
|
||||||
<Compile Include="Windows\Command.cs" />
|
<Compile Include="Windows\Command.cs" />
|
||||||
<Compile Include="Linux\Command.cs" />
|
<Compile Include="Linux\Command.cs" />
|
||||||
<Compile Include="Command.cs" />
|
|
||||||
<Compile Include="Device\Constructor.cs" />
|
<Compile Include="Device\Constructor.cs" />
|
||||||
<Compile Include="Device\Variables.cs" />
|
<Compile Include="Device\Variables.cs" />
|
||||||
<Compile Include="Device\Destructor.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;
|
namespace Aaru.Devices;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Aaru.Decoders.ATA;
|
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
|
/// <c>True</c> if SCSI command returned non-OK status and <paramref name="senseBuffer" /> contains
|
||||||
/// SCSI sense
|
/// SCSI sense
|
||||||
/// </param>
|
/// </param>
|
||||||
public int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
public virtual int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||||
ScsiDirection direction, out double duration, out bool sense)
|
ScsiDirection direction, out double duration, out bool sense)
|
||||||
{
|
{
|
||||||
// We need a timeout
|
duration = 0;
|
||||||
if(timeout == 0)
|
sense = true;
|
||||||
timeout = Timeout > 0 ? Timeout : 15;
|
senseBuffer = null;
|
||||||
|
|
||||||
if(!(_remote is null))
|
return -1;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends an ATA/ATAPI command to this device using CHS addressing</summary>
|
/// <summary>Sends an ATA/ATAPI command to this device using CHS addressing</summary>
|
||||||
@@ -80,20 +74,15 @@ public partial class Device
|
|||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="duration">Time it took to execute the command in milliseconds</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>
|
/// <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,
|
public virtual int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||||
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||||
bool transferBlocks, out double duration, out bool sense)
|
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||||
{
|
{
|
||||||
// We need a timeout
|
duration = 0;
|
||||||
if(timeout == 0)
|
sense = true;
|
||||||
timeout = Timeout > 0 ? Timeout : 15;
|
errorRegisters = default(AtaErrorRegistersChs);
|
||||||
|
|
||||||
if(!(_remote is null))
|
return -1;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends an ATA/ATAPI command to this device using 28-bit LBA addressing</summary>
|
/// <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>
|
||||||
/// <param name="duration">Time it took to execute the command in milliseconds</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>
|
/// <param name="sense"><c>True</c> if ATA/ATAPI command returned non-OK status</param>
|
||||||
public int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
public virtual int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
||||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||||
{
|
{
|
||||||
// We need a timeout
|
errorRegisters = default(AtaErrorRegistersLba28);
|
||||||
if(timeout == 0)
|
duration = 0;
|
||||||
timeout = Timeout > 0 ? Timeout : 15;
|
sense = true;
|
||||||
|
|
||||||
if(!(_remote is null))
|
return -1;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends an ATA/ATAPI command to this device using 48-bit LBA addressing</summary>
|
/// <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>
|
||||||
/// <param name="duration">Time it took to execute the command in milliseconds</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>
|
/// <param name="sense"><c>True</c> if ATA/ATAPI command returned non-OK status</param>
|
||||||
public int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
public virtual int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
||||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||||
{
|
{
|
||||||
// We need a timeout
|
errorRegisters = default(AtaErrorRegistersLba48);
|
||||||
if(timeout == 0)
|
duration = 0;
|
||||||
timeout = Timeout > 0 ? Timeout : 15;
|
sense = true;
|
||||||
|
|
||||||
if(!(_remote is null))
|
return -1;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends a MMC/SD command to this device</summary>
|
/// <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="argument">Command argument</param>
|
||||||
/// <param name="response">Response registers</param>
|
/// <param name="response">Response registers</param>
|
||||||
/// <param name="blockSize">Size of block in bytes</param>
|
/// <param name="blockSize">Size of block in bytes</param>
|
||||||
public int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, uint argument,
|
public virtual int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||||
uint blockSize, uint blocks, ref byte[] buffer, out uint[] response, out double duration,
|
uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||||
out bool sense, uint timeout = 15)
|
out uint[] response, out double duration, out bool sense, uint timeout = 15)
|
||||||
{
|
{
|
||||||
// We need a timeout
|
response = null;
|
||||||
if(timeout == 0)
|
duration = 0;
|
||||||
timeout = Timeout > 0 ? Timeout : 15;
|
sense = true;
|
||||||
|
|
||||||
switch(command)
|
return -1;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Encapsulates a single MMC command to send in a queue</summary>
|
/// <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="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>
|
/// <param name="timeout">Maximum allowed time to execute a single command</param>
|
||||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
||||||
public int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense,
|
public virtual int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense,
|
||||||
uint timeout = 15)
|
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;
|
duration = 0;
|
||||||
sense = false;
|
sense = true;
|
||||||
|
|
||||||
foreach(MmcSingleCommand command in commands)
|
return -1;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Closes then immediately reopens a device</summary>
|
/// <summary>Closes then immediately reopens a device</summary>
|
||||||
/// <returns>Returned error number if any</returns>
|
/// <returns>Returned error number if any</returns>
|
||||||
public bool ReOpen()
|
public virtual bool ReOpen() => false;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Reads data using operating system buffers.</summary>
|
/// <summary>Reads data using operating system buffers.</summary>
|
||||||
/// <param name="buffer">Data buffer</param>
|
/// <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="length">Number of bytes to read</param>
|
||||||
/// <param name="duration">Total time in milliseconds the reading took</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>
|
/// <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))
|
buffer = null;
|
||||||
return _remote.BufferedOsRead(out buffer, offset, length, out duration);
|
duration = 0;
|
||||||
|
|
||||||
int ret = Command.BufferedOsRead(PlatformId, FileHandle, out buffer, offset, length, out duration);
|
return false;
|
||||||
|
|
||||||
Error = ret != 0;
|
|
||||||
LastError = ret;
|
|
||||||
|
|
||||||
return Error;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,10 +55,6 @@ public partial class Device
|
|||||||
/// <value>The Platform ID</value>
|
/// <value>The Platform ID</value>
|
||||||
public PlatformID PlatformId { get; private protected set; }
|
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>
|
/// <summary>Gets or sets the standard timeout for commands sent to this device</summary>
|
||||||
/// <value>The timeout in seconds</value>
|
/// <value>The timeout in seconds</value>
|
||||||
public uint Timeout { get; set; }
|
public uint Timeout { get; set; }
|
||||||
@@ -162,33 +158,5 @@ public partial class Device
|
|||||||
/// <summary>Contains the PCMCIA CIS if applicable</summary>
|
/// <summary>Contains the PCMCIA CIS if applicable</summary>
|
||||||
public byte[] Cis { get; private protected set; }
|
public byte[] Cis { get; private protected set; }
|
||||||
|
|
||||||
private protected Remote.Remote _remote;
|
|
||||||
bool? _isRemoteAdmin;
|
|
||||||
private protected string _devicePath;
|
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.CommonTypes.Interop;
|
||||||
using Aaru.Decoders.ATA;
|
using Aaru.Decoders.ATA;
|
||||||
|
|
||||||
static class Command
|
partial class Device
|
||||||
{
|
{
|
||||||
/// <summary>Sends a SCSI command</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||||
/// <param name="fd">File handle</param>
|
ScsiDirection direction, out double duration, out bool sense)
|
||||||
/// <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)
|
|
||||||
{
|
{
|
||||||
|
// We need a timeout
|
||||||
|
if(timeout == 0)
|
||||||
|
timeout = Timeout > 0 ? Timeout : 15;
|
||||||
|
|
||||||
senseBuffer = null;
|
senseBuffer = null;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
@@ -64,6 +56,32 @@ static class Command
|
|||||||
if(buffer == null)
|
if(buffer == null)
|
||||||
return -1;
|
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();
|
var ioHdr = new SgIoHdrT();
|
||||||
|
|
||||||
senseBuffer = new byte[64];
|
senseBuffer = new byte[64];
|
||||||
@@ -71,7 +89,7 @@ static class Command
|
|||||||
ioHdr.interface_id = 'S';
|
ioHdr.interface_id = 'S';
|
||||||
ioHdr.cmd_len = (byte)cdb.Length;
|
ioHdr.cmd_len = (byte)cdb.Length;
|
||||||
ioHdr.mx_sb_len = (byte)senseBuffer.Length;
|
ioHdr.mx_sb_len = (byte)senseBuffer.Length;
|
||||||
ioHdr.dxfer_direction = direction;
|
ioHdr.dxfer_direction = dir;
|
||||||
ioHdr.dxfer_len = (uint)buffer.Length;
|
ioHdr.dxfer_len = (uint)buffer.Length;
|
||||||
ioHdr.dxferp = Marshal.AllocHGlobal(buffer.Length);
|
ioHdr.dxferp = Marshal.AllocHGlobal(buffer.Length);
|
||||||
ioHdr.cmdp = Marshal.AllocHGlobal(cdb.Length);
|
ioHdr.cmdp = Marshal.AllocHGlobal(cdb.Length);
|
||||||
@@ -84,7 +102,7 @@ static class Command
|
|||||||
Marshal.Copy(senseBuffer, 0, ioHdr.sbp, senseBuffer.Length);
|
Marshal.Copy(senseBuffer, 0, ioHdr.sbp, senseBuffer.Length);
|
||||||
|
|
||||||
DateTime start = DateTime.UtcNow;
|
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;
|
DateTime end = DateTime.UtcNow;
|
||||||
|
|
||||||
if(error < 0)
|
if(error < 0)
|
||||||
@@ -108,7 +126,7 @@ static class Command
|
|||||||
/// <summary>Converts ATA protocol to SG_IO direction</summary>
|
/// <summary>Converts ATA protocol to SG_IO direction</summary>
|
||||||
/// <param name="protocol">ATA protocol</param>
|
/// <param name="protocol">ATA protocol</param>
|
||||||
/// <returns>SG_IO direction</returns>
|
/// <returns>SG_IO direction</returns>
|
||||||
static ScsiIoctlDirection AtaProtocolToScsiDirection(AtaProtocol protocol)
|
static ScsiDirection AtaProtocolToScsiDirection(AtaProtocol protocol)
|
||||||
{
|
{
|
||||||
switch(protocol)
|
switch(protocol)
|
||||||
{
|
{
|
||||||
@@ -117,31 +135,24 @@ static class Command
|
|||||||
case AtaProtocol.HardReset:
|
case AtaProtocol.HardReset:
|
||||||
case AtaProtocol.NonData:
|
case AtaProtocol.NonData:
|
||||||
case AtaProtocol.SoftReset:
|
case AtaProtocol.SoftReset:
|
||||||
case AtaProtocol.ReturnResponse: return ScsiIoctlDirection.None;
|
case AtaProtocol.ReturnResponse: return ScsiDirection.None;
|
||||||
case AtaProtocol.PioIn:
|
case AtaProtocol.PioIn:
|
||||||
case AtaProtocol.UDmaIn: return ScsiIoctlDirection.In;
|
case AtaProtocol.UDmaIn: return ScsiDirection.In;
|
||||||
case AtaProtocol.PioOut:
|
case AtaProtocol.PioOut:
|
||||||
case AtaProtocol.UDmaOut: return ScsiIoctlDirection.Out;
|
case AtaProtocol.UDmaOut: return ScsiDirection.Out;
|
||||||
default: return ScsiIoctlDirection.Unspecified;
|
default: return ScsiDirection.Unspecified;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends an ATA command in CHS mode</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
public override int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||||
/// <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,
|
|
||||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||||
{
|
{
|
||||||
|
// We need a timeout
|
||||||
|
if(timeout == 0)
|
||||||
|
timeout = Timeout > 0 ? Timeout : 15;
|
||||||
|
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
errorRegisters = new AtaErrorRegistersChs();
|
errorRegisters = new AtaErrorRegistersChs();
|
||||||
@@ -185,7 +196,7 @@ static class Command
|
|||||||
cdb[13] = registers.DeviceHead;
|
cdb[13] = registers.DeviceHead;
|
||||||
cdb[14] = registers.Command;
|
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);
|
AtaProtocolToScsiDirection(protocol), out duration, out sense);
|
||||||
|
|
||||||
if(senseBuffer.Length < 22 ||
|
if(senseBuffer.Length < 22 ||
|
||||||
@@ -206,22 +217,15 @@ static class Command
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends an ATA command in 28-bit LBA mode</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
public override int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
||||||
/// <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,
|
|
||||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||||
{
|
{
|
||||||
|
// We need a timeout
|
||||||
|
if(timeout == 0)
|
||||||
|
timeout = Timeout > 0 ? Timeout : 15;
|
||||||
|
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
errorRegisters = new AtaErrorRegistersLba28();
|
errorRegisters = new AtaErrorRegistersLba28();
|
||||||
@@ -265,7 +269,7 @@ static class Command
|
|||||||
cdb[13] = registers.DeviceHead;
|
cdb[13] = registers.DeviceHead;
|
||||||
cdb[14] = registers.Command;
|
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);
|
AtaProtocolToScsiDirection(protocol), out duration, out sense);
|
||||||
|
|
||||||
if(senseBuffer.Length < 22 ||
|
if(senseBuffer.Length < 22 ||
|
||||||
@@ -286,22 +290,15 @@ static class Command
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends an ATA command in 48-bit LBA mode</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
public override int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
||||||
/// <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,
|
|
||||||
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||||
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||||
{
|
{
|
||||||
|
// We need a timeout
|
||||||
|
if(timeout == 0)
|
||||||
|
timeout = Timeout > 0 ? Timeout : 15;
|
||||||
|
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
errorRegisters = new AtaErrorRegistersLba48();
|
errorRegisters = new AtaErrorRegistersLba48();
|
||||||
@@ -351,7 +348,7 @@ static class Command
|
|||||||
cdb[13] = registers.DeviceHead;
|
cdb[13] = registers.DeviceHead;
|
||||||
cdb[14] = registers.Command;
|
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);
|
AtaProtocolToScsiDirection(protocol), out duration, out sense);
|
||||||
|
|
||||||
if(senseBuffer.Length < 22 ||
|
if(senseBuffer.Length < 22 ||
|
||||||
@@ -377,25 +374,71 @@ static class Command
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends a MMC/SD command</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>The result of the command.</returns>
|
public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||||
/// <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,
|
|
||||||
uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
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;
|
response = null;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
@@ -425,9 +468,9 @@ static class Command
|
|||||||
|
|
||||||
Marshal.Copy(buffer, 0, bufPtr, buffer.Length);
|
Marshal.Copy(buffer, 0, bufPtr, buffer.Length);
|
||||||
|
|
||||||
DateTime start = DateTime.UtcNow;
|
start = DateTime.UtcNow;
|
||||||
int error = Extern.ioctlMmc(fd, LinuxIoctl.MmcIocCmd, ref ioCmd);
|
int error = Extern.ioctlMmc(_fileDescriptor, LinuxIoctl.MmcIocCmd, ref ioCmd);
|
||||||
DateTime end = DateTime.UtcNow;
|
end = DateTime.UtcNow;
|
||||||
|
|
||||||
sense |= error < 0;
|
sense |= error < 0;
|
||||||
|
|
||||||
@@ -444,9 +487,14 @@ static class Command
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int SendMultipleMmcCommands(int fd, Device.MmcSingleCommand[] commands, out double duration,
|
/// <inheritdoc />
|
||||||
out bool sense, uint timeout = 0)
|
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;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
int off;
|
int off;
|
||||||
@@ -506,7 +554,7 @@ static class Command
|
|||||||
|
|
||||||
// Send command
|
// Send command
|
||||||
DateTime start = DateTime.UtcNow;
|
DateTime start = DateTime.UtcNow;
|
||||||
int error = Extern.ioctlMmcMulti(fd, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr);
|
int error = Extern.ioctlMmcMulti(_fileDescriptor, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr);
|
||||||
DateTime end = DateTime.UtcNow;
|
DateTime end = DateTime.UtcNow;
|
||||||
|
|
||||||
sense |= error < 0;
|
sense |= error < 0;
|
||||||
@@ -549,35 +597,61 @@ static class Command
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int ReOpen(string devicePath, int fd, out object newFd)
|
/// <inheritdoc />
|
||||||
{
|
public override bool ReOpen()
|
||||||
newFd = -1;
|
|
||||||
|
|
||||||
int ret = Extern.close(fd);
|
{
|
||||||
|
int ret = Extern.close(_fileDescriptor);
|
||||||
|
|
||||||
if(ret < 0)
|
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)
|
int newFd = Extern.open(_devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew);
|
||||||
return 0;
|
|
||||||
|
if(newFd >= 0)
|
||||||
|
{
|
||||||
|
Error = false;
|
||||||
|
_fileDescriptor = newFd;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int error = Marshal.GetLastWin32Error();
|
int error = Marshal.GetLastWin32Error();
|
||||||
|
|
||||||
if(error != 13 &&
|
if(error != 13 &&
|
||||||
error != 30)
|
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>
|
/// <summary>Reads the contents of a symbolic link</summary>
|
||||||
/// <param name="path">Path to the symbolic link</param>
|
/// <param name="path">Path to the symbolic link</param>
|
||||||
/// <returns>Contents of the symbolic link</returns>
|
/// <returns>Contents of the symbolic link</returns>
|
||||||
internal static string ReadLink(string path)
|
static string ReadLink(string path)
|
||||||
{
|
{
|
||||||
IntPtr buf = Marshal.AllocHGlobal(4096);
|
IntPtr buf = Marshal.AllocHGlobal(4096);
|
||||||
int resultSize;
|
int resultSize;
|
||||||
@@ -608,13 +682,15 @@ static class Command
|
|||||||
return Encoding.ASCII.GetString(resultString);
|
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];
|
buffer = new byte[length];
|
||||||
|
|
||||||
DateTime start = DateTime.Now;
|
DateTime start = DateTime.Now;
|
||||||
|
|
||||||
long sense = Extern.lseek(fd, offset, SeekWhence.Begin);
|
long sense = Extern.lseek(_fileDescriptor, offset, SeekWhence.Begin);
|
||||||
|
|
||||||
DateTime end = DateTime.Now;
|
DateTime end = DateTime.Now;
|
||||||
|
|
||||||
@@ -622,10 +698,14 @@ static class Command
|
|||||||
{
|
{
|
||||||
duration = (end - start).TotalMilliseconds;
|
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;
|
end = DateTime.Now;
|
||||||
duration = (end - start).TotalMilliseconds;
|
duration = (end - start).TotalMilliseconds;
|
||||||
@@ -637,6 +717,9 @@ static class Command
|
|||||||
else if(errno == 0)
|
else if(errno == 0)
|
||||||
errno = -22;
|
errno = -22;
|
||||||
|
|
||||||
return errno;
|
LastError = errno;
|
||||||
|
Error = errno == 0;
|
||||||
|
|
||||||
|
return errno != 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,31 +46,34 @@ using VendorString = Aaru.Decoders.MMC.VendorString;
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[SupportedOSPlatform("linux")]
|
[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() {}
|
Device() {}
|
||||||
|
|
||||||
public new static Device Create(string devicePath)
|
internal new static Device Create(string devicePath)
|
||||||
{
|
{
|
||||||
var dev = new Device
|
var dev = new Device
|
||||||
{
|
{
|
||||||
PlatformId = DetectOS.GetRealPlatformID(),
|
PlatformId = DetectOS.GetRealPlatformID(),
|
||||||
Timeout = 15,
|
Timeout = 15,
|
||||||
Error = false,
|
Error = false,
|
||||||
IsRemovable = 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(dev._fileDescriptor < 0)
|
||||||
|
|
||||||
if((int)dev.FileHandle < 0)
|
|
||||||
{
|
{
|
||||||
dev.LastError = Marshal.GetLastWin32Error();
|
dev.LastError = Marshal.GetLastWin32Error();
|
||||||
|
|
||||||
if(dev.LastError is 13 or 30) // EACCES or EROFS
|
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.Error = true;
|
||||||
dev.LastError = Marshal.GetLastWin32Error();
|
dev.LastError = Marshal.GetLastWin32Error();
|
||||||
@@ -92,23 +95,22 @@ public class Device : Devices.Device
|
|||||||
dev.Type = DeviceType.Unknown;
|
dev.Type = DeviceType.Unknown;
|
||||||
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
||||||
|
|
||||||
byte[] ataBuf;
|
|
||||||
byte[] inqBuf = null;
|
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
throw new DeviceException(dev.LastError);
|
throw new DeviceException(dev.LastError);
|
||||||
|
|
||||||
|
string devPath;
|
||||||
|
|
||||||
if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
|
if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
|
||||||
devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
||||||
devicePath.StartsWith("/dev/st", StringComparison.Ordinal) ||
|
devicePath.StartsWith("/dev/st", StringComparison.Ordinal) ||
|
||||||
devicePath.StartsWith("/dev/sg", StringComparison.Ordinal))
|
devicePath.StartsWith("/dev/sg", StringComparison.Ordinal))
|
||||||
if(!dev.ScsiInquiry(out inqBuf, out _))
|
if(!dev.ScsiInquiry(out byte[] _, out _))
|
||||||
dev.Type = DeviceType.SCSI;
|
dev.Type = DeviceType.SCSI;
|
||||||
|
|
||||||
// MultiMediaCard and SecureDigital go here
|
// MultiMediaCard and SecureDigital go here
|
||||||
else if(devicePath.StartsWith("/dev/mmcblk", StringComparison.Ordinal))
|
else if(devicePath.StartsWith("/dev/mmcblk", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
string devPath = devicePath.Substring(5);
|
devPath = devicePath[5..];
|
||||||
|
|
||||||
if(File.Exists("/sys/block/" + devPath + "/device/csd"))
|
if(File.Exists("/sys/block/" + devPath + "/device/csd"))
|
||||||
{
|
{
|
||||||
@@ -179,21 +181,23 @@ public class Device : Devices.Device
|
|||||||
#endregion SecureDigital / MultiMediaCard
|
#endregion SecureDigital / MultiMediaCard
|
||||||
|
|
||||||
#region USB
|
#region USB
|
||||||
|
string resolvedLink;
|
||||||
|
|
||||||
if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
|
if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
|
||||||
devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
||||||
devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
|
devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
string devPath = devicePath.Substring(5);
|
devPath = devicePath[5..];
|
||||||
|
|
||||||
if(Directory.Exists("/sys/block/" + devPath))
|
if(Directory.Exists("/sys/block/" + devPath))
|
||||||
{
|
{
|
||||||
string resolvedLink = Command.ReadLink("/sys/block/" + devPath);
|
resolvedLink = ReadLink("/sys/block/" + devPath);
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(resolvedLink))
|
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);
|
resolvedLink = Path.GetDirectoryName(resolvedLink);
|
||||||
|
|
||||||
@@ -257,128 +261,121 @@ public class Device : Devices.Device
|
|||||||
#endregion USB
|
#endregion USB
|
||||||
|
|
||||||
#region FireWire
|
#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) ||
|
if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) ||
|
||||||
devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) ||
|
||||||
devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
|
devicePath.StartsWith("/dev/st", StringComparison.Ordinal))
|
||||||
{
|
{
|
||||||
string devPath = devicePath.Substring(5);
|
devPath = devicePath[5..];
|
||||||
|
|
||||||
if(Directory.Exists("/sys/block/" + devPath))
|
if(Directory.Exists("/sys/block/" + devPath))
|
||||||
{
|
{
|
||||||
string resolvedLink = Command.ReadLink("/sys/block/" + devPath);
|
resolvedLink = ReadLink("/sys/block/" + devPath);
|
||||||
resolvedLink = "/sys" + resolvedLink.Substring(2);
|
resolvedLink = "/sys" + resolvedLink[2..];
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(resolvedLink))
|
if(!string.IsNullOrEmpty(resolvedLink))
|
||||||
while(resolvedLink.Contains("/sys/devices"))
|
while(resolvedLink?.Contains("firewire") == true)
|
||||||
{
|
{
|
||||||
resolvedLink = Path.GetDirectoryName(resolvedLink);
|
resolvedLink = Path.GetDirectoryName(resolvedLink);
|
||||||
|
|
||||||
if(!Directory.Exists(resolvedLink + "/pcmcia_socket"))
|
if(!File.Exists(resolvedLink + "/model") ||
|
||||||
|
!File.Exists(resolvedLink + "/vendor") ||
|
||||||
|
!File.Exists(resolvedLink + "/guid"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
string[] subdirs = Directory.GetDirectories(resolvedLink + "/pcmcia_socket", "pcmcia_socket*",
|
var fwSr = new StreamReader(resolvedLink + "/model");
|
||||||
SearchOption.TopDirectoryOnly);
|
string fwTemp = fwSr.ReadToEnd();
|
||||||
|
|
||||||
if(subdirs.Length <= 0)
|
uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||||
continue;
|
out dev._firewireModel);
|
||||||
|
|
||||||
string possibleDir = Path.Combine(resolvedLink, "pcmcia_socket", subdirs[0]);
|
fwSr.Close();
|
||||||
|
|
||||||
if(!File.Exists(possibleDir + "/card_type") ||
|
fwSr = new StreamReader(resolvedLink + "/vendor");
|
||||||
!File.Exists(possibleDir + "/cis"))
|
fwTemp = fwSr.ReadToEnd();
|
||||||
continue;
|
|
||||||
|
|
||||||
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];
|
fwSr.Close();
|
||||||
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;
|
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;
|
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
|
#endregion PCMCIA
|
||||||
|
|
||||||
return dev;
|
return dev;
|
||||||
@@ -399,11 +396,11 @@ public class Device : Devices.Device
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Close()
|
public override void Close()
|
||||||
{
|
{
|
||||||
if(FileHandle == null)
|
if(_fileDescriptor == 0)
|
||||||
return;
|
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;
|
using Aaru.Decoders.SecureDigital;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <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() {}
|
Device() {}
|
||||||
|
|
||||||
/// <summary>Opens the device for sending direct commands</summary>
|
/// <summary>Opens the device for sending direct commands</summary>
|
||||||
/// <param name="aaruUri">AaruRemote URI</param>
|
/// <param name="aaruUri">AaruRemote URI</param>
|
||||||
/// <returns>Device</returns>
|
/// <returns>Device</returns>
|
||||||
public static Device Create(Uri aaruUri)
|
internal static Device Create(Uri aaruUri)
|
||||||
{
|
{
|
||||||
var dev = new Device
|
var dev = new Device
|
||||||
{
|
{
|
||||||
@@ -83,9 +112,6 @@ public sealed class Device : Devices.Device
|
|||||||
dev.Type = DeviceType.Unknown;
|
dev.Type = DeviceType.Unknown;
|
||||||
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
||||||
|
|
||||||
byte[] ataBuf;
|
|
||||||
byte[] inqBuf = null;
|
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
throw new DeviceException(dev.LastError);
|
throw new DeviceException(dev.LastError);
|
||||||
|
|
||||||
@@ -93,11 +119,6 @@ public sealed class Device : Devices.Device
|
|||||||
|
|
||||||
switch(dev.Type)
|
switch(dev.Type)
|
||||||
{
|
{
|
||||||
case DeviceType.ATAPI:
|
|
||||||
case DeviceType.SCSI:
|
|
||||||
bool scsiSense = dev.ScsiInquiry(out inqBuf, out _);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case DeviceType.SecureDigital:
|
case DeviceType.SecureDigital:
|
||||||
case DeviceType.MMC:
|
case DeviceType.MMC:
|
||||||
if(!dev._remote.GetSdhciRegisters(out dev._cachedCsd, out dev._cachedCid, out dev._cachedOcr,
|
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;
|
using Microsoft.Win32.SafeHandles;
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "UnusedParameter.Global")]
|
[SuppressMessage("ReSharper", "UnusedParameter.Global")]
|
||||||
static class Command
|
partial class Device
|
||||||
{
|
{
|
||||||
/// <summary>Sends a SCSI command</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
||||||
/// <param name="fd">File handle</param>
|
ScsiDirection direction, out double duration, out bool sense)
|
||||||
/// <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)
|
|
||||||
{
|
{
|
||||||
|
// We need a timeout
|
||||||
|
if(timeout == 0)
|
||||||
|
timeout = Timeout > 0 ? Timeout : 15;
|
||||||
|
|
||||||
senseBuffer = null;
|
senseBuffer = null;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
@@ -65,6 +57,24 @@ static class Command
|
|||||||
if(buffer == null)
|
if(buffer == null)
|
||||||
return -1;
|
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
|
var sptdSb = new ScsiPassThroughDirectAndSenseBuffer
|
||||||
{
|
{
|
||||||
SenseBuf = new byte[32],
|
SenseBuf = new byte[32],
|
||||||
@@ -73,7 +83,7 @@ static class Command
|
|||||||
Cdb = new byte[16],
|
Cdb = new byte[16],
|
||||||
CdbLength = (byte)cdb.Length,
|
CdbLength = (byte)cdb.Length,
|
||||||
SenseInfoLength = 32,
|
SenseInfoLength = 32,
|
||||||
DataIn = direction,
|
DataIn = dir,
|
||||||
DataTransferLength = (uint)buffer.Length,
|
DataTransferLength = (uint)buffer.Length,
|
||||||
TimeOutValue = timeout,
|
TimeOutValue = timeout,
|
||||||
DataBuffer = Marshal.AllocHGlobal(buffer.Length)
|
DataBuffer = Marshal.AllocHGlobal(buffer.Length)
|
||||||
@@ -91,7 +101,7 @@ static class Command
|
|||||||
|
|
||||||
DateTime start = DateTime.Now;
|
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 sptdSb,
|
||||||
(uint)Marshal.SizeOf(sptdSb), ref k, IntPtr.Zero);
|
(uint)Marshal.SizeOf(sptdSb), ref k, IntPtr.Zero);
|
||||||
|
|
||||||
@@ -114,20 +124,15 @@ static class Command
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends an ATA command in CHS mode</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
public override int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
||||||
/// <param name="fd">File handle</param>
|
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||||
/// <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)
|
|
||||||
{
|
{
|
||||||
|
// We need a timeout
|
||||||
|
if(timeout == 0)
|
||||||
|
timeout = Timeout > 0 ? Timeout : 15;
|
||||||
|
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
errorRegisters = new AtaErrorRegistersChs();
|
errorRegisters = new AtaErrorRegistersChs();
|
||||||
@@ -191,7 +196,7 @@ static class Command
|
|||||||
|
|
||||||
DateTime start = DateTime.Now;
|
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,
|
(uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
|
||||||
IntPtr.Zero);
|
IntPtr.Zero);
|
||||||
|
|
||||||
@@ -219,20 +224,15 @@ static class Command
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends an ATA command in 28-bit LBA mode</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
public override int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters,
|
||||||
/// <param name="fd">File handle</param>
|
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||||
/// <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)
|
|
||||||
{
|
{
|
||||||
|
// We need a timeout
|
||||||
|
if(timeout == 0)
|
||||||
|
timeout = Timeout > 0 ? Timeout : 15;
|
||||||
|
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
errorRegisters = new AtaErrorRegistersLba28();
|
errorRegisters = new AtaErrorRegistersLba28();
|
||||||
@@ -296,7 +296,7 @@ static class Command
|
|||||||
|
|
||||||
DateTime start = DateTime.Now;
|
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,
|
(uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
|
||||||
IntPtr.Zero);
|
IntPtr.Zero);
|
||||||
|
|
||||||
@@ -324,20 +324,15 @@ static class Command
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends an ATA command in 48-bit LBA mode</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
public override int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters,
|
||||||
/// <param name="fd">File handle</param>
|
AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer,
|
||||||
/// <param name="buffer">Buffer for SCSI command response</param>
|
uint timeout, bool transferBlocks, out double duration, out bool sense)
|
||||||
/// <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)
|
|
||||||
{
|
{
|
||||||
|
// We need a timeout
|
||||||
|
if(timeout == 0)
|
||||||
|
timeout = Timeout > 0 ? Timeout : 15;
|
||||||
|
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
errorRegisters = new AtaErrorRegistersLba48();
|
errorRegisters = new AtaErrorRegistersLba48();
|
||||||
@@ -410,7 +405,7 @@ static class Command
|
|||||||
|
|
||||||
DateTime start = DateTime.Now;
|
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,
|
(uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k,
|
||||||
IntPtr.Zero);
|
IntPtr.Zero);
|
||||||
|
|
||||||
@@ -458,25 +453,67 @@ static class Command
|
|||||||
queryData1.protocolGuid.Equals(Consts.GuidSffProtocolMmc);
|
queryData1.protocolGuid.Equals(Consts.GuidSffProtocolMmc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Sends a MMC/SD command</summary>
|
/// <inheritdoc />
|
||||||
/// <returns>The result of the command.</returns>
|
public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags,
|
||||||
/// <param name="fd">File handle</param>
|
uint argument, uint blockSize, uint blocks, ref byte[] buffer,
|
||||||
/// <param name="command">MMC/SD opcode</param>
|
out uint[] response, out double duration, out bool sense, uint timeout = 15)
|
||||||
/// <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)
|
|
||||||
{
|
{
|
||||||
|
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 commandData = new SffdiskDeviceCommandData();
|
||||||
var commandDescriptor = new SdCmdDescriptor();
|
var commandDescriptor = new SdCmdDescriptor();
|
||||||
commandData.size = (ushort)Marshal.SizeOf(commandData);
|
commandData.size = (ushort)Marshal.SizeOf(commandData);
|
||||||
@@ -531,13 +568,13 @@ static class Command
|
|||||||
Marshal.Copy(hBuf, commandB, 0, commandB.Length);
|
Marshal.Copy(hBuf, commandB, 0, commandB.Length);
|
||||||
Marshal.FreeHGlobal(hBuf);
|
Marshal.FreeHGlobal(hBuf);
|
||||||
|
|
||||||
var error = 0;
|
var error = 0;
|
||||||
DateTime start = DateTime.Now;
|
start = DateTime.Now;
|
||||||
|
|
||||||
sense = !Extern.DeviceIoControl(fd, WindowsIoctl.IoctlSffdiskDeviceCommand, commandB, (uint)commandB.Length,
|
sense = !Extern.DeviceIoControl(_fileHandle, WindowsIoctl.IoctlSffdiskDeviceCommand, commandB,
|
||||||
commandB, (uint)commandB.Length, out _, IntPtr.Zero);
|
(uint)commandB.Length, commandB, (uint)commandB.Length, out _, IntPtr.Zero);
|
||||||
|
|
||||||
DateTime end = DateTime.Now;
|
end = DateTime.Now;
|
||||||
|
|
||||||
if(sense)
|
if(sense)
|
||||||
error = Marshal.GetLastWin32Error();
|
error = Marshal.GetLastWin32Error();
|
||||||
@@ -551,9 +588,14 @@ static class Command
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static int SendMultipleMmcCommands(SafeFileHandle fd, Device.MmcSingleCommand[] commands,
|
/// <inheritdoc />
|
||||||
out double duration, out bool sense, uint timeout = 0)
|
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;
|
var error = 0;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
sense = false;
|
sense = false;
|
||||||
@@ -562,13 +604,13 @@ static class Command
|
|||||||
commands[0].command == MmcCommands.SetBlocklen &&
|
commands[0].command == MmcCommands.SetBlocklen &&
|
||||||
commands[1].command == MmcCommands.ReadMultipleBlock &&
|
commands[1].command == MmcCommands.ReadMultipleBlock &&
|
||||||
commands[2].command == MmcCommands.StopTransmission)
|
commands[2].command == MmcCommands.StopTransmission)
|
||||||
return SendMmcCommand(fd, commands[1].command, commands[1].write, commands[1].isApplication,
|
return SendMmcCommand(commands[1].command, commands[1].write, commands[1].isApplication, commands[1].flags,
|
||||||
commands[1].flags, commands[1].argument, commands[1].blockSize, commands[1].blocks,
|
commands[1].argument, commands[1].blockSize, commands[1].blocks,
|
||||||
ref commands[1].buffer, out commands[1].response, out duration, out sense, timeout);
|
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,
|
command.argument, command.blockSize, command.blocks, ref command.buffer,
|
||||||
out command.response, out double cmdDuration, out bool cmdSense, timeout);
|
out command.response, out double cmdDuration, out bool cmdSense, timeout);
|
||||||
|
|
||||||
@@ -585,25 +627,36 @@ static class Command
|
|||||||
return error;
|
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,
|
SafeFileHandle newFd = Extern.CreateFile(_devicePath, FileAccess.GenericRead | FileAccess.GenericWrite,
|
||||||
FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting,
|
FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting,
|
||||||
FileAttributes.Normal, IntPtr.Zero);
|
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,
|
/// <inheritdoc />
|
||||||
out double duration)
|
public override bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration)
|
||||||
{
|
{
|
||||||
buffer = new byte[length];
|
buffer = new byte[length];
|
||||||
|
|
||||||
DateTime start = DateTime.Now;
|
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;
|
DateTime end = DateTime.Now;
|
||||||
|
|
||||||
@@ -611,14 +664,27 @@ static class Command
|
|||||||
{
|
{
|
||||||
duration = (end - start).TotalMilliseconds;
|
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;
|
end = DateTime.Now;
|
||||||
duration = (end - start).TotalMilliseconds;
|
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 />
|
/// <inheritdoc />
|
||||||
[SupportedOSPlatform("windows")]
|
[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() {}
|
Device() {}
|
||||||
|
|
||||||
public new static Device Create(string devicePath)
|
internal new static Device Create(string devicePath)
|
||||||
{
|
{
|
||||||
var dev = new Device
|
var dev = new Device
|
||||||
{
|
{
|
||||||
PlatformId = DetectOS.GetRealPlatformID(),
|
PlatformId = DetectOS.GetRealPlatformID(),
|
||||||
Timeout = 15,
|
Timeout = 15,
|
||||||
Error = false,
|
Error = false,
|
||||||
IsRemovable = 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,
|
if(dev._fileHandle.IsInvalid)
|
||||||
FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting,
|
|
||||||
FileAttributes.Normal, IntPtr.Zero);
|
|
||||||
|
|
||||||
if(((SafeFileHandle)dev.FileHandle).IsInvalid)
|
|
||||||
{
|
{
|
||||||
dev.Error = true;
|
dev.Error = true;
|
||||||
dev.LastError = Marshal.GetLastWin32Error();
|
dev.LastError = Marshal.GetLastWin32Error();
|
||||||
@@ -73,9 +76,6 @@ public class Device : Devices.Device
|
|||||||
dev.Type = DeviceType.Unknown;
|
dev.Type = DeviceType.Unknown;
|
||||||
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
||||||
|
|
||||||
byte[] ataBuf;
|
|
||||||
byte[] inqBuf = null;
|
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
throw new DeviceException(dev.LastError);
|
throw new DeviceException(dev.LastError);
|
||||||
|
|
||||||
@@ -91,9 +91,8 @@ public class Device : Devices.Device
|
|||||||
uint returned = 0;
|
uint returned = 0;
|
||||||
var error = 0;
|
var error = 0;
|
||||||
|
|
||||||
bool hasError = !Extern.DeviceIoControlStorageQuery((SafeFileHandle)dev.FileHandle,
|
bool hasError = !Extern.DeviceIoControlStorageQuery(dev._fileHandle, WindowsIoctl.IoctlStorageQueryProperty,
|
||||||
WindowsIoctl.IoctlStorageQueryProperty, ref query,
|
ref query, (uint)Marshal.SizeOf(query), descriptorPtr, 1000,
|
||||||
(uint)Marshal.SizeOf(query), descriptorPtr, 1000,
|
|
||||||
ref returned, IntPtr.Zero);
|
ref returned, IntPtr.Zero);
|
||||||
|
|
||||||
if(hasError)
|
if(hasError)
|
||||||
@@ -170,7 +169,7 @@ public class Device : Devices.Device
|
|||||||
switch(dev.Type)
|
switch(dev.Type)
|
||||||
{
|
{
|
||||||
case DeviceType.ATA:
|
case DeviceType.ATA:
|
||||||
bool atapiSense = dev.AtapiIdentify(out ataBuf, out _);
|
bool atapiSense = dev.AtapiIdentify(out byte[] _, out _);
|
||||||
|
|
||||||
if(!atapiSense)
|
if(!atapiSense)
|
||||||
dev.Type = DeviceType.ATAPI;
|
dev.Type = DeviceType.ATAPI;
|
||||||
@@ -183,13 +182,13 @@ public class Device : Devices.Device
|
|||||||
|
|
||||||
Marshal.FreeHGlobal(descriptorPtr);
|
Marshal.FreeHGlobal(descriptorPtr);
|
||||||
|
|
||||||
if(Command.IsSdhci((SafeFileHandle)dev.FileHandle))
|
if(IsSdhci(dev._fileHandle))
|
||||||
{
|
{
|
||||||
var sdBuffer = new byte[16];
|
var sdBuffer = new byte[16];
|
||||||
|
|
||||||
dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle, MmcCommands.SendCsd, false, false,
|
dev.LastError = dev.SendMmcCommand(MmcCommands.SendCsd, false, false,
|
||||||
MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0,
|
MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16,
|
||||||
16, 1, ref sdBuffer, out _, out _, out bool sense);
|
1, ref sdBuffer, out _, out _, out bool sense);
|
||||||
|
|
||||||
if(!sense)
|
if(!sense)
|
||||||
{
|
{
|
||||||
@@ -199,9 +198,9 @@ public class Device : Devices.Device
|
|||||||
|
|
||||||
sdBuffer = new byte[16];
|
sdBuffer = new byte[16];
|
||||||
|
|
||||||
dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle, MmcCommands.SendCid, false, false,
|
dev.LastError = dev.SendMmcCommand(MmcCommands.SendCid, false, false,
|
||||||
MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0,
|
MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16,
|
||||||
16, 1, ref sdBuffer, out _, out _, out sense);
|
1, ref sdBuffer, out _, out _, out sense);
|
||||||
|
|
||||||
if(!sense)
|
if(!sense)
|
||||||
{
|
{
|
||||||
@@ -211,10 +210,9 @@ public class Device : Devices.Device
|
|||||||
|
|
||||||
sdBuffer = new byte[8];
|
sdBuffer = new byte[8];
|
||||||
|
|
||||||
dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle,
|
dev.LastError = dev.SendMmcCommand((MmcCommands)SecureDigitalCommands.SendScr, false, true,
|
||||||
(MmcCommands)SecureDigitalCommands.SendScr, false, true,
|
MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, 0,
|
||||||
MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc,
|
8, 1, ref sdBuffer, out _, out _, out sense);
|
||||||
0, 8, 1, ref sdBuffer, out _, out _, out sense);
|
|
||||||
|
|
||||||
if(!sense)
|
if(!sense)
|
||||||
{
|
{
|
||||||
@@ -224,12 +222,10 @@ public class Device : Devices.Device
|
|||||||
|
|
||||||
sdBuffer = new byte[4];
|
sdBuffer = new byte[4];
|
||||||
|
|
||||||
dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle,
|
dev.LastError =
|
||||||
dev._cachedScr != null
|
dev.SendMmcCommand(dev._cachedScr != null ? (MmcCommands)SecureDigitalCommands.SendOperatingCondition : MmcCommands.SendOpCond,
|
||||||
? (MmcCommands)SecureDigitalCommands.SendOperatingCondition
|
false, true, MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, 0,
|
||||||
: MmcCommands.SendOpCond, false, true,
|
4, 1, ref sdBuffer, out _, out _, out sense);
|
||||||
MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr,
|
|
||||||
0, 4, 1, ref sdBuffer, out _, out _, out sense);
|
|
||||||
|
|
||||||
if(!sense)
|
if(!sense)
|
||||||
{
|
{
|
||||||
@@ -318,11 +314,11 @@ public class Device : Devices.Device
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Close()
|
public override void Close()
|
||||||
{
|
{
|
||||||
if(FileHandle == null)
|
if(_fileHandle == null)
|
||||||
return;
|
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);
|
var dev = Device.Create(deviceModel.Path);
|
||||||
|
|
||||||
if(dev.IsRemote)
|
if(dev is Devices.Remote.Device remoteDev)
|
||||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion,
|
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||||
dev.RemoteOperatingSystem, dev.RemoteOperatingSystemVersion,
|
remoteDev.RemoteOperatingSystem,
|
||||||
dev.RemoteArchitecture);
|
remoteDev.RemoteOperatingSystemVersion,
|
||||||
|
remoteDev.RemoteArchitecture);
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
{
|
{
|
||||||
@@ -789,9 +790,10 @@ public sealed class MainWindowViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
var dev = Device.Create(device.Path);
|
var dev = Device.Create(device.Path);
|
||||||
|
|
||||||
if(dev.IsRemote)
|
if(dev is Devices.Remote.Device remoteDev)
|
||||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||||
|
remoteDev.RemoteArchitecture);
|
||||||
|
|
||||||
switch(dev.Type)
|
switch(dev.Type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -728,9 +728,10 @@ public sealed class MediaDumpViewModel : ViewModelBase
|
|||||||
{
|
{
|
||||||
_dev = Device.Create(_devicePath);
|
_dev = Device.Create(_devicePath);
|
||||||
|
|
||||||
if(_dev.IsRemote)
|
if(_dev is Devices.Remote.Device remoteDev)
|
||||||
Statistics.AddRemote(_dev.RemoteApplication, _dev.RemoteVersion, _dev.RemoteOperatingSystem,
|
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||||
_dev.RemoteOperatingSystemVersion, _dev.RemoteArchitecture);
|
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||||
|
remoteDev.RemoteArchitecture);
|
||||||
|
|
||||||
if(_dev.Error)
|
if(_dev.Error)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -330,9 +330,9 @@ public sealed class MediaScanViewModel : ViewModelBase
|
|||||||
|
|
||||||
var dev = Device.Create(_devicePath);
|
var dev = Device.Create(_devicePath);
|
||||||
|
|
||||||
if(dev.IsRemote)
|
if(dev is Devices.Remote.Device remoteDev)
|
||||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, remoteDev.RemoteOperatingSystem,
|
||||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
remoteDev.RemoteOperatingSystemVersion, remoteDev.RemoteArchitecture);
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ static partial class MainClass
|
|||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
AaruConsole.WriteLine("dev.PlatformID = {0}", dev.PlatformId);
|
AaruConsole.WriteLine("dev.PlatformID = {0}", dev.PlatformId);
|
||||||
AaruConsole.WriteLine("dev.FileHandle = {0}", dev.FileHandle);
|
|
||||||
AaruConsole.WriteLine("dev.Timeout = {0}", dev.Timeout);
|
AaruConsole.WriteLine("dev.Timeout = {0}", dev.Timeout);
|
||||||
AaruConsole.WriteLine("dev.Error = {0}", dev.Error);
|
AaruConsole.WriteLine("dev.Error = {0}", dev.Error);
|
||||||
AaruConsole.WriteLine("dev.LastError = {0}", dev.LastError);
|
AaruConsole.WriteLine("dev.LastError = {0}", dev.LastError);
|
||||||
|
|||||||
@@ -130,9 +130,10 @@ sealed class DeviceReportCommand : Command
|
|||||||
{
|
{
|
||||||
dev = Device.Create(devicePath);
|
dev = Device.Create(devicePath);
|
||||||
|
|
||||||
if(dev.IsRemote)
|
if(dev is Devices.Remote.Device remoteDev)
|
||||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||||
|
remoteDev.RemoteArchitecture);
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
{
|
{
|
||||||
@@ -150,7 +151,7 @@ sealed class DeviceReportCommand : Command
|
|||||||
|
|
||||||
Statistics.AddDevice(dev);
|
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)
|
if(!isAdmin)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -134,9 +134,10 @@ sealed class DeviceInfoCommand : Command
|
|||||||
{
|
{
|
||||||
dev = Device.Create(devicePath);
|
dev = Device.Create(devicePath);
|
||||||
|
|
||||||
if(dev.IsRemote)
|
if(dev is Devices.Remote.Device remoteDev)
|
||||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||||
|
remoteDev.RemoteArchitecture);
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -546,9 +546,10 @@ sealed class DumpMediaCommand : Command
|
|||||||
dev = Device.Create(devicePath);
|
dev = Device.Create(devicePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(dev.IsRemote)
|
if(dev is Devices.Remote.Device remoteDev)
|
||||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||||
|
remoteDev.RemoteArchitecture);
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -139,9 +139,10 @@ sealed class MediaInfoCommand : Command
|
|||||||
dev = Device.Create(devicePath);
|
dev = Device.Create(devicePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(dev.IsRemote)
|
if(dev is Devices.Remote.Device remoteDev)
|
||||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||||
|
remoteDev.RemoteArchitecture);
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -140,9 +140,10 @@ sealed class MediaScanCommand : Command
|
|||||||
dev = Device.Create(devicePath);
|
dev = Device.Create(devicePath);
|
||||||
});
|
});
|
||||||
|
|
||||||
if(dev.IsRemote)
|
if(dev is Devices.Remote.Device remoteDev)
|
||||||
Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem,
|
Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion,
|
||||||
dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture);
|
remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion,
|
||||||
|
remoteDev.RemoteArchitecture);
|
||||||
|
|
||||||
if(dev.Error)
|
if(dev.Error)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user