// /*************************************************************************** // Aaru Data Preservation Suite // ---------------------------------------------------------------------------- // // Filename : Dump.cs // Author(s) : Natalia Portillo // // Component : Core algorithms. // // --[ Description ] ---------------------------------------------------------- // // Dumps media from 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 . // // ---------------------------------------------------------------------------- // Copyright © 2011-2021 Natalia Portillo // Copyright © 2020-2021 Rebecca Wallander // ****************************************************************************/ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Xml.Serialization; using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using Aaru.CommonTypes.Metadata; using Aaru.Core.Logging; using Aaru.Database; using Aaru.Devices; using Schemas; namespace Aaru.Core.Devices.Dumping { /// Subchannel requested to dump public enum DumpSubchannel { /// Any available subchannel, in order: raw P to W, PQ, none Any, /// Raw P to W Rw, /// Raw P to W or PQ if not possible RwOrPq, /// PQ Pq, /// None None } public partial class Dump { readonly bool _debug; readonly Device _dev; readonly string _devicePath; readonly bool _doResume; readonly DumpLog _dumpLog; readonly bool _dumpRaw; readonly Encoding _encoding; readonly ErrorLog _errorLog; readonly bool _fixSubchannel; readonly bool _fixSubchannelCrc; readonly bool _fixSubchannelPosition; readonly bool _force; readonly Dictionary _formatOptions; readonly bool _generateSubchannels; readonly bool _metadata; readonly string _outputPath; readonly IWritableImage _outputPlugin; readonly string _outputPrefix; readonly bool _persistent; readonly CICMMetadataType _preSidecar; readonly bool _private; readonly ushort _retryPasses; readonly bool _retrySubchannel; readonly bool _stopOnError; readonly bool _storeEncrypted; readonly DumpSubchannel _subchannel; readonly bool _titleKeys; readonly bool _trim; readonly bool _useBufferedReads; bool _aborted; AaruContext _ctx; // Main database context Database.Models.Device _dbDev; // Device database entry bool _dumpFirstTrackPregap; bool _fixOffset; uint _maximumReadable; // Maximum number of sectors drive can read at once Resume _resume; Sidecar _sidecarClass; uint _skip; bool _skipCdireadyHole; int _speed; int _speedMultiplier; bool _supportsPlextorD8; /// Initializes dumpers /// Should resume? /// Device /// Path to the device /// Prefix for output log files /// Plugin for output file /// How many times to retry /// Force to continue dump whenever possible /// Dump long sectors /// Store whatever data the drive returned on error /// Stop dump on first error /// Information for dump resuming /// Dump logger /// Encoding to use when analyzing dump /// Path to output file /// Formats to pass to output file plugin /// Trim errors from skipped sectors /// Try to read and dump as much first track pregap as possible /// Sidecar to store in dumped image /// How many sectors to skip reading on error /// Create metadata sidecar after dump? /// Fix audio offset /// Debug mode /// Desired subchannel to save to image /// Desired drive speed /// Disable saving paths or serial numbers in images and logs /// Fix subchannel position (save where it says it belongs) /// Retry reading incorrect or missing subchannels /// Try to fix subchannel errors (but not Q CRC) /// Try to fix subchannel Q CRC errors /// Skip gap between CD-i Ready hidden track and track 1 audio /// Error log /// Generate missing subchannels /// Number of maximum blocks to be read at once (can be overriden by database) /// /// If MMC/SD does not support CMD23, use OS buffered reads instead of multiple single block /// commands /// /// Store encrypted data as is /// Dump DVD CSS title keys public Dump(bool doResume, Device dev, string devicePath, IWritableImage outputPlugin, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, Resume resume, DumpLog dumpLog, Encoding encoding, string outputPrefix, string outputPath, Dictionary formatOptions, CICMMetadataType preSidecar, uint skip, bool metadata, bool trim, bool dumpFirstTrackPregap, bool fixOffset, bool debug, DumpSubchannel subchannel, int speed, bool @private, bool fixSubchannelPosition, bool retrySubchannel, bool fixSubchannel, bool fixSubchannelCrc, bool skipCdireadyHole, ErrorLog errorLog, bool generateSubchannels, uint maximumReadable, bool useBufferedReads, bool storeEncrypted, bool titleKeys) { _doResume = doResume; _dev = dev; _devicePath = devicePath; _outputPlugin = outputPlugin; _retryPasses = retryPasses; _force = force; _dumpRaw = dumpRaw; _persistent = persistent; _stopOnError = stopOnError; _resume = resume; _dumpLog = dumpLog; _encoding = encoding; _outputPrefix = outputPrefix; _outputPath = outputPath; _formatOptions = formatOptions; _preSidecar = preSidecar; _skip = skip; _metadata = metadata; _trim = trim; _dumpFirstTrackPregap = dumpFirstTrackPregap; _aborted = false; _fixOffset = fixOffset; _debug = debug; _maximumReadable = maximumReadable; _subchannel = subchannel; _speedMultiplier = -1; _speed = speed; _private = @private; _fixSubchannelPosition = fixSubchannelPosition; _retrySubchannel = retrySubchannel; _fixSubchannel = fixSubchannel; _fixSubchannelCrc = fixSubchannelCrc; _skipCdireadyHole = skipCdireadyHole; _errorLog = errorLog; _generateSubchannels = generateSubchannels; _useBufferedReads = useBufferedReads; _storeEncrypted = storeEncrypted; _titleKeys = titleKeys; } /// Starts dumping with the established fields and autodetecting the device type public void Start() { // Open main database _ctx = AaruContext.Create(Settings.Settings.MainDbPath); // Search for device in main database _dbDev = _ctx.Devices.FirstOrDefault(d => d.Manufacturer == _dev.Manufacturer && d.Model == _dev.Model && d.Revision == _dev.FirmwareRevision); if(_dbDev is null) { _dumpLog.WriteLine("Device not in database, please create a device report and attach it to a Github issue."); UpdateStatus?. Invoke("Device not in database, please create a device report and attach it to a Github issue."); } else { _dumpLog.WriteLine($"Device in database since {_dbDev.LastSynchronized}."); UpdateStatus?.Invoke($"Device in database since {_dbDev.LastSynchronized}."); if(_dbDev.OptimalMultipleSectorsRead > 0) _maximumReadable = (uint)_dbDev.OptimalMultipleSectorsRead; } if(_dev.IsUsb && _dev.UsbVendorId == 0x054C && (_dev.UsbProductId == 0x01C8 || _dev.UsbProductId == 0x01C9 || _dev.UsbProductId == 0x02D2)) PlayStationPortable(); else switch(_dev.Type) { case DeviceType.ATA: Ata(); break; case DeviceType.MMC: case DeviceType.SecureDigital: SecureDigital(); break; case DeviceType.NVMe: NVMe(); break; case DeviceType.ATAPI: case DeviceType.SCSI: Scsi(); break; default: _dumpLog.WriteLine("Unknown device type."); _dumpLog.Close(); StoppingErrorMessage?.Invoke("Unknown device type."); return; } _errorLog.Close(); _dumpLog.Close(); if(_resume == null || !_doResume) return; _resume.LastWriteDate = DateTime.UtcNow; _resume.BadBlocks.Sort(); if(File.Exists(_outputPrefix + ".resume.xml")) File.Delete(_outputPrefix + ".resume.xml"); var fs = new FileStream(_outputPrefix + ".resume.xml", FileMode.Create, FileAccess.ReadWrite); var xs = new XmlSerializer(_resume.GetType()); xs.Serialize(fs, _resume); fs.Close(); } /// Aborts the dump in progress public void Abort() { _aborted = true; _sidecarClass?.Abort(); } /// Event raised when the progress bar is not longer needed public event EndProgressHandler EndProgress; /// Event raised when a progress bar is needed public event InitProgressHandler InitProgress; /// Event raised to report status updates public event UpdateStatusHandler UpdateStatus; /// Event raised to report a non-fatal error public event ErrorMessageHandler ErrorMessage; /// Event raised to report a fatal error that stops the dumping operation and should call user's attention public event ErrorMessageHandler StoppingErrorMessage; /// Event raised to update the values of a determinate progress bar public event UpdateProgressHandler UpdateProgress; /// Event raised to update the status of an undeterminate progress bar public event PulseProgressHandler PulseProgress; /// Event raised when the progress bar is not longer needed public event EndProgressHandler2 EndProgress2; /// Event raised when a progress bar is needed public event InitProgressHandler2 InitProgress2; /// Event raised to update the values of a determinate progress bar public event UpdateProgressHandler2 UpdateProgress2; } }