Files
Aaru-aaru-dps/Aaru.Core/Devices/Reader.cs
Rebecca Wallander 0dfef8ccb3 Dump NGCW
2026-04-03 08:39:09 +02:00

226 lines
7.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Reader.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Core algorithms.
//
// --[ Description ] ----------------------------------------------------------
//
// Contains common code for reading devices.
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2026 Natalia Portillo
// ****************************************************************************/
using System;
using System.Diagnostics.CodeAnalysis;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Structs.Devices.ATA;
using Aaru.Core.Logging;
using Aaru.Devices;
namespace Aaru.Core.Devices;
/// <summary>Reduces common code used for scanning and dumping</summary>
[SuppressMessage("ReSharper", "UnusedMethodReturnValue.Global")]
sealed partial class Reader
{
const string ATA_MODULE_NAME = "ATA Reader";
const string SCSI_MODULE_NAME = "SCSI Reader";
readonly Device _dev;
readonly ErrorLog _errorLog;
readonly uint _timeout;
internal Reader(Device dev, uint timeout, byte[] identification, ErrorLog errorLog, bool raw = false)
{
_dev = dev;
_timeout = timeout;
BlocksToRead = 64;
CanReadRaw = raw;
_errorLog = errorLog;
switch(dev.Type)
{
case DeviceType.ATA:
Identify.IdentifyDevice? ataIdNullable = Identify.Decode(identification);
if(ataIdNullable.HasValue) _ataId = ataIdNullable.Value;
break;
case DeviceType.NVMe:
throw new NotImplementedException(Localization.Core.NVMe_devices_not_yet_supported);
}
}
internal string ErrorMessage { get; private set; }
internal ulong Blocks { get; private set; }
internal uint BlocksToRead { get; private set; }
internal uint LogicalBlockSize { get; private set; }
internal uint PhysicalBlockSize { get; private set; }
internal uint LongBlockSize { get; private set; }
internal bool CanReadRaw { get; private set; }
/// <summary>When true with OmniDrive raw reads, use descramble=0 and software Nintendo descrambling (GameCube/Wii).</summary>
internal bool OmniDriveNintendoMode { get; set; }
/// <summary>
/// Disc-wide Nintendo XOR key (015) from LBA 0 CPR_MAI, set after the dump pipeline reads LBA 0. Used for
/// OmniDrive Nintendo reads at LBAs ≥ 16; null until derived.
/// </summary>
internal byte? NintendoDerivedDiscKey { get; set; }
internal bool CanSeek => _ataSeek || _seek6 || _seek10;
internal bool CanSeekLba => _ataSeekLba || _seek6 || _seek10;
internal ulong GetDeviceBlocks()
{
switch(_dev.Type)
{
case DeviceType.ATA:
return AtaGetBlocks();
case DeviceType.ATAPI:
case DeviceType.SCSI:
return ScsiGetBlocks();
default:
ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type);
return 0;
}
}
internal bool FindReadCommand()
{
switch(_dev.Type)
{
case DeviceType.ATA:
return AtaFindReadCommand();
case DeviceType.ATAPI:
case DeviceType.SCSI:
return ScsiFindReadCommand();
default:
ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type);
return true;
}
}
internal bool GetBlockSize()
{
switch(_dev.Type)
{
case DeviceType.ATA:
return AtaGetBlockSize();
case DeviceType.ATAPI:
case DeviceType.SCSI:
return ScsiGetBlockSize();
default:
ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type);
return true;
}
}
internal bool GetBlocksToRead(uint startWithBlocks = 64)
{
switch(_dev.Type)
{
case DeviceType.ATA:
return AtaGetBlocksToRead(startWithBlocks);
case DeviceType.ATAPI:
case DeviceType.SCSI:
return ScsiGetBlocksToRead(startWithBlocks);
default:
ErrorMessage = string.Format(Localization.Core.Unknown_device_type_0, _dev.Type);
return true;
}
}
internal bool ReadBlock(out byte[] buffer, ulong block, out double duration, out bool recoveredError,
out bool blankCheck) =>
ReadBlocks(out buffer, block, 1, out duration, out recoveredError, out blankCheck);
internal bool ReadBlocks(out byte[] buffer, ulong block, uint count, out double duration, out bool recoveredError,
out bool blankCheck, bool negative = false)
{
switch(_dev.Type)
{
case DeviceType.ATA:
blankCheck = false;
return AtaReadBlocks(out buffer, block, count, out duration, out recoveredError);
case DeviceType.ATAPI:
case DeviceType.SCSI:
return ScsiReadBlocks(out buffer, block, count, out duration, out recoveredError, out blankCheck,
negative);
default:
buffer = null;
duration = 0d;
recoveredError = false;
blankCheck = false;
return true;
}
}
internal bool ReadChs(out byte[] buffer, ushort cylinder, byte head, byte sector, out double duration,
out bool recoveredError)
{
switch(_dev.Type)
{
case DeviceType.ATA:
return AtaReadChs(out buffer, cylinder, head, sector, out duration, out recoveredError);
default:
buffer = null;
duration = 0d;
recoveredError = false;
return true;
}
}
internal bool Seek(ulong block, out double duration)
{
switch(_dev.Type)
{
case DeviceType.ATA:
return AtaSeek(block, out duration);
case DeviceType.ATAPI:
case DeviceType.SCSI:
return ScsiSeek(block, out duration);
default:
duration = 0d;
return true;
}
}
internal bool SeekChs(ushort cylinder, byte head, byte sector, out double duration)
{
switch(_dev.Type)
{
case DeviceType.ATA:
return AtaSeekChs(cylinder, head, sector, out duration);
default:
duration = 0;
return true;
}
}
}