2017-05-19 20:28:49 +01:00
|
|
|
// /***************************************************************************
|
2020-02-27 12:31:25 +00:00
|
|
|
// Aaru Data Preservation Suite
|
2015-10-12 06:39:31 +01:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Filename : Command.cs
|
2016-07-28 18:13:49 +01:00
|
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
2015-10-12 06:39:31 +01:00
|
|
|
//
|
2016-07-28 18:13:49 +01:00
|
|
|
// Component : Linux direct device access.
|
2015-10-12 06:39:31 +01:00
|
|
|
//
|
|
|
|
|
// --[ Description ] ----------------------------------------------------------
|
|
|
|
|
//
|
2016-07-28 18:13:49 +01:00
|
|
|
// Contains a high level representation of the Linux syscalls used to
|
|
|
|
|
// directly interface devices.
|
2015-10-12 06:39:31 +01:00
|
|
|
//
|
|
|
|
|
// --[ License ] --------------------------------------------------------------
|
|
|
|
|
//
|
2016-07-28 18:13:49 +01:00
|
|
|
// 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
|
2015-10-12 06:39:31 +01:00
|
|
|
// License, or (at your option) any later version.
|
|
|
|
|
//
|
2016-07-28 18:13:49 +01:00
|
|
|
// 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.
|
2015-10-12 06:39:31 +01:00
|
|
|
//
|
2016-07-28 18:13:49 +01:00
|
|
|
// 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/>.
|
2015-10-12 06:39:31 +01:00
|
|
|
//
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2022-02-18 10:02:53 +00:00
|
|
|
// Copyright © 2011-2022 Natalia Portillo
|
2015-10-12 06:39:31 +01:00
|
|
|
// ****************************************************************************/
|
|
|
|
|
|
|
|
|
|
using System;
|
2015-10-12 06:25:49 +01:00
|
|
|
using System.Runtime.InteropServices;
|
2017-12-21 14:30:38 +00:00
|
|
|
using System.Text;
|
2020-02-27 00:33:26 +00:00
|
|
|
using Aaru.CommonTypes.Interop;
|
|
|
|
|
using Aaru.Decoders.ATA;
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2020-02-27 00:33:26 +00:00
|
|
|
namespace Aaru.Devices.Linux
|
2015-10-12 06:25:49 +01:00
|
|
|
{
|
2020-02-29 18:03:35 +00:00
|
|
|
internal static class Command
|
2015-10-12 06:25:49 +01:00
|
|
|
{
|
2020-02-29 18:03:35 +00:00
|
|
|
/// <summary>Sends a SCSI command</summary>
|
2015-10-12 20:08:56 +01:00
|
|
|
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
|
|
|
|
/// <param name="fd">File handle</param>
|
|
|
|
|
/// <param name="cdb">SCSI CDB</param>
|
|
|
|
|
/// <param name="buffer">Buffer for SCSI command response</param>
|
|
|
|
|
/// <param name="senseBuffer">Buffer with the SCSI sense</param>
|
|
|
|
|
/// <param name="timeout">Timeout in seconds</param>
|
|
|
|
|
/// <param name="direction">SCSI command transfer direction</param>
|
|
|
|
|
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
2017-12-23 20:04:36 +00:00
|
|
|
/// <param name="sense">
|
|
|
|
|
/// <c>True</c> if SCSI error returned non-OK status and <paramref name="senseBuffer" /> contains SCSI
|
|
|
|
|
/// sense
|
|
|
|
|
/// </param>
|
2020-02-29 18:03:35 +00:00
|
|
|
internal static int SendScsiCommand(int fd, byte[] cdb, ref byte[] buffer, out byte[] senseBuffer, uint timeout,
|
|
|
|
|
ScsiIoctlDirection direction, out double duration, out bool sense)
|
2015-10-12 06:25:49 +01:00
|
|
|
{
|
|
|
|
|
senseBuffer = null;
|
2018-04-02 23:10:13 +01:00
|
|
|
duration = 0;
|
|
|
|
|
sense = false;
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(buffer == null)
|
|
|
|
|
return -1;
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
var ioHdr = new SgIoHdrT();
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2021-03-25 23:23:18 +00:00
|
|
|
senseBuffer = new byte[64];
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2018-04-02 23:10:13 +01:00
|
|
|
ioHdr.interface_id = 'S';
|
|
|
|
|
ioHdr.cmd_len = (byte)cdb.Length;
|
|
|
|
|
ioHdr.mx_sb_len = (byte)senseBuffer.Length;
|
2017-12-20 17:15:26 +00:00
|
|
|
ioHdr.dxfer_direction = direction;
|
2018-04-02 23:10:13 +01:00
|
|
|
ioHdr.dxfer_len = (uint)buffer.Length;
|
|
|
|
|
ioHdr.dxferp = Marshal.AllocHGlobal(buffer.Length);
|
|
|
|
|
ioHdr.cmdp = Marshal.AllocHGlobal(cdb.Length);
|
|
|
|
|
ioHdr.sbp = Marshal.AllocHGlobal(senseBuffer.Length);
|
|
|
|
|
ioHdr.timeout = timeout * 1000;
|
|
|
|
|
ioHdr.flags = (uint)SgFlags.DirectIo;
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
Marshal.Copy(buffer, 0, ioHdr.dxferp, buffer.Length);
|
|
|
|
|
Marshal.Copy(cdb, 0, ioHdr.cmdp, cdb.Length);
|
|
|
|
|
Marshal.Copy(senseBuffer, 0, ioHdr.sbp, senseBuffer.Length);
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2016-02-10 03:00:39 +00:00
|
|
|
DateTime start = DateTime.UtcNow;
|
2018-04-02 23:10:13 +01:00
|
|
|
int error = Extern.ioctlSg(fd, LinuxIoctl.SgIo, ref ioHdr);
|
|
|
|
|
DateTime end = DateTime.UtcNow;
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(error < 0)
|
|
|
|
|
error = Marshal.GetLastWin32Error();
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
Marshal.Copy(ioHdr.dxferp, buffer, 0, buffer.Length);
|
|
|
|
|
Marshal.Copy(ioHdr.cmdp, cdb, 0, cdb.Length);
|
|
|
|
|
Marshal.Copy(ioHdr.sbp, senseBuffer, 0, senseBuffer.Length);
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
sense |= (ioHdr.info & SgInfo.OkMask) != SgInfo.Ok;
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2017-12-22 03:13:43 +00:00
|
|
|
duration = ioHdr.duration > 0 ? ioHdr.duration : (end - start).TotalMilliseconds;
|
2015-10-12 06:25:49 +01:00
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
Marshal.FreeHGlobal(ioHdr.dxferp);
|
|
|
|
|
Marshal.FreeHGlobal(ioHdr.cmdp);
|
|
|
|
|
Marshal.FreeHGlobal(ioHdr.sbp);
|
2015-12-30 11:45:27 +00:00
|
|
|
|
2015-10-12 06:25:49 +01:00
|
|
|
return error;
|
|
|
|
|
}
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
/// <summary>Converts ATA protocol to SG_IO direction</summary>
|
2017-12-23 02:32:02 +00:00
|
|
|
/// <param name="protocol">ATA protocol</param>
|
|
|
|
|
/// <returns>SG_IO direction</returns>
|
2015-10-19 04:39:39 +01:00
|
|
|
static ScsiIoctlDirection AtaProtocolToScsiDirection(AtaProtocol protocol)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2016-04-19 02:11:47 +01:00
|
|
|
switch(protocol)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2015-10-19 04:39:39 +01:00
|
|
|
case AtaProtocol.DeviceDiagnostic:
|
|
|
|
|
case AtaProtocol.DeviceReset:
|
|
|
|
|
case AtaProtocol.HardReset:
|
|
|
|
|
case AtaProtocol.NonData:
|
|
|
|
|
case AtaProtocol.SoftReset:
|
2017-12-19 20:33:03 +00:00
|
|
|
case AtaProtocol.ReturnResponse: return ScsiIoctlDirection.None;
|
2015-10-19 04:39:39 +01:00
|
|
|
case AtaProtocol.PioIn:
|
2017-12-19 20:33:03 +00:00
|
|
|
case AtaProtocol.UDmaIn: return ScsiIoctlDirection.In;
|
2015-10-19 04:39:39 +01:00
|
|
|
case AtaProtocol.PioOut:
|
2017-12-19 20:33:03 +00:00
|
|
|
case AtaProtocol.UDmaOut: return ScsiIoctlDirection.Out;
|
|
|
|
|
default: return ScsiIoctlDirection.Unspecified;
|
2015-10-14 02:53:46 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
/// <summary>Sends an ATA command in CHS mode</summary>
|
2017-12-23 02:32:02 +00:00
|
|
|
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
|
|
|
|
/// <param name="fd">File handle</param>
|
|
|
|
|
/// <param name="buffer">Buffer for SCSI command response</param>
|
|
|
|
|
/// <param name="timeout">Timeout in seconds</param>
|
|
|
|
|
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
|
|
|
|
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
|
|
|
|
/// <param name="registers">Registers to send to drive</param>
|
|
|
|
|
/// <param name="errorRegisters">Registers returned by drive</param>
|
|
|
|
|
/// <param name="protocol">ATA protocol to use</param>
|
|
|
|
|
/// <param name="transferRegister">Which register contains the transfer count</param>
|
|
|
|
|
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
|
2020-02-29 18:03:35 +00:00
|
|
|
internal static int SendAtaCommand(int fd, AtaRegistersChs registers, out AtaErrorRegistersChs errorRegisters,
|
|
|
|
|
AtaProtocol protocol, AtaTransferRegister transferRegister,
|
|
|
|
|
ref byte[] buffer, uint timeout, bool transferBlocks, out double duration,
|
|
|
|
|
out bool sense)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2018-04-02 23:10:13 +01:00
|
|
|
duration = 0;
|
|
|
|
|
sense = false;
|
2017-12-22 02:04:18 +00:00
|
|
|
errorRegisters = new AtaErrorRegistersChs();
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(buffer == null)
|
|
|
|
|
return -1;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2015-10-15 01:46:31 +01:00
|
|
|
byte[] cdb = new byte[16];
|
2015-10-19 04:39:39 +01:00
|
|
|
cdb[0] = (byte)ScsiCommands.AtaPassThrough16;
|
2015-10-14 02:53:46 +01:00
|
|
|
cdb[1] = (byte)(((byte)protocol << 1) & 0x1E);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
|
|
|
if(transferRegister != AtaTransferRegister.NoTransfer &&
|
|
|
|
|
protocol != AtaProtocol.NonData)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2016-04-19 02:11:47 +01:00
|
|
|
switch(protocol)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2015-10-19 04:39:39 +01:00
|
|
|
case AtaProtocol.PioIn:
|
|
|
|
|
case AtaProtocol.UDmaIn:
|
2015-10-14 02:53:46 +01:00
|
|
|
cdb[2] = 0x08;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
2015-10-14 02:53:46 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cdb[2] = 0x00;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
2015-10-14 02:53:46 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(transferBlocks)
|
|
|
|
|
cdb[2] |= 0x04;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
|
|
|
|
cdb[2] |= (byte)((int)transferRegister & 0x03);
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-06 18:16:55 +01:00
|
|
|
//cdb[2] |= 0x20;
|
2015-10-15 01:46:31 +01:00
|
|
|
|
2018-04-02 23:10:13 +01:00
|
|
|
cdb[4] = registers.Feature;
|
|
|
|
|
cdb[6] = registers.SectorCount;
|
|
|
|
|
cdb[8] = registers.Sector;
|
2017-12-22 02:04:18 +00:00
|
|
|
cdb[10] = registers.CylinderLow;
|
|
|
|
|
cdb[12] = registers.CylinderHigh;
|
|
|
|
|
cdb[13] = registers.DeviceHead;
|
|
|
|
|
cdb[14] = registers.Command;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout,
|
2017-12-19 20:33:03 +00:00
|
|
|
AtaProtocolToScsiDirection(protocol), out duration, out sense);
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(senseBuffer.Length < 22 ||
|
|
|
|
|
(senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C))
|
|
|
|
|
return error;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2017-12-22 02:04:18 +00:00
|
|
|
errorRegisters.Error = senseBuffer[11];
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2018-04-02 23:10:13 +01:00
|
|
|
errorRegisters.SectorCount = senseBuffer[13];
|
|
|
|
|
errorRegisters.Sector = senseBuffer[15];
|
|
|
|
|
errorRegisters.CylinderLow = senseBuffer[17];
|
2017-12-22 02:04:18 +00:00
|
|
|
errorRegisters.CylinderHigh = senseBuffer[19];
|
2018-04-02 23:10:13 +01:00
|
|
|
errorRegisters.DeviceHead = senseBuffer[20];
|
|
|
|
|
errorRegisters.Status = senseBuffer[21];
|
2015-10-15 01:46:31 +01:00
|
|
|
|
2017-12-22 02:04:18 +00:00
|
|
|
sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
/// <summary>Sends an ATA command in 28-bit LBA mode</summary>
|
2017-12-23 02:32:02 +00:00
|
|
|
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
|
|
|
|
/// <param name="fd">File handle</param>
|
|
|
|
|
/// <param name="buffer">Buffer for SCSI command response</param>
|
|
|
|
|
/// <param name="timeout">Timeout in seconds</param>
|
|
|
|
|
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
|
|
|
|
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
|
|
|
|
/// <param name="registers">Registers to send to drive</param>
|
|
|
|
|
/// <param name="errorRegisters">Registers returned by drive</param>
|
|
|
|
|
/// <param name="protocol">ATA protocol to use</param>
|
|
|
|
|
/// <param name="transferRegister">Which register contains the transfer count</param>
|
|
|
|
|
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
|
2020-02-29 18:03:35 +00:00
|
|
|
internal static int SendAtaCommand(int fd, AtaRegistersLba28 registers,
|
|
|
|
|
out AtaErrorRegistersLba28 errorRegisters, AtaProtocol protocol,
|
|
|
|
|
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
|
|
|
|
bool transferBlocks, out double duration, out bool sense)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2018-04-02 23:10:13 +01:00
|
|
|
duration = 0;
|
|
|
|
|
sense = false;
|
2017-12-22 02:04:18 +00:00
|
|
|
errorRegisters = new AtaErrorRegistersLba28();
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(buffer == null)
|
|
|
|
|
return -1;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2015-10-15 01:46:31 +01:00
|
|
|
byte[] cdb = new byte[16];
|
2015-10-19 04:39:39 +01:00
|
|
|
cdb[0] = (byte)ScsiCommands.AtaPassThrough16;
|
2015-10-14 02:53:46 +01:00
|
|
|
cdb[1] = (byte)(((byte)protocol << 1) & 0x1E);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
|
|
|
if(transferRegister != AtaTransferRegister.NoTransfer &&
|
|
|
|
|
protocol != AtaProtocol.NonData)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2016-04-19 02:11:47 +01:00
|
|
|
switch(protocol)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2015-10-19 04:39:39 +01:00
|
|
|
case AtaProtocol.PioIn:
|
|
|
|
|
case AtaProtocol.UDmaIn:
|
2015-10-14 02:53:46 +01:00
|
|
|
cdb[2] = 0x08;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
2015-10-14 02:53:46 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cdb[2] = 0x00;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
2015-10-14 02:53:46 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(transferBlocks)
|
|
|
|
|
cdb[2] |= 0x04;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
|
|
|
|
cdb[2] |= (byte)((int)transferRegister & 0x03);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 01:46:31 +01:00
|
|
|
cdb[2] |= 0x20;
|
|
|
|
|
|
2018-04-02 23:10:13 +01:00
|
|
|
cdb[4] = registers.Feature;
|
|
|
|
|
cdb[6] = registers.SectorCount;
|
|
|
|
|
cdb[8] = registers.LbaLow;
|
2017-12-22 02:04:18 +00:00
|
|
|
cdb[10] = registers.LbaMid;
|
|
|
|
|
cdb[12] = registers.LbaHigh;
|
|
|
|
|
cdb[13] = registers.DeviceHead;
|
|
|
|
|
cdb[14] = registers.Command;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout,
|
2017-12-19 20:33:03 +00:00
|
|
|
AtaProtocolToScsiDirection(protocol), out duration, out sense);
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(senseBuffer.Length < 22 ||
|
|
|
|
|
(senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C))
|
|
|
|
|
return error;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2017-12-22 02:04:18 +00:00
|
|
|
errorRegisters.Error = senseBuffer[11];
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2017-12-22 02:04:18 +00:00
|
|
|
errorRegisters.SectorCount = senseBuffer[13];
|
2018-04-02 23:10:13 +01:00
|
|
|
errorRegisters.LbaLow = senseBuffer[15];
|
|
|
|
|
errorRegisters.LbaMid = senseBuffer[17];
|
|
|
|
|
errorRegisters.LbaHigh = senseBuffer[19];
|
|
|
|
|
errorRegisters.DeviceHead = senseBuffer[20];
|
|
|
|
|
errorRegisters.Status = senseBuffer[21];
|
2015-10-15 01:46:31 +01:00
|
|
|
|
2017-12-22 02:04:18 +00:00
|
|
|
sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
/// <summary>Sends an ATA command in 48-bit LBA mode</summary>
|
2017-12-23 02:32:02 +00:00
|
|
|
/// <returns>0 if no error occurred, otherwise, errno</returns>
|
|
|
|
|
/// <param name="fd">File handle</param>
|
|
|
|
|
/// <param name="buffer">Buffer for SCSI command response</param>
|
|
|
|
|
/// <param name="timeout">Timeout in seconds</param>
|
|
|
|
|
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
|
|
|
|
/// <param name="sense"><c>True</c> if ATA error returned non-OK status</param>
|
|
|
|
|
/// <param name="registers">Registers to send to drive</param>
|
|
|
|
|
/// <param name="errorRegisters">Registers returned by drive</param>
|
|
|
|
|
/// <param name="protocol">ATA protocol to use</param>
|
|
|
|
|
/// <param name="transferRegister">Which register contains the transfer count</param>
|
|
|
|
|
/// <param name="transferBlocks">Set to <c>true</c> if the transfer count is in blocks, otherwise it is in bytes</param>
|
2020-02-29 18:03:35 +00:00
|
|
|
internal static int SendAtaCommand(int fd, AtaRegistersLba48 registers,
|
|
|
|
|
out AtaErrorRegistersLba48 errorRegisters, AtaProtocol protocol,
|
|
|
|
|
AtaTransferRegister transferRegister, ref byte[] buffer, uint timeout,
|
|
|
|
|
bool transferBlocks, out double duration, out bool sense)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2018-04-02 23:10:13 +01:00
|
|
|
duration = 0;
|
|
|
|
|
sense = false;
|
2017-12-22 02:04:18 +00:00
|
|
|
errorRegisters = new AtaErrorRegistersLba48();
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(buffer == null)
|
|
|
|
|
return -1;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
|
|
|
|
byte[] cdb = new byte[16];
|
2018-04-02 23:10:13 +01:00
|
|
|
cdb[0] = (byte)ScsiCommands.AtaPassThrough16;
|
|
|
|
|
cdb[1] = (byte)(((byte)protocol << 1) & 0x1E);
|
2017-12-13 00:31:32 +00:00
|
|
|
cdb[1] |= 0x01;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
|
|
|
if(transferRegister != AtaTransferRegister.NoTransfer &&
|
|
|
|
|
protocol != AtaProtocol.NonData)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2016-04-19 02:11:47 +01:00
|
|
|
switch(protocol)
|
2015-10-14 02:53:46 +01:00
|
|
|
{
|
2015-10-19 04:39:39 +01:00
|
|
|
case AtaProtocol.PioIn:
|
|
|
|
|
case AtaProtocol.UDmaIn:
|
2015-10-14 02:53:46 +01:00
|
|
|
cdb[2] = 0x08;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
2015-10-14 02:53:46 +01:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
cdb[2] = 0x00;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
2015-10-14 02:53:46 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(transferBlocks)
|
|
|
|
|
cdb[2] |= 0x04;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
|
|
|
|
cdb[2] |= (byte)((int)transferRegister & 0x03);
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-15 01:46:31 +01:00
|
|
|
cdb[2] |= 0x20;
|
|
|
|
|
|
2018-04-02 23:10:13 +01:00
|
|
|
cdb[3] = (byte)((registers.Feature & 0xFF00) >> 8);
|
|
|
|
|
cdb[4] = (byte)(registers.Feature & 0xFF);
|
|
|
|
|
cdb[5] = (byte)((registers.SectorCount & 0xFF00) >> 8);
|
|
|
|
|
cdb[6] = (byte)(registers.SectorCount & 0xFF);
|
2021-07-29 00:56:12 +01:00
|
|
|
cdb[7] = registers.LbaLowPrevious;
|
|
|
|
|
cdb[8] = registers.LbaLowCurrent;
|
|
|
|
|
cdb[9] = registers.LbaMidPrevious;
|
|
|
|
|
cdb[10] = registers.LbaMidCurrent;
|
|
|
|
|
cdb[11] = registers.LbaHighPrevious;
|
|
|
|
|
cdb[12] = registers.LbaHighCurrent;
|
2017-12-22 02:04:18 +00:00
|
|
|
cdb[13] = registers.DeviceHead;
|
|
|
|
|
cdb[14] = registers.Command;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
int error = SendScsiCommand(fd, cdb, ref buffer, out byte[] senseBuffer, timeout,
|
2017-12-19 20:33:03 +00:00
|
|
|
AtaProtocolToScsiDirection(protocol), out duration, out sense);
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(senseBuffer.Length < 22 ||
|
|
|
|
|
(senseBuffer[8] != 0x09 && senseBuffer[9] != 0x0C))
|
|
|
|
|
return error;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2017-12-22 02:04:18 +00:00
|
|
|
errorRegisters.Error = senseBuffer[11];
|
2015-10-15 01:46:31 +01:00
|
|
|
|
2021-07-29 00:56:12 +01:00
|
|
|
errorRegisters.SectorCount = (ushort)((senseBuffer[12] << 8) + senseBuffer[13]);
|
|
|
|
|
errorRegisters.LbaLowPrevious = senseBuffer[14];
|
|
|
|
|
errorRegisters.LbaLowCurrent = senseBuffer[15];
|
|
|
|
|
errorRegisters.LbaMidPrevious = senseBuffer[16];
|
|
|
|
|
errorRegisters.LbaMidCurrent = senseBuffer[17];
|
|
|
|
|
errorRegisters.LbaHighPrevious = senseBuffer[18];
|
|
|
|
|
errorRegisters.LbaHighCurrent = senseBuffer[19];
|
|
|
|
|
errorRegisters.DeviceHead = senseBuffer[20];
|
|
|
|
|
errorRegisters.Status = senseBuffer[21];
|
2015-10-14 02:53:46 +01:00
|
|
|
|
2017-12-22 02:04:18 +00:00
|
|
|
sense = errorRegisters.Error != 0 || (errorRegisters.Status & 0xA5) != 0;
|
2015-10-14 02:53:46 +01:00
|
|
|
|
|
|
|
|
sense |= error != 0;
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
2015-12-31 16:12:22 +00:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
/// <summary>Sends a MMC/SD command</summary>
|
2016-10-22 22:58:01 +01:00
|
|
|
/// <returns>The result of the command.</returns>
|
|
|
|
|
/// <param name="fd">File handle</param>
|
|
|
|
|
/// <param name="command">MMC/SD opcode</param>
|
|
|
|
|
/// <param name="buffer">Buffer for MMC/SD command response</param>
|
|
|
|
|
/// <param name="timeout">Timeout in seconds</param>
|
|
|
|
|
/// <param name="duration">Time it took to execute the command in milliseconds</param>
|
|
|
|
|
/// <param name="sense"><c>True</c> if MMC/SD returned non-OK status</param>
|
|
|
|
|
/// <param name="write"><c>True</c> if data is sent from host to card</param>
|
|
|
|
|
/// <param name="isApplication"><c>True</c> if command should be preceded with CMD55</param>
|
|
|
|
|
/// <param name="flags">Flags indicating kind and place of response</param>
|
|
|
|
|
/// <param name="blocks">How many blocks to transfer</param>
|
|
|
|
|
/// <param name="argument">Command argument</param>
|
|
|
|
|
/// <param name="response">Response registers</param>
|
|
|
|
|
/// <param name="blockSize">Size of block in bytes</param>
|
2020-02-29 18:03:35 +00:00
|
|
|
internal static int SendMmcCommand(int 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)
|
2016-10-22 22:58:01 +01:00
|
|
|
{
|
|
|
|
|
response = null;
|
|
|
|
|
duration = 0;
|
2018-04-02 23:10:13 +01:00
|
|
|
sense = false;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(buffer == null)
|
|
|
|
|
return -1;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
var ioCmd = new MmcIocCmd();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
IntPtr bufPtr = Marshal.AllocHGlobal(buffer.Length);
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
ioCmd.write_flag = write;
|
2018-04-02 23:10:13 +01:00
|
|
|
ioCmd.is_ascmd = isApplication;
|
|
|
|
|
ioCmd.opcode = (uint)command;
|
|
|
|
|
ioCmd.arg = argument;
|
|
|
|
|
ioCmd.flags = flags;
|
|
|
|
|
ioCmd.blksz = blockSize;
|
|
|
|
|
ioCmd.blocks = blocks;
|
2020-02-29 18:03:35 +00:00
|
|
|
|
2016-10-22 22:58:01 +01:00
|
|
|
if(timeout > 0)
|
|
|
|
|
{
|
2017-12-20 17:15:26 +00:00
|
|
|
ioCmd.data_timeout_ns = timeout * 1000000000;
|
2018-04-02 23:10:13 +01:00
|
|
|
ioCmd.cmd_timeout_ms = timeout * 1000;
|
2016-10-22 22:58:01 +01:00
|
|
|
}
|
2018-04-02 23:10:13 +01:00
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
ioCmd.data_ptr = (ulong)bufPtr;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
Marshal.Copy(buffer, 0, bufPtr, buffer.Length);
|
|
|
|
|
|
|
|
|
|
DateTime start = DateTime.UtcNow;
|
2018-04-02 23:10:13 +01:00
|
|
|
int error = Extern.ioctlMmc(fd, LinuxIoctl.MmcIocCmd, ref ioCmd);
|
|
|
|
|
DateTime end = DateTime.UtcNow;
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
sense |= error < 0;
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
if(error < 0)
|
|
|
|
|
error = Marshal.GetLastWin32Error();
|
2016-10-22 22:58:01 +01:00
|
|
|
|
|
|
|
|
Marshal.Copy(bufPtr, buffer, 0, buffer.Length);
|
|
|
|
|
|
2017-12-20 17:15:26 +00:00
|
|
|
response = ioCmd.response;
|
2016-10-22 22:58:01 +01:00
|
|
|
duration = (end - start).TotalMilliseconds;
|
|
|
|
|
|
|
|
|
|
Marshal.FreeHGlobal(bufPtr);
|
|
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 20:58:58 +00:00
|
|
|
internal static int SendMultipleMmcCommands(int fd, Device.MmcSingleCommand[] commands, out double duration,
|
|
|
|
|
out bool sense, uint timeout = 0)
|
|
|
|
|
{
|
|
|
|
|
duration = 0;
|
|
|
|
|
sense = false;
|
2021-08-17 16:27:42 +01:00
|
|
|
int off;
|
2020-12-12 20:58:58 +00:00
|
|
|
|
|
|
|
|
// Create array for buffers
|
|
|
|
|
IntPtr[] bufferPointers = new IntPtr[commands.Length];
|
|
|
|
|
|
2020-12-13 20:33:36 +00:00
|
|
|
// Allocate memory for the array for commands
|
|
|
|
|
byte[] ioMultiCmd = new byte[sizeof(ulong) + (Marshal.SizeOf<MmcIocCmd>() * commands.Length)];
|
|
|
|
|
|
|
|
|
|
// First value of array is uint64 with count of commands
|
|
|
|
|
Array.Copy(BitConverter.GetBytes((ulong)commands.Length), 0, ioMultiCmd, 0, sizeof(ulong));
|
2020-12-12 20:58:58 +00:00
|
|
|
|
|
|
|
|
off = sizeof(ulong);
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < commands.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
// Create command
|
|
|
|
|
var ioCmd = new MmcIocCmd();
|
|
|
|
|
|
|
|
|
|
// Allocate buffer
|
|
|
|
|
bufferPointers[i] = Marshal.AllocHGlobal(commands[i].buffer.Length);
|
|
|
|
|
|
|
|
|
|
// Define command
|
|
|
|
|
ioCmd.write_flag = commands[i].write;
|
|
|
|
|
ioCmd.is_ascmd = commands[i].isApplication;
|
|
|
|
|
ioCmd.opcode = (uint)commands[i].command;
|
|
|
|
|
ioCmd.arg = commands[i].argument;
|
|
|
|
|
ioCmd.flags = commands[i].flags;
|
|
|
|
|
ioCmd.blksz = commands[i].blockSize;
|
|
|
|
|
ioCmd.blocks = commands[i].blocks;
|
|
|
|
|
|
|
|
|
|
if(timeout > 0)
|
|
|
|
|
{
|
|
|
|
|
ioCmd.data_timeout_ns = timeout * 1000000000;
|
|
|
|
|
ioCmd.cmd_timeout_ms = timeout * 1000;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ioCmd.data_ptr = (ulong)bufferPointers[i];
|
|
|
|
|
|
|
|
|
|
// Copy buffer to unmanaged space
|
|
|
|
|
Marshal.Copy(commands[i].buffer, 0, bufferPointers[i], commands[i].buffer.Length);
|
|
|
|
|
|
2020-12-13 20:33:36 +00:00
|
|
|
// Copy command to array
|
|
|
|
|
byte[] ioCmdBytes = Helpers.Marshal.StructureToByteArrayLittleEndian(ioCmd);
|
|
|
|
|
Array.Copy(ioCmdBytes, 0, ioMultiCmd, off, Marshal.SizeOf<MmcIocCmd>());
|
2020-12-12 20:58:58 +00:00
|
|
|
|
|
|
|
|
// Advance pointer
|
|
|
|
|
off += Marshal.SizeOf<MmcIocCmd>();
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-13 20:33:36 +00:00
|
|
|
// Allocate unmanaged memory for array of commands
|
|
|
|
|
IntPtr ioMultiCmdPtr = Marshal.AllocHGlobal(ioMultiCmd.Length);
|
|
|
|
|
|
|
|
|
|
// Copy array of commands to unmanaged memory
|
|
|
|
|
Marshal.Copy(ioMultiCmd, 0, ioMultiCmdPtr, ioMultiCmd.Length);
|
|
|
|
|
|
2020-12-12 20:58:58 +00:00
|
|
|
// Send command
|
|
|
|
|
DateTime start = DateTime.UtcNow;
|
2020-12-13 20:33:36 +00:00
|
|
|
int error = Extern.ioctlMmcMulti(fd, LinuxIoctl.MmcIocMultiCmd, ioMultiCmdPtr);
|
2020-12-12 20:58:58 +00:00
|
|
|
DateTime end = DateTime.UtcNow;
|
|
|
|
|
|
|
|
|
|
sense |= error < 0;
|
|
|
|
|
|
|
|
|
|
if(error < 0)
|
|
|
|
|
error = Marshal.GetLastWin32Error();
|
|
|
|
|
|
|
|
|
|
duration = (end - start).TotalMilliseconds;
|
|
|
|
|
|
|
|
|
|
off = sizeof(ulong);
|
|
|
|
|
|
2020-12-13 20:33:36 +00:00
|
|
|
// Copy array from unmanaged memory
|
|
|
|
|
Marshal.Copy(ioMultiCmdPtr, ioMultiCmd, 0, ioMultiCmd.Length);
|
|
|
|
|
|
2020-12-12 20:58:58 +00:00
|
|
|
// TODO: Use real pointers this is too slow
|
|
|
|
|
for(int i = 0; i < commands.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
byte[] tmp = new byte[Marshal.SizeOf<MmcIocCmd>()];
|
|
|
|
|
|
|
|
|
|
// Copy command to managed space
|
2020-12-13 20:33:36 +00:00
|
|
|
Array.Copy(ioMultiCmd, off, tmp, 0, tmp.Length);
|
|
|
|
|
MmcIocCmd command = Helpers.Marshal.ByteArrayToStructureLittleEndian<MmcIocCmd>(tmp);
|
|
|
|
|
|
|
|
|
|
// Copy response
|
|
|
|
|
commands[i].response = command.response;
|
2020-12-12 20:58:58 +00:00
|
|
|
|
|
|
|
|
// Copy buffer to managed space
|
|
|
|
|
Marshal.Copy(bufferPointers[i], commands[i].buffer, 0, commands[i].buffer.Length);
|
|
|
|
|
|
|
|
|
|
// Free buffer
|
|
|
|
|
Marshal.FreeHGlobal(bufferPointers[i]);
|
|
|
|
|
|
|
|
|
|
// Advance pointer
|
|
|
|
|
off += Marshal.SizeOf<MmcIocCmd>();
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-13 20:33:36 +00:00
|
|
|
// Free unmanaged memory
|
|
|
|
|
Marshal.FreeHGlobal(ioMultiCmdPtr);
|
2020-12-12 20:58:58 +00:00
|
|
|
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-12 21:03:01 +00:00
|
|
|
internal static int ReOpen(string devicePath, int fd, out object newFd)
|
|
|
|
|
{
|
|
|
|
|
newFd = -1;
|
|
|
|
|
|
|
|
|
|
int ret = Extern.close(fd);
|
|
|
|
|
|
|
|
|
|
if(ret < 0)
|
|
|
|
|
return Marshal.GetLastWin32Error();
|
|
|
|
|
|
|
|
|
|
newFd = Extern.open(devicePath, FileFlags.ReadWrite | FileFlags.NonBlocking | FileFlags.CreateNew);
|
|
|
|
|
|
|
|
|
|
if((int)newFd >= 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
int error = Marshal.GetLastWin32Error();
|
|
|
|
|
|
|
|
|
|
if(error != 13 &&
|
|
|
|
|
error != 30)
|
|
|
|
|
return Marshal.GetLastWin32Error();
|
|
|
|
|
|
|
|
|
|
newFd = Extern.open(devicePath, FileFlags.Readonly | FileFlags.NonBlocking);
|
|
|
|
|
|
|
|
|
|
return (int)newFd < 0 ? Marshal.GetLastWin32Error() : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-29 18:03:35 +00:00
|
|
|
/// <summary>Reads the contents of a symbolic link</summary>
|
2017-12-23 02:32:02 +00:00
|
|
|
/// <param name="path">Path to the symbolic link</param>
|
|
|
|
|
/// <returns>Contents of the symbolic link</returns>
|
|
|
|
|
internal static string ReadLink(string path)
|
2015-12-31 16:12:22 +00:00
|
|
|
{
|
* DiscImageChef.CommonTypes/MediaTypeFromSCSI.cs:
* DiscImageChef.CommonTypes/DiscImageChef.CommonTypes.csproj:
Added method to calculate MediaType from SCSI parameters
(mode, density, medium type, device type, etc).
* DiscImageChef.Metadata/DeviceReport.cs:
Added command to guess drive and media parameters and output
an XML report of them.
* DiscImageChef/Commands/DeviceReport.cs:
* DiscImageChef.Metadata/DiscImageChef.Metadata.csproj:
Added command to guess drive and media parameters and output
an XML report of them.
* DiscImageChef/Commands/DumpMedia.cs:
Added preliminary command to dump media. Only SCSI for now.
CDs and tapes are not supported. Errors are blalanty
ignored. Options are incomplete. Not yet usable.
* DiscImageChef/Core/Checksum.cs:
* DiscImageChef/Commands/CreateSidecar.cs:
Moved checksum generation to a separate class.
* CICMMetadata:
Added support for ADIP.
* DiscImageChef.CommonTypes/MediaType.cs:
Added parameters of UDO media.
Moved DataPlay outside of Iomega, as it's not from that
manufacturer.
Added missing Exatape media and corrected 160m XL one.
Added SyJet media.
Added all ECMA defined magneto-optical (sectors calculated
from specifications, unchecked).
Added PD media.
Added Imation 320Gb RDX.
Added generic USB flash drives.
* DiscImageChef.Decoders/SCSI/Enums.cs:
Make enumerations public.
* DiscImageChef.Decoders/SCSI/Inquiry.cs:
* DiscImageChef.Devices/Device/Constructor.cs:
Trim space padded strings on SCSI INQUIRY.
* DiscImageChef.Devices/Device/ScsiCommands/MMC.cs:
Added PREVENT ALLOW MEDIUM REMOVAL.
Added START STOP UNIT.
* DiscImageChef.Devices/Device/ScsiCommands/NEC.cs:
Rename NEC methods.
* DiscImageChef.Devices/Device/ScsiCommands/Pioneer.cs:
Corrected Pioneer transfer length calculation.
* DiscImageChef.Devices/Device/ScsiCommands/Plextor.cs:
Renamed Plextor methods.
* DiscImageChef.Devices/Device/ScsiCommands/SPC.cs:
Renamed SSC PREVENT ALLOW MEDIUM REMOVAL to uncollide with
MMC same name but different command.
* DiscImageChef.Devices/DiscImageChef.Devices.csproj:
Set platform target to x86 (does it really matter?).
* DiscImageChef.Devices/Linux/Command.cs:
Reduced allocation for readlink() to current kernel
MAX_PATH.
* DiscImageChef.Devices/Linux/Enums.cs:
Modified Linux ioctl to 32-bit. Works on 64-bit also. Solves
commands not working on 32-bit environments.
* DiscImageChef.DiscImages/ZZZRawImage.cs:
Changed ECMA-184 and ECMA-183 enums.
* DiscImageChef.Metadata/Dimensions.cs:
Added all ECMA defined magneto-opticals.
Added PD media.
Added 320Gb RDX.
Corrected Exatape 160m XL.
Added Exatape 22m and 28m.
* DiscImageChef.Metadata/MediaType.cs:
Added 356mm magneto-optical media.
Changed ECMA-184 and ECMA-183 enums.
Added USB generic flash drive.
* DiscImageChef/Commands/DeviceInfo.cs:
Corrected SCSI INQUIRY naming.
Corrected SCSI MODE SENSE (6) parameters.
Reduced SCSI MODE SENSE timeout, some devices just get stuck
with unsupported MODE SENSE commanda and must be left to
timeout.
Changed FUJITSU vendor string comparison.
* DiscImageChef/Commands/MediaInfo.cs:
Added method to calculate MediaType from SCSI parameters
(mode, density, medium type, device type, etc).
Changed some error WriteLine() to debug ones. Too much
verbosity.
Added DVD media type decoding from PFI.
Found a drive that dumps ADIP, enabling it again (not
decoded).
* DiscImageChef/Commands/MediaScan.cs:
Added option to generate ImgBurn compatible log to
media-scan command.
* DiscImageChef/DiscImageChef.csproj:
Moved checksum generation to a separate class.
Added command to guess drive and media parameters and output
an XML report of them.
Added preliminary command to dump media. Only SCSI for now.
CDs and tapes are not supported. Errors are blalanty
ignored. Options are incomplete. Not yet usable.
* DiscImageChef/Main.cs:
Added command to guess drive and media parameters and output
an XML report of them.
Added preliminary command to dump media. Only SCSI for now.
CDs and tapes are not supported. Errors are blalanty
ignored. Options are incomplete. Not yet usable.
* DiscImageChef/Options.cs:
Added command to guess drive and media parameters and output
an XML report of them.
Added preliminary command to dump media. Only SCSI for now.
CDs and tapes are not supported. Errors are blalanty
ignored. Options are incomplete. Not yet usable.
Added option to generate ImgBurn compatible log to media-scan
command.
2016-01-31 08:05:56 +00:00
|
|
|
IntPtr buf = Marshal.AllocHGlobal(4096);
|
2018-04-02 23:10:13 +01:00
|
|
|
int resultSize;
|
2015-12-31 16:12:22 +00:00
|
|
|
|
2018-04-11 07:16:45 +01:00
|
|
|
if(DetectOS.Is64Bit)
|
2015-12-31 16:12:22 +00:00
|
|
|
{
|
2016-07-28 22:25:26 +01:00
|
|
|
long result64 = Extern.readlink64(path, buf, 4096);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
|
|
|
if(result64 <= 0)
|
|
|
|
|
return null;
|
2016-04-19 02:11:47 +01:00
|
|
|
|
2015-12-31 16:12:22 +00:00
|
|
|
resultSize = (int)result64;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
* DiscImageChef.CommonTypes/MediaTypeFromSCSI.cs:
* DiscImageChef.CommonTypes/DiscImageChef.CommonTypes.csproj:
Added method to calculate MediaType from SCSI parameters
(mode, density, medium type, device type, etc).
* DiscImageChef.Metadata/DeviceReport.cs:
Added command to guess drive and media parameters and output
an XML report of them.
* DiscImageChef/Commands/DeviceReport.cs:
* DiscImageChef.Metadata/DiscImageChef.Metadata.csproj:
Added command to guess drive and media parameters and output
an XML report of them.
* DiscImageChef/Commands/DumpMedia.cs:
Added preliminary command to dump media. Only SCSI for now.
CDs and tapes are not supported. Errors are blalanty
ignored. Options are incomplete. Not yet usable.
* DiscImageChef/Core/Checksum.cs:
* DiscImageChef/Commands/CreateSidecar.cs:
Moved checksum generation to a separate class.
* CICMMetadata:
Added support for ADIP.
* DiscImageChef.CommonTypes/MediaType.cs:
Added parameters of UDO media.
Moved DataPlay outside of Iomega, as it's not from that
manufacturer.
Added missing Exatape media and corrected 160m XL one.
Added SyJet media.
Added all ECMA defined magneto-optical (sectors calculated
from specifications, unchecked).
Added PD media.
Added Imation 320Gb RDX.
Added generic USB flash drives.
* DiscImageChef.Decoders/SCSI/Enums.cs:
Make enumerations public.
* DiscImageChef.Decoders/SCSI/Inquiry.cs:
* DiscImageChef.Devices/Device/Constructor.cs:
Trim space padded strings on SCSI INQUIRY.
* DiscImageChef.Devices/Device/ScsiCommands/MMC.cs:
Added PREVENT ALLOW MEDIUM REMOVAL.
Added START STOP UNIT.
* DiscImageChef.Devices/Device/ScsiCommands/NEC.cs:
Rename NEC methods.
* DiscImageChef.Devices/Device/ScsiCommands/Pioneer.cs:
Corrected Pioneer transfer length calculation.
* DiscImageChef.Devices/Device/ScsiCommands/Plextor.cs:
Renamed Plextor methods.
* DiscImageChef.Devices/Device/ScsiCommands/SPC.cs:
Renamed SSC PREVENT ALLOW MEDIUM REMOVAL to uncollide with
MMC same name but different command.
* DiscImageChef.Devices/DiscImageChef.Devices.csproj:
Set platform target to x86 (does it really matter?).
* DiscImageChef.Devices/Linux/Command.cs:
Reduced allocation for readlink() to current kernel
MAX_PATH.
* DiscImageChef.Devices/Linux/Enums.cs:
Modified Linux ioctl to 32-bit. Works on 64-bit also. Solves
commands not working on 32-bit environments.
* DiscImageChef.DiscImages/ZZZRawImage.cs:
Changed ECMA-184 and ECMA-183 enums.
* DiscImageChef.Metadata/Dimensions.cs:
Added all ECMA defined magneto-opticals.
Added PD media.
Added 320Gb RDX.
Corrected Exatape 160m XL.
Added Exatape 22m and 28m.
* DiscImageChef.Metadata/MediaType.cs:
Added 356mm magneto-optical media.
Changed ECMA-184 and ECMA-183 enums.
Added USB generic flash drive.
* DiscImageChef/Commands/DeviceInfo.cs:
Corrected SCSI INQUIRY naming.
Corrected SCSI MODE SENSE (6) parameters.
Reduced SCSI MODE SENSE timeout, some devices just get stuck
with unsupported MODE SENSE commanda and must be left to
timeout.
Changed FUJITSU vendor string comparison.
* DiscImageChef/Commands/MediaInfo.cs:
Added method to calculate MediaType from SCSI parameters
(mode, density, medium type, device type, etc).
Changed some error WriteLine() to debug ones. Too much
verbosity.
Added DVD media type decoding from PFI.
Found a drive that dumps ADIP, enabling it again (not
decoded).
* DiscImageChef/Commands/MediaScan.cs:
Added option to generate ImgBurn compatible log to
media-scan command.
* DiscImageChef/DiscImageChef.csproj:
Moved checksum generation to a separate class.
Added command to guess drive and media parameters and output
an XML report of them.
Added preliminary command to dump media. Only SCSI for now.
CDs and tapes are not supported. Errors are blalanty
ignored. Options are incomplete. Not yet usable.
* DiscImageChef/Main.cs:
Added command to guess drive and media parameters and output
an XML report of them.
Added preliminary command to dump media. Only SCSI for now.
CDs and tapes are not supported. Errors are blalanty
ignored. Options are incomplete. Not yet usable.
* DiscImageChef/Options.cs:
Added command to guess drive and media parameters and output
an XML report of them.
Added preliminary command to dump media. Only SCSI for now.
CDs and tapes are not supported. Errors are blalanty
ignored. Options are incomplete. Not yet usable.
Added option to generate ImgBurn compatible log to media-scan
command.
2016-01-31 08:05:56 +00:00
|
|
|
int result = Extern.readlink(path, buf, 4096);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
|
|
|
if(result <= 0)
|
|
|
|
|
return null;
|
2015-12-31 16:12:22 +00:00
|
|
|
|
|
|
|
|
resultSize = result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
byte[] resultString = new byte[resultSize];
|
|
|
|
|
Marshal.Copy(buf, resultString, 0, resultSize);
|
|
|
|
|
Marshal.FreeHGlobal(buf);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
2017-12-21 14:30:38 +00:00
|
|
|
return Encoding.ASCII.GetString(resultString);
|
2015-12-31 16:12:22 +00:00
|
|
|
}
|
2020-12-12 22:48:03 +00:00
|
|
|
|
|
|
|
|
internal static int BufferedOsRead(int fd, 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);
|
|
|
|
|
|
|
|
|
|
DateTime end = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
if(sense < 0)
|
|
|
|
|
{
|
|
|
|
|
duration = (end - start).TotalMilliseconds;
|
|
|
|
|
|
|
|
|
|
return Marshal.GetLastWin32Error();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sense = DetectOS.Is64Bit ? Extern.read64(fd, buffer, length) : Extern.read(fd, buffer, (int)length);
|
|
|
|
|
|
|
|
|
|
end = DateTime.Now;
|
|
|
|
|
duration = (end - start).TotalMilliseconds;
|
|
|
|
|
|
2021-12-11 19:46:04 +00:00
|
|
|
int errno = Marshal.GetLastWin32Error();
|
|
|
|
|
|
|
|
|
|
if(sense == length)
|
|
|
|
|
errno = 0;
|
|
|
|
|
else if(errno == 0)
|
|
|
|
|
errno = -22;
|
|
|
|
|
|
|
|
|
|
return errno;
|
2020-12-12 22:48:03 +00:00
|
|
|
}
|
2015-10-12 06:25:49 +01:00
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
}
|