// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : Device.cs // Author(s) : Natalia Portillo // // Component : Remote device access. // // --[ Description ] ---------------------------------------------------------- // // Prepares a remote device for direct access. // // --[ 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-2024 Natalia Portillo // ****************************************************************************/ using System; using System.Net.Sockets; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interop; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Decoders.SecureDigital; namespace Aaru.Devices.Remote; /// public sealed partial class Device : Devices.Device { bool? _isRemoteAdmin; Remote _remote; Device() {} /// Returns if remote is running under administrative (aka root) privileges public bool IsAdmin { get { _isRemoteAdmin ??= _remote.IsRoot; return _isRemoteAdmin == true; } } /// Current device is remote // ReSharper disable once UnusedMember.Global 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; /// Opens the device for sending direct commands /// AaruRemote URI /// Sets the error if a device cannot be opened /// Device internal static Device Create(Uri aaruUri, out ErrorNumber errno) { errno = ErrorNumber.NoError; var dev = new Device { PlatformId = DetectOS.GetRealPlatformID(), Timeout = 15, Error = false, IsRemovable = false }; if(aaruUri.Scheme is not ("dic" or "aaru")) return null; string devicePath = aaruUri.AbsolutePath; if(devicePath.StartsWith('/')) devicePath = devicePath[1..]; if(devicePath.StartsWith("dev", StringComparison.Ordinal)) devicePath = $"/{devicePath}"; dev.DevicePath = devicePath; try { dev._remote = new Remote(aaruUri); } catch(Exception ex) { if(ex is SocketException sockEx) errno = (ErrorNumber)(-1 * sockEx.ErrorCode); else errno = ErrorNumber.NoSuchDeviceOrAddress; return null; } dev.Error = !dev._remote.Open(devicePath, out int remoteErrno); dev.LastError = remoteErrno; // TODO: Convert error codes if(dev.Error) { errno = (ErrorNumber)remoteErrno; return null; } if(dev._remote.ServerOperatingSystem == "Linux") _readMultipleBlockCannotSetBlockCount = true; dev.Type = DeviceType.Unknown; dev.ScsiType = PeripheralDeviceTypes.UnknownDevice; if(dev.Error) { errno = (ErrorNumber)dev.LastError; return null; } dev.Type = dev._remote.GetDeviceType(); switch(dev.Type) { case DeviceType.SecureDigital: case DeviceType.MMC: if(!dev._remote.GetSdhciRegisters(out dev.CachedCsd, out dev.CachedCid, out dev.CachedOcr, out dev.CachedScr)) { dev.Type = DeviceType.SCSI; dev.ScsiType = PeripheralDeviceTypes.DirectAccess; } break; } #region SecureDigital / MultiMediaCard if(dev.CachedCid != null) { dev.ScsiType = PeripheralDeviceTypes.DirectAccess; dev.IsRemovable = false; if(dev.CachedScr != null) { dev.Type = DeviceType.SecureDigital; CID decoded = Decoders.SecureDigital.Decoders.DecodeCID(dev.CachedCid); dev.Manufacturer = VendorString.Prettify(decoded.Manufacturer); dev.Model = decoded.ProductName; dev.FirmwareRevision = $"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}"; dev.Serial = $"{decoded.ProductSerialNumber}"; } else { dev.Type = DeviceType.MMC; Decoders.MMC.CID decoded = Decoders.MMC.Decoders.DecodeCID(dev.CachedCid); dev.Manufacturer = Decoders.MMC.VendorString.Prettify(decoded.Manufacturer); dev.Model = decoded.ProductName; dev.FirmwareRevision = $"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}"; dev.Serial = $"{decoded.ProductSerialNumber}"; } return dev; } #endregion SecureDigital / MultiMediaCard #region USB if(dev._remote.GetUsbData(out byte[] remoteUsbDescriptors, out ushort remoteUsbVendor, out ushort remoteUsbProduct, out string remoteUsbManufacturer, out string remoteUsbProductString, out string remoteUsbSerial)) { dev.IsUsb = true; dev.UsbDescriptors = remoteUsbDescriptors; dev.UsbVendor = remoteUsbVendor; dev.UsbProduct = remoteUsbProduct; dev.UsbManufacturerString = remoteUsbManufacturer; dev.UsbProductString = remoteUsbProductString; dev.UsbSerialString = remoteUsbSerial; } #endregion USB #region FireWire if(dev._remote.GetFireWireData(out dev.FirewireVendor, out dev.FirewireModel, out dev.FirewireGuid, out string remoteFireWireVendorName, out string remoteFireWireModelName)) { dev.IsFireWire = true; dev.FireWireVendorName = remoteFireWireVendorName; dev.FireWireModelName = remoteFireWireModelName; } #endregion FireWire #region PCMCIA if(!dev._remote.GetPcmciaData(out byte[] cisBuf)) return dev; dev.IsPcmcia = true; dev.Cis = cisBuf; #endregion PCMCIA return dev; } /// public override void Close() { if(_remote == null) return; _remote.Close(); _remote.Disconnect(); } }