2022-03-26 18:31:04 +00:00
|
|
|
// /***************************************************************************
|
|
|
|
|
// Aaru Data Preservation Suite
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Filename : Device.cs
|
|
|
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
|
|
|
//
|
|
|
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
//
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2022-12-03 16:07:10 +00:00
|
|
|
// Copyright © 2011-2023 Natalia Portillo
|
2022-03-26 18:31:04 +00:00
|
|
|
// ****************************************************************************/
|
|
|
|
|
|
|
|
|
|
using System;
|
2022-04-18 15:45:21 +01:00
|
|
|
using System.Net.Sockets;
|
2022-03-26 18:31:04 +00:00
|
|
|
using Aaru.CommonTypes.Enums;
|
|
|
|
|
using Aaru.CommonTypes.Interop;
|
|
|
|
|
using Aaru.CommonTypes.Structs.Devices.SCSI;
|
|
|
|
|
using Aaru.Decoders.SecureDigital;
|
|
|
|
|
|
2022-11-15 15:58:43 +00:00
|
|
|
namespace Aaru.Devices.Remote;
|
|
|
|
|
|
2022-03-26 18:31:04 +00:00
|
|
|
/// <inheritdoc />
|
2022-03-26 19:35:13 +00:00
|
|
|
public sealed partial class Device : Devices.Device
|
2022-03-26 18:31:04 +00:00
|
|
|
{
|
2023-10-03 23:12:01 +01:00
|
|
|
bool? _isRemoteAdmin;
|
2022-03-26 19:35:13 +00:00
|
|
|
Remote _remote;
|
|
|
|
|
|
2023-10-03 23:12:01 +01:00
|
|
|
Device() {}
|
|
|
|
|
|
2022-03-26 19:35:13 +00:00
|
|
|
/// <summary>Returns if remote is running under administrative (aka root) privileges</summary>
|
|
|
|
|
public bool IsAdmin
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
_isRemoteAdmin ??= _remote.IsRoot;
|
|
|
|
|
|
|
|
|
|
return _isRemoteAdmin == true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>Current device is remote</summary>
|
2023-10-05 01:05:23 +01:00
|
|
|
// ReSharper disable once UnusedMember.Global
|
2022-03-26 19:35:13 +00:00
|
|
|
public bool IsRemote => _remote != null;
|
2023-10-03 23:12:01 +01:00
|
|
|
|
2022-03-26 19:35:13 +00:00
|
|
|
/// <summary>Remote application</summary>
|
|
|
|
|
public string RemoteApplication => _remote?.ServerApplication;
|
2023-10-03 23:12:01 +01:00
|
|
|
|
2022-03-26 19:35:13 +00:00
|
|
|
/// <summary>Remote application server</summary>
|
|
|
|
|
public string RemoteVersion => _remote?.ServerVersion;
|
2023-10-03 23:12:01 +01:00
|
|
|
|
2022-03-26 19:35:13 +00:00
|
|
|
/// <summary>Remote operating system name</summary>
|
|
|
|
|
public string RemoteOperatingSystem => _remote?.ServerOperatingSystem;
|
2023-10-03 23:12:01 +01:00
|
|
|
|
2022-03-26 19:35:13 +00:00
|
|
|
/// <summary>Remote operating system version</summary>
|
|
|
|
|
public string RemoteOperatingSystemVersion => _remote?.ServerOperatingSystemVersion;
|
2023-10-03 23:12:01 +01:00
|
|
|
|
2022-03-26 19:35:13 +00:00
|
|
|
/// <summary>Remote architecture</summary>
|
|
|
|
|
public string RemoteArchitecture => _remote?.ServerArchitecture;
|
2023-10-03 23:12:01 +01:00
|
|
|
|
2022-03-26 19:35:13 +00:00
|
|
|
/// <summary>Remote protocol version</summary>
|
|
|
|
|
public int RemoteProtocolVersion => _remote?.ServerProtocolVersion ?? 0;
|
2022-03-26 18:31:04 +00:00
|
|
|
|
|
|
|
|
/// <summary>Opens the device for sending direct commands</summary>
|
|
|
|
|
/// <param name="aaruUri">AaruRemote URI</param>
|
2022-11-15 01:35:06 +00:00
|
|
|
/// <param name="errno">Sets the error if a device cannot be opened</param>
|
2022-03-26 18:31:04 +00:00
|
|
|
/// <returns>Device</returns>
|
2022-03-26 20:18:01 +00:00
|
|
|
internal static Device Create(Uri aaruUri, out ErrorNumber errno)
|
2022-03-26 18:31:04 +00:00
|
|
|
{
|
2022-03-26 20:18:01 +00:00
|
|
|
errno = ErrorNumber.NoError;
|
|
|
|
|
|
2022-03-26 18:31:04 +00:00
|
|
|
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}";
|
|
|
|
|
|
2023-10-05 01:52:48 +01:00
|
|
|
dev.DevicePath = devicePath;
|
2022-03-26 18:31:04 +00:00
|
|
|
|
2022-04-18 15:45:21 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2022-03-26 18:31:04 +00:00
|
|
|
|
2022-03-26 20:18:01 +00:00
|
|
|
dev.Error = !dev._remote.Open(devicePath, out int remoteErrno);
|
|
|
|
|
dev.LastError = remoteErrno;
|
2022-03-26 18:31:04 +00:00
|
|
|
|
2022-03-26 20:18:01 +00:00
|
|
|
// TODO: Convert error codes
|
2022-03-26 18:31:04 +00:00
|
|
|
if(dev.Error)
|
2022-03-26 20:18:01 +00:00
|
|
|
{
|
|
|
|
|
errno = (ErrorNumber)remoteErrno;
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2022-03-26 18:31:04 +00:00
|
|
|
|
|
|
|
|
if(dev._remote.ServerOperatingSystem == "Linux")
|
2022-11-13 20:38:15 +00:00
|
|
|
ReadMultipleBlockCannotSetBlockCount = true;
|
2022-03-26 18:31:04 +00:00
|
|
|
|
|
|
|
|
dev.Type = DeviceType.Unknown;
|
|
|
|
|
dev.ScsiType = PeripheralDeviceTypes.UnknownDevice;
|
|
|
|
|
|
|
|
|
|
if(dev.Error)
|
2022-11-14 01:49:10 +00:00
|
|
|
{
|
|
|
|
|
errno = (ErrorNumber)dev.LastError;
|
2022-03-26 20:18:01 +00:00
|
|
|
|
2022-11-14 01:49:10 +00:00
|
|
|
return null;
|
|
|
|
|
}
|
2022-03-26 18:31:04 +00:00
|
|
|
|
|
|
|
|
dev.Type = dev._remote.GetDeviceType();
|
|
|
|
|
|
|
|
|
|
switch(dev.Type)
|
|
|
|
|
{
|
|
|
|
|
case DeviceType.SecureDigital:
|
|
|
|
|
case DeviceType.MMC:
|
2023-10-05 01:52:48 +01:00
|
|
|
if(!dev._remote.GetSdhciRegisters(out dev.CachedCsd, out dev.CachedCid, out dev.CachedOcr,
|
|
|
|
|
out dev.CachedScr))
|
2022-03-26 18:31:04 +00:00
|
|
|
{
|
|
|
|
|
dev.Type = DeviceType.SCSI;
|
|
|
|
|
dev.ScsiType = PeripheralDeviceTypes.DirectAccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-03 23:12:01 +01:00
|
|
|
#region SecureDigital / MultiMediaCard
|
|
|
|
|
|
2023-10-05 01:52:48 +01:00
|
|
|
if(dev.CachedCid != null)
|
2022-03-26 18:31:04 +00:00
|
|
|
{
|
|
|
|
|
dev.ScsiType = PeripheralDeviceTypes.DirectAccess;
|
|
|
|
|
dev.IsRemovable = false;
|
|
|
|
|
|
2023-10-05 01:52:48 +01:00
|
|
|
if(dev.CachedScr != null)
|
2022-03-26 18:31:04 +00:00
|
|
|
{
|
|
|
|
|
dev.Type = DeviceType.SecureDigital;
|
2023-10-05 01:52:48 +01:00
|
|
|
CID decoded = Decoders.SecureDigital.Decoders.DecodeCID(dev.CachedCid);
|
2022-03-26 18:31:04 +00:00
|
|
|
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;
|
2023-10-05 01:52:48 +01:00
|
|
|
Decoders.MMC.CID decoded = Decoders.MMC.Decoders.DecodeCID(dev.CachedCid);
|
2022-11-15 15:58:43 +00:00
|
|
|
dev.Manufacturer = Decoders.MMC.VendorString.Prettify(decoded.Manufacturer);
|
2022-03-26 18:31:04 +00:00
|
|
|
dev.Model = decoded.ProductName;
|
|
|
|
|
|
|
|
|
|
dev.FirmwareRevision =
|
|
|
|
|
$"{(decoded.ProductRevision & 0xF0) >> 4:X2}.{decoded.ProductRevision & 0x0F:X2}";
|
|
|
|
|
|
|
|
|
|
dev.Serial = $"{decoded.ProductSerialNumber}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-03 23:12:01 +01:00
|
|
|
#endregion SecureDigital / MultiMediaCard
|
|
|
|
|
|
|
|
|
|
#region USB
|
|
|
|
|
|
2022-03-26 18:31:04 +00:00
|
|
|
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;
|
2023-10-05 01:52:48 +01:00
|
|
|
dev.UsbVendor = remoteUsbVendor;
|
|
|
|
|
dev.UsbProduct = remoteUsbProduct;
|
2022-03-26 18:31:04 +00:00
|
|
|
dev.UsbManufacturerString = remoteUsbManufacturer;
|
|
|
|
|
dev.UsbProductString = remoteUsbProductString;
|
|
|
|
|
dev.UsbSerialString = remoteUsbSerial;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-03 23:12:01 +01:00
|
|
|
#endregion USB
|
|
|
|
|
|
|
|
|
|
#region FireWire
|
|
|
|
|
|
2023-10-05 01:52:48 +01:00
|
|
|
if(dev._remote.GetFireWireData(out dev.FirewireVendor, out dev.FirewireModel, out dev.FirewireGuid,
|
2022-03-26 18:31:04 +00:00
|
|
|
out string remoteFireWireVendorName, out string remoteFireWireModelName))
|
|
|
|
|
{
|
|
|
|
|
dev.IsFireWire = true;
|
|
|
|
|
dev.FireWireVendorName = remoteFireWireVendorName;
|
|
|
|
|
dev.FireWireModelName = remoteFireWireModelName;
|
|
|
|
|
}
|
2023-10-03 23:12:01 +01:00
|
|
|
|
|
|
|
|
#endregion FireWire
|
|
|
|
|
|
|
|
|
|
#region PCMCIA
|
|
|
|
|
|
2022-11-13 21:14:18 +00:00
|
|
|
if(!dev._remote.GetPcmciaData(out byte[] cisBuf))
|
|
|
|
|
return dev;
|
|
|
|
|
|
|
|
|
|
dev.IsPcmcia = true;
|
|
|
|
|
dev.Cis = cisBuf;
|
2023-10-03 23:12:01 +01:00
|
|
|
|
|
|
|
|
#endregion PCMCIA
|
2022-03-26 18:31:04 +00:00
|
|
|
|
|
|
|
|
return dev;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public override void Close()
|
|
|
|
|
{
|
|
|
|
|
if(_remote == null)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
_remote.Close();
|
|
|
|
|
_remote.Disconnect();
|
|
|
|
|
}
|
|
|
|
|
}
|