diff --git a/Aaru.Core/Devices/Dumping/XGD.cs b/Aaru.Core/Devices/Dumping/XGD.cs index 0af215e92..e198cf5db 100644 --- a/Aaru.Core/Devices/Dumping/XGD.cs +++ b/Aaru.Core/Devices/Dumping/XGD.cs @@ -51,6 +51,7 @@ using Aaru.Decoders.SCSI; using Aaru.Decoders.Xbox; using Aaru.Devices; using Schemas; +using Device = Aaru.Devices.Remote.Device; using PlatformID = Aaru.CommonTypes.Interop.PlatformID; using TrackType = Aaru.CommonTypes.Enums.TrackType; using Version = Aaru.CommonTypes.Interop.Version; @@ -82,7 +83,7 @@ partial class Dump if(DetectOS.GetRealPlatformID() != PlatformID.Win32NT) { - bool isAdmin = _dev.IsRemote ? _dev.IsRemoteAdmin : DetectOS.IsAdmin; + bool isAdmin = _dev is Device remoteDev ? remoteDev.IsAdmin : DetectOS.IsAdmin; if(!isAdmin) { diff --git a/Aaru.Core/Logging/DumpLog.cs b/Aaru.Core/Logging/DumpLog.cs index 270ebcf00..6184b888e 100644 --- a/Aaru.Core/Logging/DumpLog.cs +++ b/Aaru.Core/Logging/DumpLog.cs @@ -114,17 +114,18 @@ public sealed class DumpLog _logSw.WriteLine(); - if(dev.IsRemote) + if(dev is Aaru.Devices.Remote.Device remoteDev) { _logSw.WriteLine("################# Remote information #################"); - _logSw.WriteLine("Server: {0}", dev.RemoteApplication); - _logSw.WriteLine("Version: {0}", dev.RemoteVersion); + _logSw.WriteLine("Server: {0}", remoteDev.RemoteApplication); + _logSw.WriteLine("Version: {0}", remoteDev.RemoteVersion); - _logSw.WriteLine("Operating system: {0} {1}", dev.RemoteOperatingSystem, dev.RemoteOperatingSystemVersion); + _logSw.WriteLine("Operating system: {0} {1}", remoteDev.RemoteOperatingSystem, + remoteDev.RemoteOperatingSystemVersion); - _logSw.WriteLine("Architecture: {0}", dev.RemoteArchitecture); - _logSw.WriteLine("Protocol version: {0}", dev.RemoteProtocolVersion); - _logSw.WriteLine("Running as superuser: {0}", dev.IsRemoteAdmin ? "Yes" : "No"); + _logSw.WriteLine("Architecture: {0}", remoteDev.RemoteArchitecture); + _logSw.WriteLine("Protocol version: {0}", remoteDev.RemoteProtocolVersion); + _logSw.WriteLine("Running as superuser: {0}", remoteDev.IsAdmin ? "Yes" : "No"); _logSw.WriteLine("######################################################"); } diff --git a/Aaru.Devices/Aaru.Devices.csproj b/Aaru.Devices/Aaru.Devices.csproj index 7811699e2..049e5053c 100644 --- a/Aaru.Devices/Aaru.Devices.csproj +++ b/Aaru.Devices/Aaru.Devices.csproj @@ -65,6 +65,7 @@ + @@ -77,7 +78,6 @@ - diff --git a/Aaru.Devices/Command.cs b/Aaru.Devices/Command.cs deleted file mode 100644 index 821c45b51..000000000 --- a/Aaru.Devices/Command.cs +++ /dev/null @@ -1,434 +0,0 @@ -// /*************************************************************************** -// Aaru Data Preservation Suite -// ---------------------------------------------------------------------------- -// -// Filename : Command.cs -// Author(s) : Natalia Portillo -// -// 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 . -// -// ---------------------------------------------------------------------------- -// 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 -{ - /// Sends a SCSI command - /// 0 if no error occurred, otherwise, errno - /// File handle - /// SCSI CDB - /// Buffer for SCSI command response - /// Buffer with the SCSI sense - /// Timeout in seconds - /// SCSI command transfer direction - /// Time it took to execute the command in milliseconds - /// - /// True if SCSI error returned non-OK status and contains SCSI - /// sense - /// - /// If the specified platform is not supported - 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); - } - - /// Sends a SCSI command - /// 0 if no error occurred, otherwise, errno - /// Platform ID for executing the command - /// File handle - /// SCSI CDB - /// Buffer for SCSI command response - /// Buffer with the SCSI sense - /// Timeout in seconds - /// SCSI command transfer direction - /// Time it took to execute the command in milliseconds - /// - /// True if SCSI error returned non-OK status and contains SCSI - /// sense - /// - /// If the specified platform is not supported - 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."); - } - } - - /// Sends an ATA command in CHS format - /// 0 if no error occurred, otherwise, errno - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA returned non-OK status - /// Registers to send to the device - /// Registers returned by the device - /// ATA protocol to use - /// What register contains the transfer length - /// Set to true if the transfer length is in block, otherwise it is in bytes - /// If the specified platform is not supported - 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); - } - - /// Sends an ATA command in CHS format - /// 0 if no error occurred, otherwise, errno - /// Platform ID for executing the command - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA returned non-OK status - /// Registers to send to the device - /// Registers returned by the device - /// ATA protocol to use - /// What register contains the transfer length - /// Set to true if the transfer length is in block, otherwise it is in bytes - /// If the specified platform is not supported - 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."); - } - } - - /// Sends an ATA command in CHS format - /// 0 if no error occurred, otherwise, errno - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA returned non-OK status - /// Registers to send to the device - /// Registers returned by the device - /// ATA protocol to use - /// What register contains the transfer length - /// Set to true if the transfer length is in block, otherwise it is in bytes - /// If the specified platform is not supported - 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); - } - - /// Sends an ATA command in 28-bit LBA format - /// 0 if no error occurred, otherwise, errno - /// Platform ID for executing the command - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA returned non-OK status - /// Registers to send to the device - /// Registers returned by the device - /// ATA protocol to use - /// What register contains the transfer length - /// Set to true if the transfer length is in block, otherwise it is in bytes - /// If the specified platform is not supported - 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."); - } - } - - /// Sends an ATA command in 48-bit LBA format - /// 0 if no error occurred, otherwise, errno - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA returned non-OK status - /// Registers to send to the device - /// Registers returned by the device - /// ATA protocol to use - /// What register contains the transfer length - /// Set to true if the transfer length is in block, otherwise it is in bytes - /// If the specified platform is not supported - 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); - } - - /// Sends an ATA command in 48-bit format - /// 0 if no error occurred, otherwise, errno - /// Platform ID for executing the command - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA returned non-OK status - /// Registers to send to the device - /// Registers returned by the device - /// ATA protocol to use - /// What register contains the transfer length - /// Set to true if the transfer length is in block, otherwise it is in bytes - /// If the specified platform is not supported - 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."); - } - } - - /// Sends a MMC/SD command - /// The result of the command. - /// File handle - /// MMC/SD opcode - /// Buffer for MMC/SD command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if MMC/SD returned non-OK status - /// True if data is sent from host to card - /// True if command should be preceded with CMD55 - /// Flags indicating kind and place of response - /// How many blocks to transfer - /// Command argument - /// Response registers - /// Size of block in bytes - /// If the specified platform is not supported - 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); - } - - /// Sends a MMC/SD command - /// The result of the command. - /// Platform ID for executing the command - /// File handle - /// MMC/SD opcode - /// Buffer for MMC/SD command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if MMC/SD returned non-OK status - /// True if data is sent from host to card - /// True if command should be preceded with CMD55 - /// Flags indicating kind and place of response - /// How many blocks to transfer - /// Command argument - /// Response registers - /// Size of block in bytes - /// If the specified platform is not supported - 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."); - } - } -} \ No newline at end of file diff --git a/Aaru.Devices/Device/Commands.cs b/Aaru.Devices/Device/Commands.cs index 8a79de53c..ffc2b8f22 100644 --- a/Aaru.Devices/Device/Commands.cs +++ b/Aaru.Devices/Device/Commands.cs @@ -32,7 +32,6 @@ namespace Aaru.Devices; -using System; using System.Diagnostics.CodeAnalysis; using Aaru.Decoders.ATA; @@ -51,19 +50,14 @@ public partial class Device /// True if SCSI command returned non-OK status and contains /// SCSI sense /// - public int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, - ScsiDirection direction, out double duration, out bool sense) + public virtual int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, + ScsiDirection direction, out double duration, out bool sense) { - // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + duration = 0; + sense = true; + senseBuffer = null; - if(!(_remote is null)) - return _remote.SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, direction, out duration, - out sense); - - return Command.SendScsiCommand(PlatformId, FileHandle, cdb, ref buffer, out senseBuffer, timeout, direction, - out duration, out sense); + return -1; } /// Sends an ATA/ATAPI command to this device using CHS addressing @@ -80,20 +74,15 @@ public partial class Device /// /// Time it took to execute the command in milliseconds /// True if ATA/ATAPI command returned non-OK status - public int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol, - AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, - bool transferBlocks, out double duration, out bool sense) + public virtual int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, + AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, + uint timeout, bool transferBlocks, out double duration, out bool sense) { - // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + duration = 0; + sense = true; + errorRegisters = default(AtaErrorRegistersChs); - if(!(_remote is null)) - return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, - timeout, transferBlocks, out duration, out sense); - - return Command.SendAtaCommand(PlatformId, FileHandle, registers, out errorRegisters, protocol, transferRegister, - ref buffer, timeout, transferBlocks, out duration, out sense); + return -1; } /// Sends an ATA/ATAPI command to this device using 28-bit LBA addressing @@ -110,20 +99,15 @@ public partial class Device /// /// Time it took to execute the command in milliseconds /// True if ATA/ATAPI command returned non-OK status - public int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, - AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, - uint timeout, bool transferBlocks, out double duration, out bool sense) + public virtual int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, + AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, + uint timeout, bool transferBlocks, out double duration, out bool sense) { - // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + errorRegisters = default(AtaErrorRegistersLba28); + duration = 0; + sense = true; - if(!(_remote is null)) - return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, - timeout, transferBlocks, out duration, out sense); - - return Command.SendAtaCommand(PlatformId, FileHandle, registers, out errorRegisters, protocol, transferRegister, - ref buffer, timeout, transferBlocks, out duration, out sense); + return -1; } /// Sends an ATA/ATAPI command to this device using 48-bit LBA addressing @@ -140,20 +124,15 @@ public partial class Device /// /// Time it took to execute the command in milliseconds /// True if ATA/ATAPI command returned non-OK status - public int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, - AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, - uint timeout, bool transferBlocks, out double duration, out bool sense) + public virtual int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, + AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, + uint timeout, bool transferBlocks, out double duration, out bool sense) { - // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + errorRegisters = default(AtaErrorRegistersLba48); + duration = 0; + sense = true; - if(!(_remote is null)) - return _remote.SendAtaCommand(registers, out errorRegisters, protocol, transferRegister, ref buffer, - timeout, transferBlocks, out duration, out sense); - - return Command.SendAtaCommand(PlatformId, FileHandle, registers, out errorRegisters, protocol, transferRegister, - ref buffer, timeout, transferBlocks, out duration, out sense); + return -1; } /// Sends a MMC/SD command to this device @@ -170,74 +149,15 @@ public partial class Device /// Command argument /// Response registers /// Size of block in bytes - public int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, uint argument, - uint blockSize, uint blocks, ref byte[] buffer, out uint[] response, out double duration, - out bool sense, uint timeout = 15) + public virtual int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, + uint argument, uint blockSize, uint blocks, ref byte[] buffer, + out uint[] response, out double duration, out bool sense, uint timeout = 15) { - // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; + response = null; + duration = 0; + sense = true; - switch(command) - { - case MmcCommands.SendCid when _cachedCid != null: - { - DateTime start = DateTime.Now; - buffer = new byte[_cachedCid.Length]; - Array.Copy(_cachedCid, buffer, buffer.Length); - response = new uint[4]; - sense = false; - DateTime end = DateTime.Now; - duration = (end - start).TotalMilliseconds; - - return 0; - } - case MmcCommands.SendCsd when _cachedCid != null: - { - DateTime start = DateTime.Now; - buffer = new byte[_cachedCsd.Length]; - Array.Copy(_cachedCsd, buffer, buffer.Length); - response = new uint[4]; - sense = false; - DateTime end = DateTime.Now; - duration = (end - start).TotalMilliseconds; - - return 0; - } - case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null: - { - DateTime start = DateTime.Now; - buffer = new byte[_cachedScr.Length]; - Array.Copy(_cachedScr, buffer, buffer.Length); - response = new uint[4]; - sense = false; - DateTime end = DateTime.Now; - duration = (end - start).TotalMilliseconds; - - return 0; - } - case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null: - case MmcCommands.SendOpCond when _cachedOcr != null: - { - DateTime start = DateTime.Now; - buffer = new byte[_cachedOcr.Length]; - Array.Copy(_cachedOcr, buffer, buffer.Length); - response = new uint[4]; - sense = false; - DateTime end = DateTime.Now; - duration = (end - start).TotalMilliseconds; - - return 0; - } - } - - return _remote is null - ? Command.SendMmcCommand(PlatformId, FileHandle, command, write, isApplication, flags, argument, - blockSize, blocks, ref buffer, out response, out duration, out sense, - timeout) : _remote.SendMmcCommand(command, write, isApplication, flags, - argument, blockSize, blocks, ref buffer, - out response, out duration, out sense, - timeout); + return -1; } /// Encapsulates a single MMC command to send in a queue @@ -273,59 +193,18 @@ public partial class Device /// Set to true if any of the commands returned an error status, false otherwise /// Maximum allowed time to execute a single command /// 0 if no error occurred, otherwise, errno - public int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense, - uint timeout = 15) + public virtual int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense, + uint timeout = 15) { - // We need a timeout - if(timeout == 0) - timeout = Timeout > 0 ? Timeout : 15; - - if(_remote is null) - return Command.SendMultipleMmcCommands(PlatformId, FileHandle, commands, out duration, out sense, timeout); - - if(_remote.ServerProtocolVersion >= 2) - return _remote.SendMultipleMmcCommands(commands, out duration, out sense, timeout); - - var error = 0; duration = 0; - sense = false; + sense = true; - foreach(MmcSingleCommand command in commands) - { - int singleError = _remote.SendMmcCommand(command.command, command.write, command.isApplication, - command.flags, command.argument, command.blockSize, command.blocks, - ref command.buffer, out command.response, out double cmdDuration, - out bool cmdSense, timeout); - - if(error == 0 && - singleError != 0) - error = singleError; - - duration += cmdDuration; - - if(cmdSense) - sense = true; - } - - return error; + return -1; } /// Closes then immediately reopens a device /// Returned error number if any - public bool ReOpen() - { - if(!(_remote is null)) - return _remote.ReOpen(); - - int ret = Command.ReOpen(PlatformId, _devicePath, FileHandle, out object newFileHandle); - - FileHandle = newFileHandle; - - Error = ret != 0; - LastError = ret; - - return Error; - } + public virtual bool ReOpen() => false; /// Reads data using operating system buffers. /// Data buffer @@ -333,16 +212,11 @@ public partial class Device /// Number of bytes to read /// Total time in milliseconds the reading took /// true if there was an error, false otherwise - public bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration) + public virtual bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration) { - if(!(_remote is null)) - return _remote.BufferedOsRead(out buffer, offset, length, out duration); + buffer = null; + duration = 0; - int ret = Command.BufferedOsRead(PlatformId, FileHandle, out buffer, offset, length, out duration); - - Error = ret != 0; - LastError = ret; - - return Error; + return false; } } \ No newline at end of file diff --git a/Aaru.Devices/Device/Variables.cs b/Aaru.Devices/Device/Variables.cs index 7e1d5dac6..5280936e3 100644 --- a/Aaru.Devices/Device/Variables.cs +++ b/Aaru.Devices/Device/Variables.cs @@ -55,10 +55,6 @@ public partial class Device /// The Platform ID public PlatformID PlatformId { get; private protected set; } - /// Gets the file handle representing this device - /// The file handle - public object FileHandle { get; private protected set; } - /// Gets or sets the standard timeout for commands sent to this device /// The timeout in seconds public uint Timeout { get; set; } @@ -162,33 +158,5 @@ public partial class Device /// Contains the PCMCIA CIS if applicable public byte[] Cis { get; private protected set; } - private protected Remote.Remote _remote; - bool? _isRemoteAdmin; private protected string _devicePath; - - /// Returns if remote is running under administrative (aka root) privileges - public bool IsRemoteAdmin - { - get - { - _isRemoteAdmin ??= _remote.IsRoot; - - return _isRemoteAdmin == true; - } - } - - /// Current device is remote - public bool IsRemote => _remote != null; - /// Remote application - public string RemoteApplication => _remote?.ServerApplication; - /// Remote application server - public string RemoteVersion => _remote?.ServerVersion; - /// Remote operating system name - public string RemoteOperatingSystem => _remote?.ServerOperatingSystem; - /// Remote operating system version - public string RemoteOperatingSystemVersion => _remote?.ServerOperatingSystemVersion; - /// Remote architecture - public string RemoteArchitecture => _remote?.ServerArchitecture; - /// Remote protocol version - public int RemoteProtocolVersion => _remote?.ServerProtocolVersion ?? 0; } \ No newline at end of file diff --git a/Aaru.Devices/Linux/Command.cs b/Aaru.Devices/Linux/Command.cs index c7259440b..fd4e53237 100644 --- a/Aaru.Devices/Linux/Command.cs +++ b/Aaru.Devices/Linux/Command.cs @@ -39,24 +39,16 @@ using System.Text; using Aaru.CommonTypes.Interop; using Aaru.Decoders.ATA; -static class Command +partial class Device { - /// Sends a SCSI command - /// 0 if no error occurred, otherwise, errno - /// File handle - /// SCSI CDB - /// Buffer for SCSI command response - /// Buffer with the SCSI sense - /// Timeout in seconds - /// SCSI command transfer direction - /// Time it took to execute the command in milliseconds - /// - /// True if SCSI error returned non-OK status and contains SCSI - /// sense - /// - internal static int SendScsiCommand(int fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, - ScsiIoctlDirection direction, out double duration, out bool sense) + /// + public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, + ScsiDirection direction, out double duration, out bool sense) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + senseBuffer = null; duration = 0; sense = false; @@ -64,6 +56,32 @@ static class Command if(buffer == null) return -1; + ScsiIoctlDirection dir; + + switch(direction) + { + case ScsiDirection.In: + dir = ScsiIoctlDirection.In; + + break; + case ScsiDirection.Out: + dir = ScsiIoctlDirection.Out; + + break; + case ScsiDirection.Bidirectional: + dir = ScsiIoctlDirection.Unspecified; + + break; + case ScsiDirection.None: + dir = ScsiIoctlDirection.None; + + break; + default: + dir = ScsiIoctlDirection.Unknown; + + break; + } + var ioHdr = new SgIoHdrT(); senseBuffer = new byte[64]; @@ -71,7 +89,7 @@ static class Command ioHdr.interface_id = 'S'; ioHdr.cmd_len = (byte)cdb.Length; ioHdr.mx_sb_len = (byte)senseBuffer.Length; - ioHdr.dxfer_direction = direction; + ioHdr.dxfer_direction = dir; ioHdr.dxfer_len = (uint)buffer.Length; ioHdr.dxferp = Marshal.AllocHGlobal(buffer.Length); ioHdr.cmdp = Marshal.AllocHGlobal(cdb.Length); @@ -84,7 +102,7 @@ static class Command Marshal.Copy(senseBuffer, 0, ioHdr.sbp, senseBuffer.Length); DateTime start = DateTime.UtcNow; - int error = Extern.ioctlSg(fd, LinuxIoctl.SgIo, ref ioHdr); + int error = Extern.ioctlSg(_fileDescriptor, LinuxIoctl.SgIo, ref ioHdr); DateTime end = DateTime.UtcNow; if(error < 0) @@ -108,7 +126,7 @@ static class Command /// Converts ATA protocol to SG_IO direction /// ATA protocol /// SG_IO direction - static ScsiIoctlDirection AtaProtocolToScsiDirection(AtaProtocol protocol) + static ScsiDirection AtaProtocolToScsiDirection(AtaProtocol protocol) { switch(protocol) { @@ -117,31 +135,24 @@ static class Command case AtaProtocol.HardReset: case AtaProtocol.NonData: case AtaProtocol.SoftReset: - case AtaProtocol.ReturnResponse: return ScsiIoctlDirection.None; + case AtaProtocol.ReturnResponse: return ScsiDirection.None; case AtaProtocol.PioIn: - case AtaProtocol.UDmaIn: return ScsiIoctlDirection.In; + case AtaProtocol.UDmaIn: return ScsiDirection.In; case AtaProtocol.PioOut: - case AtaProtocol.UDmaOut: return ScsiIoctlDirection.Out; - default: return ScsiIoctlDirection.Unspecified; + case AtaProtocol.UDmaOut: return ScsiDirection.Out; + default: return ScsiDirection.Unspecified; } } - /// Sends an ATA command in CHS mode - /// 0 if no error occurred, otherwise, errno - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA error returned non-OK status - /// Registers to send to drive - /// Registers returned by drive - /// ATA protocol to use - /// Which register contains the transfer count - /// Set to true if the transfer count is in blocks, otherwise it is in bytes - internal static int SendAtaCommand(int fd, AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, + /// + public override int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + duration = 0; sense = false; errorRegisters = new AtaErrorRegistersChs(); @@ -185,7 +196,7 @@ static class Command cdb[13] = registers.DeviceHead; cdb[14] = registers.Command; - int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout, + int error = SendScsiCommand(cdb, ref buffer, out byte[] senseBuffer, timeout, AtaProtocolToScsiDirection(protocol), out duration, out sense); if(senseBuffer.Length < 22 || @@ -206,22 +217,15 @@ static class Command return error; } - /// Sends an ATA command in 28-bit LBA mode - /// 0 if no error occurred, otherwise, errno - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA error returned non-OK status - /// Registers to send to drive - /// Registers returned by drive - /// ATA protocol to use - /// Which register contains the transfer count - /// Set to true if the transfer count is in blocks, otherwise it is in bytes - internal static int SendAtaCommand(int fd, AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, + /// + public override int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba28(); @@ -265,7 +269,7 @@ static class Command cdb[13] = registers.DeviceHead; cdb[14] = registers.Command; - int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout, + int error = SendScsiCommand(cdb, ref buffer, out byte[] senseBuffer, timeout, AtaProtocolToScsiDirection(protocol), out duration, out sense); if(senseBuffer.Length < 22 || @@ -286,22 +290,15 @@ static class Command return error; } - /// Sends an ATA command in 48-bit LBA mode - /// 0 if no error occurred, otherwise, errno - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA error returned non-OK status - /// Registers to send to drive - /// Registers returned by drive - /// ATA protocol to use - /// Which register contains the transfer count - /// Set to true if the transfer count is in blocks, otherwise it is in bytes - internal static int SendAtaCommand(int fd, AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, + /// + public override int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout, bool transferBlocks, out double duration, out bool sense) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba48(); @@ -351,7 +348,7 @@ static class Command cdb[13] = registers.DeviceHead; cdb[14] = registers.Command; - int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout, + int error = SendScsiCommand(cdb, ref buffer, out byte[] senseBuffer, timeout, AtaProtocolToScsiDirection(protocol), out duration, out sense); if(senseBuffer.Length < 22 || @@ -377,25 +374,71 @@ static class Command return error; } - /// Sends a MMC/SD command - /// The result of the command. - /// File handle - /// MMC/SD opcode - /// Buffer for MMC/SD command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if MMC/SD returned non-OK status - /// True if data is sent from host to card - /// True if command should be preceded with CMD55 - /// Flags indicating kind and place of response - /// How many blocks to transfer - /// Command argument - /// Response registers - /// Size of block in bytes - internal static int SendMmcCommand(int fd, MmcCommands command, bool write, bool isApplication, MmcFlags flags, + /// + public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, uint argument, uint blockSize, uint blocks, ref byte[] buffer, - out uint[] response, out double duration, out bool sense, uint timeout = 0) + out uint[] response, out double duration, out bool sense, uint timeout = 15) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + + DateTime start; + DateTime end; + + switch(command) + { + case MmcCommands.SendCid when _cachedCid != null: + { + start = DateTime.Now; + buffer = new byte[_cachedCid.Length]; + Array.Copy(_cachedCid, buffer, buffer.Length); + response = new uint[4]; + sense = false; + end = DateTime.Now; + duration = (end - start).TotalMilliseconds; + + return 0; + } + case MmcCommands.SendCsd when _cachedCid != null: + { + start = DateTime.Now; + buffer = new byte[_cachedCsd.Length]; + Array.Copy(_cachedCsd, buffer, buffer.Length); + response = new uint[4]; + sense = false; + end = DateTime.Now; + duration = (end - start).TotalMilliseconds; + + return 0; + } + case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null: + { + start = DateTime.Now; + buffer = new byte[_cachedScr.Length]; + Array.Copy(_cachedScr, buffer, buffer.Length); + response = new uint[4]; + sense = false; + end = DateTime.Now; + duration = (end - start).TotalMilliseconds; + + return 0; + } + case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null: + case MmcCommands.SendOpCond when _cachedOcr != null: + { + start = DateTime.Now; + buffer = new byte[_cachedOcr.Length]; + Array.Copy(_cachedOcr, buffer, buffer.Length); + response = new uint[4]; + sense = false; + end = DateTime.Now; + duration = (end - start).TotalMilliseconds; + + return 0; + } + } + response = null; duration = 0; sense = false; @@ -425,9 +468,9 @@ static class Command Marshal.Copy(buffer, 0, bufPtr, buffer.Length); - DateTime start = DateTime.UtcNow; - int error = Extern.ioctlMmc(fd, LinuxIoctl.MmcIocCmd, ref ioCmd); - DateTime end = DateTime.UtcNow; + start = DateTime.UtcNow; + int error = Extern.ioctlMmc(_fileDescriptor, LinuxIoctl.MmcIocCmd, ref ioCmd); + end = DateTime.UtcNow; sense |= error < 0; @@ -444,9 +487,14 @@ static class Command return error; } - internal static int SendMultipleMmcCommands(int fd, Device.MmcSingleCommand[] commands, out double duration, - out bool sense, uint timeout = 0) + /// + public override int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense, + uint timeout = 15) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + duration = 0; sense = false; int off; @@ -506,7 +554,7 @@ static class Command // Send command DateTime start = DateTime.UtcNow; - int error = Extern.ioctlMmcMulti(fd, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr); + int error = Extern.ioctlMmcMulti(_fileDescriptor, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr); DateTime end = DateTime.UtcNow; sense |= error < 0; @@ -549,35 +597,61 @@ static class Command return error; } - internal static int ReOpen(string devicePath, int fd, out object newFd) - { - newFd = -1; + /// + public override bool ReOpen() - int ret = Extern.close(fd); + { + int ret = Extern.close(_fileDescriptor); if(ret < 0) - return Marshal.GetLastWin32Error(); + { + LastError = Marshal.GetLastWin32Error(); + Error = true; - newFd = Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew); + return true; + } - if((int)newFd >= 0) - return 0; + int newFd = Extern.open(_devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew); + + if(newFd >= 0) + { + Error = false; + _fileDescriptor = newFd; + + return false; + } int error = Marshal.GetLastWin32Error(); if(error != 13 && error != 30) - return Marshal.GetLastWin32Error(); + { + LastError = Marshal.GetLastWin32Error(); + Error = true; - newFd = Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking); + return true; + } - return (int)newFd < 0 ? Marshal.GetLastWin32Error() : 0; + newFd = Extern.open(_devicePath, FileFlags.Readonly | FileFlags.NonBlocking); + + if(newFd < 0) + { + LastError = Marshal.GetLastWin32Error(); + Error = true; + + return true; + } + + Error = false; + _fileDescriptor = newFd; + + return false; } /// Reads the contents of a symbolic link /// Path to the symbolic link /// Contents of the symbolic link - internal static string ReadLink(string path) + static string ReadLink(string path) { IntPtr buf = Marshal.AllocHGlobal(4096); int resultSize; @@ -608,13 +682,15 @@ static class Command return Encoding.ASCII.GetString(resultString); } - internal static int BufferedOsRead(int fd, out byte[] buffer, long offset, uint length, out double duration) + /// + public override bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration) + { buffer = new byte[length]; DateTime start = DateTime.Now; - long sense = Extern.lseek(fd, offset, SeekWhence.Begin); + long sense = Extern.lseek(_fileDescriptor, offset, SeekWhence.Begin); DateTime end = DateTime.Now; @@ -622,10 +698,14 @@ static class Command { duration = (end - start).TotalMilliseconds; - return Marshal.GetLastWin32Error(); + Error = true; + LastError = Marshal.GetLastWin32Error(); + + return true; } - sense = DetectOS.Is64Bit ? Extern.read64(fd, buffer, length) : Extern.read(fd, buffer, (int)length); + sense = DetectOS.Is64Bit ? Extern.read64(_fileDescriptor, buffer, length) + : Extern.read(_fileDescriptor, buffer, (int)length); end = DateTime.Now; duration = (end - start).TotalMilliseconds; @@ -637,6 +717,9 @@ static class Command else if(errno == 0) errno = -22; - return errno; + LastError = errno; + Error = errno == 0; + + return errno != 0; } } \ No newline at end of file diff --git a/Aaru.Devices/Linux/Device.cs b/Aaru.Devices/Linux/Device.cs index 4eb3d11ca..4e723ea10 100644 --- a/Aaru.Devices/Linux/Device.cs +++ b/Aaru.Devices/Linux/Device.cs @@ -46,31 +46,34 @@ using VendorString = Aaru.Decoders.MMC.VendorString; /// [SupportedOSPlatform("linux")] -public class Device : Devices.Device +partial class Device : Devices.Device { + /// Gets the file handle representing this device + /// The file handle + int _fileDescriptor; + Device() {} - public new static Device Create(string devicePath) + internal new static Device Create(string devicePath) { var dev = new Device { - PlatformId = DetectOS.GetRealPlatformID(), - Timeout = 15, - Error = false, - IsRemovable = false + PlatformId = DetectOS.GetRealPlatformID(), + Timeout = 15, + Error = false, + IsRemovable = false, + _fileDescriptor = Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew) }; - dev.FileHandle = Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew); - - if((int)dev.FileHandle < 0) + if(dev._fileDescriptor < 0) { dev.LastError = Marshal.GetLastWin32Error(); if(dev.LastError is 13 or 30) // EACCES or EROFS { - dev.FileHandle = Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking); + dev._fileDescriptor = Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking); - if((int)dev.FileHandle < 0) + if(dev._fileDescriptor < 0) { dev.Error = true; dev.LastError = Marshal.GetLastWin32Error(); @@ -92,23 +95,22 @@ public class Device : Devices.Device dev.Type = DeviceType.Unknown; dev.ScsiType = PeripheralDeviceTypes.UnknownDevice; - byte[] ataBuf; - byte[] inqBuf = null; - if(dev.Error) throw new DeviceException(dev.LastError); + string devPath; + if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sg", StringComparison.Ordinal)) - if(!dev.ScsiInquiry(out inqBuf, out _)) + if(!dev.ScsiInquiry(out byte[] _, out _)) dev.Type = DeviceType.SCSI; // MultiMediaCard and SecureDigital go here else if(devicePath.StartsWith("/dev/mmcblk", StringComparison.Ordinal)) { - string devPath = devicePath.Substring(5); + devPath = devicePath[5..]; if(File.Exists("/sys/block/" + devPath + "/device/csd")) { @@ -179,21 +181,23 @@ public class Device : Devices.Device #endregion SecureDigital / MultiMediaCard #region USB + string resolvedLink; + if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) { - string devPath = devicePath.Substring(5); + devPath = devicePath[5..]; if(Directory.Exists("/sys/block/" + devPath)) { - string resolvedLink = Command.ReadLink("/sys/block/" + devPath); + resolvedLink = ReadLink("/sys/block/" + devPath); if(!string.IsNullOrEmpty(resolvedLink)) { - resolvedLink = "/sys" + resolvedLink.Substring(2); + resolvedLink = "/sys" + resolvedLink[2..]; - while(resolvedLink.Contains("usb")) + while(resolvedLink?.Contains("usb") == true) { resolvedLink = Path.GetDirectoryName(resolvedLink); @@ -257,128 +261,121 @@ public class Device : Devices.Device #endregion USB #region FireWire - { - if(true) - { - if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || - devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || - devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) - { - string devPath = devicePath.Substring(5); - - if(Directory.Exists("/sys/block/" + devPath)) - { - string resolvedLink = Command.ReadLink("/sys/block/" + devPath); - resolvedLink = "/sys" + resolvedLink.Substring(2); - - if(!string.IsNullOrEmpty(resolvedLink)) - while(resolvedLink.Contains("firewire")) - { - resolvedLink = Path.GetDirectoryName(resolvedLink); - - if(!File.Exists(resolvedLink + "/model") || - !File.Exists(resolvedLink + "/vendor") || - !File.Exists(resolvedLink + "/guid")) - continue; - - var fwSr = new StreamReader(resolvedLink + "/model"); - string fwTemp = fwSr.ReadToEnd(); - - uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, - out dev._firewireModel); - - fwSr.Close(); - - fwSr = new StreamReader(resolvedLink + "/vendor"); - fwTemp = fwSr.ReadToEnd(); - - uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, - out dev._firewireVendor); - - fwSr.Close(); - - fwSr = new StreamReader(resolvedLink + "/guid"); - fwTemp = fwSr.ReadToEnd(); - - ulong.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, - out dev._firewireGuid); - - fwSr.Close(); - - if(File.Exists(resolvedLink + "/model_name")) - { - fwSr = new StreamReader(resolvedLink + "/model_name"); - dev.FireWireModelName = fwSr.ReadToEnd().Trim(); - fwSr.Close(); - } - - if(File.Exists(resolvedLink + "/vendor_name")) - { - fwSr = new StreamReader(resolvedLink + "/vendor_name"); - dev.FireWireVendorName = fwSr.ReadToEnd().Trim(); - fwSr.Close(); - } - - dev.IsFireWire = true; - - break; - } - } - } - } - - // TODO: Implement for other operating systems - else - dev.IsFireWire = false; - } - #endregion FireWire - - #region PCMCIA if(devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) || devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) || devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) { - string devPath = devicePath.Substring(5); + devPath = devicePath[5..]; if(Directory.Exists("/sys/block/" + devPath)) { - string resolvedLink = Command.ReadLink("/sys/block/" + devPath); - resolvedLink = "/sys" + resolvedLink.Substring(2); + resolvedLink = ReadLink("/sys/block/" + devPath); + resolvedLink = "/sys" + resolvedLink[2..]; if(!string.IsNullOrEmpty(resolvedLink)) - while(resolvedLink.Contains("/sys/devices")) + while(resolvedLink?.Contains("firewire") == true) { resolvedLink = Path.GetDirectoryName(resolvedLink); - if(!Directory.Exists(resolvedLink + "/pcmcia_socket")) + if(!File.Exists(resolvedLink + "/model") || + !File.Exists(resolvedLink + "/vendor") || + !File.Exists(resolvedLink + "/guid")) continue; - string[] subdirs = Directory.GetDirectories(resolvedLink + "/pcmcia_socket", "pcmcia_socket*", - SearchOption.TopDirectoryOnly); + var fwSr = new StreamReader(resolvedLink + "/model"); + string fwTemp = fwSr.ReadToEnd(); - if(subdirs.Length <= 0) - continue; + uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, + out dev._firewireModel); - string possibleDir = Path.Combine(resolvedLink, "pcmcia_socket", subdirs[0]); + fwSr.Close(); - if(!File.Exists(possibleDir + "/card_type") || - !File.Exists(possibleDir + "/cis")) - continue; + fwSr = new StreamReader(resolvedLink + "/vendor"); + fwTemp = fwSr.ReadToEnd(); - var cisFs = new FileStream(possibleDir + "/cis", FileMode.Open, FileAccess.Read); + uint.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, + out dev._firewireVendor); - var cisBuf = new byte[65536]; - int cisCount = cisFs.Read(cisBuf, 0, 65536); - dev.Cis = new byte[cisCount]; - Array.Copy(cisBuf, 0, dev.Cis, 0, cisCount); - cisFs.Close(); + fwSr.Close(); - dev.IsPcmcia = true; + fwSr = new StreamReader(resolvedLink + "/guid"); + fwTemp = fwSr.ReadToEnd(); + + ulong.TryParse(fwTemp, NumberStyles.HexNumber, CultureInfo.InvariantCulture, + out dev._firewireGuid); + + fwSr.Close(); + + if(File.Exists(resolvedLink + "/model_name")) + { + fwSr = new StreamReader(resolvedLink + "/model_name"); + dev.FireWireModelName = fwSr.ReadToEnd().Trim(); + fwSr.Close(); + } + + if(File.Exists(resolvedLink + "/vendor_name")) + { + fwSr = new StreamReader(resolvedLink + "/vendor_name"); + dev.FireWireVendorName = fwSr.ReadToEnd().Trim(); + fwSr.Close(); + } + + dev.IsFireWire = true; break; } } } + #endregion FireWire + + #region PCMCIA + if(!devicePath.StartsWith("/dev/sd", StringComparison.Ordinal) && + !devicePath.StartsWith("/dev/sr", StringComparison.Ordinal) && + !devicePath.StartsWith("/dev/st", StringComparison.Ordinal)) + return dev; + + devPath = devicePath[5..]; + + if(!Directory.Exists("/sys/block/" + devPath)) + return dev; + + resolvedLink = ReadLink("/sys/block/" + devPath); + resolvedLink = "/sys" + resolvedLink[2..]; + + if(string.IsNullOrEmpty(resolvedLink)) + return dev; + + while(resolvedLink.Contains("/sys/devices")) + { + resolvedLink = Path.GetDirectoryName(resolvedLink); + + if(!Directory.Exists(resolvedLink + "/pcmcia_socket")) + continue; + + string[] subdirs = Directory.GetDirectories(resolvedLink + "/pcmcia_socket", "pcmcia_socket*", + SearchOption.TopDirectoryOnly); + + if(subdirs.Length <= 0) + continue; + + string possibleDir = Path.Combine(resolvedLink, "pcmcia_socket", subdirs[0]); + + if(!File.Exists(possibleDir + "/card_type") || + !File.Exists(possibleDir + "/cis")) + continue; + + var cisFs = new FileStream(possibleDir + "/cis", FileMode.Open, FileAccess.Read); + + var cisBuf = new byte[65536]; + int cisCount = cisFs.Read(cisBuf, 0, 65536); + dev.Cis = new byte[cisCount]; + Array.Copy(cisBuf, 0, dev.Cis, 0, cisCount); + cisFs.Close(); + + dev.IsPcmcia = true; + + break; + } #endregion PCMCIA return dev; @@ -399,11 +396,11 @@ public class Device : Devices.Device /// public override void Close() { - if(FileHandle == null) + if(_fileDescriptor == 0) return; - Extern.close((int)FileHandle); + Extern.close(_fileDescriptor); - FileHandle = null; + _fileDescriptor = 0; } } \ No newline at end of file diff --git a/Aaru.Devices/Remote/Command.cs b/Aaru.Devices/Remote/Command.cs new file mode 100644 index 000000000..8f0b52035 --- /dev/null +++ b/Aaru.Devices/Remote/Command.cs @@ -0,0 +1,199 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Commands.cs +// Author(s) : Natalia Portillo +// +// 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 . +// +// ---------------------------------------------------------------------------- +// 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 +{ + /// + 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); + } + + /// + 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); + } + + /// + 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); + } + + /// + 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); + } + + /// + 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); + } + + /// + 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; + } + + /// + public override bool ReOpen() => _remote.ReOpen(); + + /// + public override bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration) => + _remote.BufferedOsRead(out buffer, offset, length, out duration); +} \ No newline at end of file diff --git a/Aaru.Devices/Remote/Device.cs b/Aaru.Devices/Remote/Device.cs index 74482aeb8..c73117dd6 100644 --- a/Aaru.Devices/Remote/Device.cs +++ b/Aaru.Devices/Remote/Device.cs @@ -39,14 +39,43 @@ using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.SecureDigital; /// -public sealed class Device : Devices.Device +public sealed partial class Device : Devices.Device { + Remote _remote; + + /// Returns if remote is running under administrative (aka root) privileges + public bool IsAdmin + { + get + { + _isRemoteAdmin ??= _remote.IsRoot; + + return _isRemoteAdmin == true; + } + } + + /// Current device is remote + public bool IsRemote => _remote != null; + /// Remote application + public string RemoteApplication => _remote?.ServerApplication; + /// Remote application server + public string RemoteVersion => _remote?.ServerVersion; + /// Remote operating system name + public string RemoteOperatingSystem => _remote?.ServerOperatingSystem; + /// Remote operating system version + public string RemoteOperatingSystemVersion => _remote?.ServerOperatingSystemVersion; + /// Remote architecture + public string RemoteArchitecture => _remote?.ServerArchitecture; + /// Remote protocol version + public int RemoteProtocolVersion => _remote?.ServerProtocolVersion ?? 0; + bool? _isRemoteAdmin; + Device() {} /// Opens the device for sending direct commands /// AaruRemote URI /// Device - public static Device Create(Uri aaruUri) + internal static Device Create(Uri aaruUri) { var dev = new Device { @@ -83,9 +112,6 @@ public sealed class Device : Devices.Device dev.Type = DeviceType.Unknown; dev.ScsiType = PeripheralDeviceTypes.UnknownDevice; - byte[] ataBuf; - byte[] inqBuf = null; - if(dev.Error) throw new DeviceException(dev.LastError); @@ -93,11 +119,6 @@ public sealed class Device : Devices.Device switch(dev.Type) { - case DeviceType.ATAPI: - case DeviceType.SCSI: - bool scsiSense = dev.ScsiInquiry(out inqBuf, out _); - - break; case DeviceType.SecureDigital: case DeviceType.MMC: if(!dev._remote.GetSdhciRegisters(out dev._cachedCsd, out dev._cachedCid, out dev._cachedOcr, diff --git a/Aaru.Devices/Windows/Command.cs b/Aaru.Devices/Windows/Command.cs index 5a6711b3f..1f1896e4c 100644 --- a/Aaru.Devices/Windows/Command.cs +++ b/Aaru.Devices/Windows/Command.cs @@ -40,24 +40,16 @@ using Aaru.Decoders.ATA; using Microsoft.Win32.SafeHandles; [SuppressMessage("ReSharper", "UnusedParameter.Global")] -static class Command +partial class Device { - /// Sends a SCSI command - /// 0 if no error occurred, otherwise, errno - /// File handle - /// SCSI CDB - /// Buffer for SCSI command response - /// Buffer with the SCSI sense - /// Timeout in seconds - /// SCSI command transfer direction - /// Time it took to execute the command in milliseconds - /// - /// True if SCSI error returned non-OK status and contains SCSI - /// sense - /// - internal static int SendScsiCommand(SafeFileHandle fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, - uint timeout, ScsiIoctlDirection direction, out double duration, out bool sense) + /// + public override int SendScsiCommand(byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout, + ScsiDirection direction, out double duration, out bool sense) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + senseBuffer = null; duration = 0; sense = false; @@ -65,6 +57,24 @@ static class Command if(buffer == null) return -1; + ScsiIoctlDirection dir; + + switch(direction) + { + case ScsiDirection.In: + dir = ScsiIoctlDirection.In; + + break; + case ScsiDirection.Out: + dir = ScsiIoctlDirection.Out; + + break; + default: + dir = ScsiIoctlDirection.Unspecified; + + break; + } + var sptdSb = new ScsiPassThroughDirectAndSenseBuffer { SenseBuf = new byte[32], @@ -73,7 +83,7 @@ static class Command Cdb = new byte[16], CdbLength = (byte)cdb.Length, SenseInfoLength = 32, - DataIn = direction, + DataIn = dir, DataTransferLength = (uint)buffer.Length, TimeOutValue = timeout, DataBuffer = Marshal.AllocHGlobal(buffer.Length) @@ -91,7 +101,7 @@ static class Command DateTime start = DateTime.Now; - bool hasError = !Extern.DeviceIoControlScsi(fd, WindowsIoctl.IoctlScsiPassThroughDirect, ref sptdSb, + bool hasError = !Extern.DeviceIoControlScsi(_fileHandle, WindowsIoctl.IoctlScsiPassThroughDirect, ref sptdSb, (uint)Marshal.SizeOf(sptdSb), ref sptdSb, (uint)Marshal.SizeOf(sptdSb), ref k, IntPtr.Zero); @@ -114,20 +124,15 @@ static class Command return error; } - /// Sends an ATA command in CHS mode - /// 0 if no error occurred, otherwise, errno - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA error returned non-OK status - /// Registers to send to drive - /// Registers returned by drive - /// ATA protocol to use - internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersChs registers, - out AtaErrorRegistersChs errorRegisters, AtaProtocol protocol, ref byte[] buffer, - uint timeout, out double duration, out bool sense) + /// + public override int SendAtaCommand(AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters, + AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, + uint timeout, bool transferBlocks, out double duration, out bool sense) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + duration = 0; sense = false; errorRegisters = new AtaErrorRegistersChs(); @@ -191,7 +196,7 @@ static class Command DateTime start = DateTime.Now; - sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd, + sense = !Extern.DeviceIoControlAta(_fileHandle, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd, (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k, IntPtr.Zero); @@ -219,20 +224,15 @@ static class Command return error; } - /// Sends an ATA command in 28-bit LBA mode - /// 0 if no error occurred, otherwise, errno - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA error returned non-OK status - /// Registers to send to drive - /// Registers returned by drive - /// ATA protocol to use - internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersLba28 registers, - out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol, - ref byte[] buffer, uint timeout, out double duration, out bool sense) + /// + public override int SendAtaCommand(AtaRegistersLba28 registers, out AtaErrorRegistersLba28 errorRegisters, + AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, + uint timeout, bool transferBlocks, out double duration, out bool sense) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba28(); @@ -296,7 +296,7 @@ static class Command DateTime start = DateTime.Now; - sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd, + sense = !Extern.DeviceIoControlAta(_fileHandle, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd, (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k, IntPtr.Zero); @@ -324,20 +324,15 @@ static class Command return error; } - /// Sends an ATA command in 48-bit LBA mode - /// 0 if no error occurred, otherwise, errno - /// File handle - /// Buffer for SCSI command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if ATA error returned non-OK status - /// Registers to send to drive - /// Registers returned by drive - /// ATA protocol to use - internal static int SendAtaCommand(SafeFileHandle fd, AtaRegistersLba48 registers, - out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol, - ref byte[] buffer, uint timeout, out double duration, out bool sense) + /// + public override int SendAtaCommand(AtaRegistersLba48 registers, out AtaErrorRegistersLba48 errorRegisters, + AtaProtocol protocol, AtaTransferRegister transferRegister, ref byte[] buffer, + uint timeout, bool transferBlocks, out double duration, out bool sense) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + duration = 0; sense = false; errorRegisters = new AtaErrorRegistersLba48(); @@ -410,7 +405,7 @@ static class Command DateTime start = DateTime.Now; - sense = !Extern.DeviceIoControlAta(fd, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd, + sense = !Extern.DeviceIoControlAta(_fileHandle, WindowsIoctl.IoctlAtaPassThroughDirect, ref aptd, (uint)Marshal.SizeOf(aptd), ref aptd, (uint)Marshal.SizeOf(aptd), ref k, IntPtr.Zero); @@ -458,25 +453,67 @@ static class Command queryData1.protocolGuid.Equals(Consts.GuidSffProtocolMmc); } - /// Sends a MMC/SD command - /// The result of the command. - /// File handle - /// MMC/SD opcode - /// Buffer for MMC/SD command response - /// Timeout in seconds - /// Time it took to execute the command in milliseconds - /// True if MMC/SD returned non-OK status - /// True if data is sent from host to card - /// True if command should be preceded with CMD55 - /// Flags indicating kind and place of response - /// How many blocks to transfer - /// Command argument - /// Response registers - /// Size of block in bytes - 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) + /// + public override int SendMmcCommand(MmcCommands command, bool write, bool isApplication, MmcFlags flags, + uint argument, uint blockSize, uint blocks, ref byte[] buffer, + out uint[] response, out double duration, out bool sense, uint timeout = 15) { + DateTime start; + DateTime end; + + switch(command) + { + case MmcCommands.SendCid when _cachedCid != null: + { + start = DateTime.Now; + buffer = new byte[_cachedCid.Length]; + Array.Copy(_cachedCid, buffer, buffer.Length); + response = new uint[4]; + sense = false; + end = DateTime.Now; + duration = (end - start).TotalMilliseconds; + + return 0; + } + case MmcCommands.SendCsd when _cachedCid != null: + { + start = DateTime.Now; + buffer = new byte[_cachedCsd.Length]; + Array.Copy(_cachedCsd, buffer, buffer.Length); + response = new uint[4]; + sense = false; + end = DateTime.Now; + duration = (end - start).TotalMilliseconds; + + return 0; + } + case (MmcCommands)SecureDigitalCommands.SendScr when _cachedScr != null: + { + start = DateTime.Now; + buffer = new byte[_cachedScr.Length]; + Array.Copy(_cachedScr, buffer, buffer.Length); + response = new uint[4]; + sense = false; + end = DateTime.Now; + duration = (end - start).TotalMilliseconds; + + return 0; + } + case (MmcCommands)SecureDigitalCommands.SendOperatingCondition when _cachedOcr != null: + case MmcCommands.SendOpCond when _cachedOcr != null: + { + start = DateTime.Now; + buffer = new byte[_cachedOcr.Length]; + Array.Copy(_cachedOcr, buffer, buffer.Length); + response = new uint[4]; + sense = false; + end = DateTime.Now; + duration = (end - start).TotalMilliseconds; + + return 0; + } + } + var commandData = new SffdiskDeviceCommandData(); var commandDescriptor = new SdCmdDescriptor(); commandData.size = (ushort)Marshal.SizeOf(commandData); @@ -531,13 +568,13 @@ static class Command Marshal.Copy(hBuf, commandB, 0, commandB.Length); Marshal.FreeHGlobal(hBuf); - var error = 0; - DateTime start = DateTime.Now; + var error = 0; + start = DateTime.Now; - sense = !Extern.DeviceIoControl(fd, WindowsIoctl.IoctlSffdiskDeviceCommand, commandB, (uint)commandB.Length, - commandB, (uint)commandB.Length, out _, IntPtr.Zero); + sense = !Extern.DeviceIoControl(_fileHandle, WindowsIoctl.IoctlSffdiskDeviceCommand, commandB, + (uint)commandB.Length, commandB, (uint)commandB.Length, out _, IntPtr.Zero); - DateTime end = DateTime.Now; + end = DateTime.Now; if(sense) error = Marshal.GetLastWin32Error(); @@ -551,9 +588,14 @@ static class Command return error; } - internal static int SendMultipleMmcCommands(SafeFileHandle fd, Device.MmcSingleCommand[] commands, - out double duration, out bool sense, uint timeout = 0) + /// + public override int SendMultipleMmcCommands(MmcSingleCommand[] commands, out double duration, out bool sense, + uint timeout = 15) { + // We need a timeout + if(timeout == 0) + timeout = Timeout > 0 ? Timeout : 15; + var error = 0; duration = 0; sense = false; @@ -562,13 +604,13 @@ static class Command commands[0].command == MmcCommands.SetBlocklen && commands[1].command == MmcCommands.ReadMultipleBlock && commands[2].command == MmcCommands.StopTransmission) - return SendMmcCommand(fd, commands[1].command, commands[1].write, commands[1].isApplication, - commands[1].flags, commands[1].argument, commands[1].blockSize, commands[1].blocks, + return SendMmcCommand(commands[1].command, commands[1].write, commands[1].isApplication, commands[1].flags, + commands[1].argument, commands[1].blockSize, commands[1].blocks, ref commands[1].buffer, out commands[1].response, out duration, out sense, timeout); - foreach(Device.MmcSingleCommand command in commands) + foreach(MmcSingleCommand command in commands) { - int singleError = SendMmcCommand(fd, command.command, command.write, command.isApplication, command.flags, + int singleError = SendMmcCommand(command.command, command.write, command.isApplication, command.flags, command.argument, command.blockSize, command.blocks, ref command.buffer, out command.response, out double cmdDuration, out bool cmdSense, timeout); @@ -585,25 +627,36 @@ static class Command return error; } - internal static int ReOpen(string devicePath, SafeFileHandle fd, out object newFd) + /// + public override bool ReOpen() { - Extern.CloseHandle(fd); + Extern.CloseHandle(_fileHandle); - newFd = Extern.CreateFile(devicePath, FileAccess.GenericRead | FileAccess.GenericWrite, - FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting, - FileAttributes.Normal, IntPtr.Zero); + SafeFileHandle newFd = Extern.CreateFile(_devicePath, FileAccess.GenericRead | FileAccess.GenericWrite, + FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting, + FileAttributes.Normal, IntPtr.Zero); - return ((SafeFileHandle)newFd).IsInvalid ? Marshal.GetLastWin32Error() : 0; + if(newFd.IsInvalid) + { + LastError = Marshal.GetLastWin32Error(); + Error = true; + + return true; + } + + _fileHandle = newFd; + + return false; } - internal static int BufferedOsRead(SafeFileHandle fd, out byte[] buffer, long offset, uint length, - out double duration) + /// + public override bool BufferedOsRead(out byte[] buffer, long offset, uint length, out double duration) { buffer = new byte[length]; DateTime start = DateTime.Now; - bool sense = !Extern.SetFilePointerEx(fd, offset, out _, MoveMethod.Begin); + bool sense = !Extern.SetFilePointerEx(_fileHandle, offset, out _, MoveMethod.Begin); DateTime end = DateTime.Now; @@ -611,14 +664,27 @@ static class Command { duration = (end - start).TotalMilliseconds; - return Marshal.GetLastWin32Error(); + LastError = Marshal.GetLastWin32Error(); + Error = true; + + return true; } - sense = !Extern.ReadFile(fd, buffer, length, out _, IntPtr.Zero); + sense = !Extern.ReadFile(_fileHandle, buffer, length, out _, IntPtr.Zero); end = DateTime.Now; duration = (end - start).TotalMilliseconds; - return sense ? Marshal.GetLastWin32Error() : 0; + if(sense) + { + Error = true; + LastError = Marshal.GetLastWin32Error(); + + return true; + } + + Error = false; + + return false; } } \ No newline at end of file diff --git a/Aaru.Devices/Windows/Device.cs b/Aaru.Devices/Windows/Device.cs index b2edaeece..64b74dcad 100644 --- a/Aaru.Devices/Windows/Device.cs +++ b/Aaru.Devices/Windows/Device.cs @@ -43,25 +43,28 @@ using Microsoft.Win32.SafeHandles; /// [SupportedOSPlatform("windows")] -public class Device : Devices.Device +partial class Device : Devices.Device { + /// Gets the file handle representing this device + /// The file handle + SafeFileHandle _fileHandle; + Device() {} - public new static Device Create(string devicePath) + internal new static Device Create(string devicePath) { var dev = new Device { - PlatformId = DetectOS.GetRealPlatformID(), - Timeout = 15, - Error = false, - IsRemovable = false + PlatformId = DetectOS.GetRealPlatformID(), + Timeout = 15, + Error = false, + IsRemovable = false, + _fileHandle = Extern.CreateFile(devicePath, FileAccess.GenericRead | FileAccess.GenericWrite, + FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting, + FileAttributes.Normal, IntPtr.Zero) }; - dev.FileHandle = Extern.CreateFile(devicePath, FileAccess.GenericRead | FileAccess.GenericWrite, - FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.OpenExisting, - FileAttributes.Normal, IntPtr.Zero); - - if(((SafeFileHandle)dev.FileHandle).IsInvalid) + if(dev._fileHandle.IsInvalid) { dev.Error = true; dev.LastError = Marshal.GetLastWin32Error(); @@ -73,9 +76,6 @@ public class Device : Devices.Device dev.Type = DeviceType.Unknown; dev.ScsiType = PeripheralDeviceTypes.UnknownDevice; - byte[] ataBuf; - byte[] inqBuf = null; - if(dev.Error) throw new DeviceException(dev.LastError); @@ -91,9 +91,8 @@ public class Device : Devices.Device uint returned = 0; var error = 0; - bool hasError = !Extern.DeviceIoControlStorageQuery((SafeFileHandle)dev.FileHandle, - WindowsIoctl.IoctlStorageQueryProperty, ref query, - (uint)Marshal.SizeOf(query), descriptorPtr, 1000, + bool hasError = !Extern.DeviceIoControlStorageQuery(dev._fileHandle, WindowsIoctl.IoctlStorageQueryProperty, + ref query, (uint)Marshal.SizeOf(query), descriptorPtr, 1000, ref returned, IntPtr.Zero); if(hasError) @@ -170,7 +169,7 @@ public class Device : Devices.Device switch(dev.Type) { case DeviceType.ATA: - bool atapiSense = dev.AtapiIdentify(out ataBuf, out _); + bool atapiSense = dev.AtapiIdentify(out byte[] _, out _); if(!atapiSense) dev.Type = DeviceType.ATAPI; @@ -183,13 +182,13 @@ public class Device : Devices.Device Marshal.FreeHGlobal(descriptorPtr); - if(Command.IsSdhci((SafeFileHandle)dev.FileHandle)) + if(IsSdhci(dev._fileHandle)) { var sdBuffer = new byte[16]; - dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle, MmcCommands.SendCsd, false, false, - MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, - 16, 1, ref sdBuffer, out _, out _, out bool sense); + dev.LastError = dev.SendMmcCommand(MmcCommands.SendCsd, false, false, + MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16, + 1, ref sdBuffer, out _, out _, out bool sense); if(!sense) { @@ -199,9 +198,9 @@ public class Device : Devices.Device sdBuffer = new byte[16]; - dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle, MmcCommands.SendCid, false, false, - MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, - 16, 1, ref sdBuffer, out _, out _, out sense); + dev.LastError = dev.SendMmcCommand(MmcCommands.SendCid, false, false, + MmcFlags.ResponseSpiR2 | MmcFlags.ResponseR2 | MmcFlags.CommandAc, 0, 16, + 1, ref sdBuffer, out _, out _, out sense); if(!sense) { @@ -211,10 +210,9 @@ public class Device : Devices.Device sdBuffer = new byte[8]; - dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle, - (MmcCommands)SecureDigitalCommands.SendScr, false, true, - MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, - 0, 8, 1, ref sdBuffer, out _, out _, out sense); + dev.LastError = dev.SendMmcCommand((MmcCommands)SecureDigitalCommands.SendScr, false, true, + MmcFlags.ResponseSpiR1 | MmcFlags.ResponseR1 | MmcFlags.CommandAdtc, 0, + 8, 1, ref sdBuffer, out _, out _, out sense); if(!sense) { @@ -224,12 +222,10 @@ public class Device : Devices.Device sdBuffer = new byte[4]; - dev.LastError = Command.SendMmcCommand((SafeFileHandle)dev.FileHandle, - dev._cachedScr != null - ? (MmcCommands)SecureDigitalCommands.SendOperatingCondition - : MmcCommands.SendOpCond, false, true, - MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, - 0, 4, 1, ref sdBuffer, out _, out _, out sense); + dev.LastError = + dev.SendMmcCommand(dev._cachedScr != null ? (MmcCommands)SecureDigitalCommands.SendOperatingCondition : MmcCommands.SendOpCond, + false, true, MmcFlags.ResponseSpiR3 | MmcFlags.ResponseR3 | MmcFlags.CommandBcr, 0, + 4, 1, ref sdBuffer, out _, out _, out sense); if(!sense) { @@ -318,11 +314,11 @@ public class Device : Devices.Device /// public override void Close() { - if(FileHandle == null) + if(_fileHandle == null) return; - (FileHandle as SafeFileHandle)?.Close(); + _fileHandle?.Close(); - FileHandle = null; + _fileHandle = null; } } \ No newline at end of file diff --git a/Aaru.Gui/ViewModels/Windows/MainWindowViewModel.cs b/Aaru.Gui/ViewModels/Windows/MainWindowViewModel.cs index f441e7f12..3bfb0b902 100644 --- a/Aaru.Gui/ViewModels/Windows/MainWindowViewModel.cs +++ b/Aaru.Gui/ViewModels/Windows/MainWindowViewModel.cs @@ -250,10 +250,11 @@ public sealed class MainWindowViewModel : ViewModelBase { var dev = Device.Create(deviceModel.Path); - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, - dev.RemoteOperatingSystem, dev.RemoteOperatingSystemVersion, - dev.RemoteArchitecture); + if(dev is Devices.Remote.Device remoteDev) + Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, + remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); if(dev.Error) { @@ -789,9 +790,10 @@ public sealed class MainWindowViewModel : ViewModelBase { var dev = Device.Create(device.Path); - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, - dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + if(dev is Devices.Remote.Device remoteDev) + Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); switch(dev.Type) { diff --git a/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs b/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs index 89602b321..09343e81f 100644 --- a/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs +++ b/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs @@ -728,9 +728,10 @@ public sealed class MediaDumpViewModel : ViewModelBase { _dev = Device.Create(_devicePath); - if(_dev.IsRemote) - Statistics.AddRemote(_dev.RemoteApplication, _dev.RemoteVersion, _dev.RemoteOperatingSystem, - _dev.RemoteOperatingSystemVersion, _dev.RemoteArchitecture); + if(_dev is Devices.Remote.Device remoteDev) + Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); if(_dev.Error) { diff --git a/Aaru.Gui/ViewModels/Windows/MediaScanViewModel.cs b/Aaru.Gui/ViewModels/Windows/MediaScanViewModel.cs index 71aa1e434..4847fcdea 100644 --- a/Aaru.Gui/ViewModels/Windows/MediaScanViewModel.cs +++ b/Aaru.Gui/ViewModels/Windows/MediaScanViewModel.cs @@ -330,9 +330,9 @@ public sealed class MediaScanViewModel : ViewModelBase var dev = Device.Create(_devicePath); - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, - dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + if(dev is Devices.Remote.Device remoteDev) + Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, remoteDev.RemoteOperatingSystem, + remoteDev.RemoteOperatingSystemVersion, remoteDev.RemoteArchitecture); if(dev.Error) { diff --git a/Aaru.Tests.Devices/Device.cs b/Aaru.Tests.Devices/Device.cs index e7e0dfd00..27a8518f2 100644 --- a/Aaru.Tests.Devices/Device.cs +++ b/Aaru.Tests.Devices/Device.cs @@ -44,7 +44,6 @@ static partial class MainClass while(true) { AaruConsole.WriteLine("dev.PlatformID = {0}", dev.PlatformId); - AaruConsole.WriteLine("dev.FileHandle = {0}", dev.FileHandle); AaruConsole.WriteLine("dev.Timeout = {0}", dev.Timeout); AaruConsole.WriteLine("dev.Error = {0}", dev.Error); AaruConsole.WriteLine("dev.LastError = {0}", dev.LastError); diff --git a/Aaru/Commands/Device/DeviceReport.cs b/Aaru/Commands/Device/DeviceReport.cs index f5c01bbec..894608b17 100644 --- a/Aaru/Commands/Device/DeviceReport.cs +++ b/Aaru/Commands/Device/DeviceReport.cs @@ -130,9 +130,10 @@ sealed class DeviceReportCommand : Command { dev = Device.Create(devicePath); - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, - dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + if(dev is Devices.Remote.Device remoteDev) + Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); if(dev.Error) { @@ -150,7 +151,7 @@ sealed class DeviceReportCommand : Command Statistics.AddDevice(dev); - bool isAdmin = dev.IsRemote ? dev.IsRemoteAdmin : DetectOS.IsAdmin; + bool isAdmin = dev is Devices.Remote.Device remoteDev2 ? remoteDev2.IsAdmin : DetectOS.IsAdmin; if(!isAdmin) { diff --git a/Aaru/Commands/Device/Info.cs b/Aaru/Commands/Device/Info.cs index 058eafd7e..415784a66 100644 --- a/Aaru/Commands/Device/Info.cs +++ b/Aaru/Commands/Device/Info.cs @@ -134,9 +134,10 @@ sealed class DeviceInfoCommand : Command { dev = Device.Create(devicePath); - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, - dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + if(dev is Devices.Remote.Device remoteDev) + Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); if(dev.Error) { diff --git a/Aaru/Commands/Media/Dump.cs b/Aaru/Commands/Media/Dump.cs index 739f06a27..69bce71ba 100644 --- a/Aaru/Commands/Media/Dump.cs +++ b/Aaru/Commands/Media/Dump.cs @@ -546,9 +546,10 @@ sealed class DumpMediaCommand : Command dev = Device.Create(devicePath); }); - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, - dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + if(dev is Devices.Remote.Device remoteDev) + Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); if(dev.Error) { diff --git a/Aaru/Commands/Media/Info.cs b/Aaru/Commands/Media/Info.cs index d158ab608..708e24786 100644 --- a/Aaru/Commands/Media/Info.cs +++ b/Aaru/Commands/Media/Info.cs @@ -139,9 +139,10 @@ sealed class MediaInfoCommand : Command dev = Device.Create(devicePath); }); - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, - dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + if(dev is Devices.Remote.Device remoteDev) + Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); if(dev.Error) { diff --git a/Aaru/Commands/Media/Scan.cs b/Aaru/Commands/Media/Scan.cs index 5e08d5a70..0c8b5bebc 100644 --- a/Aaru/Commands/Media/Scan.cs +++ b/Aaru/Commands/Media/Scan.cs @@ -140,9 +140,10 @@ sealed class MediaScanCommand : Command dev = Device.Create(devicePath); }); - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, - dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + if(dev is Devices.Remote.Device remoteDev) + Statistics.AddRemote(remoteDev.RemoteApplication, remoteDev.RemoteVersion, + remoteDev.RemoteOperatingSystem, remoteDev.RemoteOperatingSystemVersion, + remoteDev.RemoteArchitecture); if(dev.Error) {