Files
Aaru/DiscImageChef.Core/Devices/Dumping/Dump.cs

204 lines
9.5 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using DiscImageChef.CommonTypes.Enums;
using DiscImageChef.CommonTypes.Interfaces;
using DiscImageChef.CommonTypes.Metadata;
using DiscImageChef.Core.Logging;
using DiscImageChef.Database;
using DiscImageChef.Devices;
using Schemas;
2019-04-19 17:23:54 +01:00
namespace DiscImageChef.Core.Devices.Dumping
{
public partial class Dump
{
readonly bool _debug;
2019-12-25 18:07:05 +00:00
readonly Device _dev;
readonly string _devicePath;
readonly bool _doResume;
readonly DumpLog _dumpLog;
readonly bool _dumpRaw;
readonly Encoding _encoding;
readonly bool _force;
readonly Dictionary<string, string> _formatOptions;
readonly bool _nometadata;
readonly bool _notrim;
readonly string _outputPath;
readonly IWritableImage _outputPlugin;
readonly string _outputPrefix;
readonly bool _persistent;
readonly CICMMetadataType _preSidecar;
readonly ushort _retryPasses;
readonly bool _stopOnError;
bool _aborted;
DicContext _ctx; // Master database context
Database.Models.Device _dbDev; // Device database entry
2019-12-25 18:07:05 +00:00
bool _dumpFirstTrackPregap;
bool _fixOffset;
uint _maximumReadable; // Maximum number of sectors drive can read at once
2019-12-25 18:07:05 +00:00
Resume _resume;
Sidecar _sidecarClass;
uint _skip;
2019-12-25 18:07:05 +00:00
/// <summary>Initializes dumpers</summary>
2019-04-20 16:24:17 +01:00
/// <param name="doResume">Should resume?</param>
/// <param name="dev">Device</param>
/// <param name="devicePath">Path to the device</param>
/// <param name="outputPrefix">Prefix for output log files</param>
/// <param name="outputPlugin">Plugin for output file</param>
/// <param name="retryPasses">How many times to retry</param>
/// <param name="force">Force to continue dump whenever possible</param>
/// <param name="dumpRaw">Dump long sectors</param>
/// <param name="persistent">Store whatever data the drive returned on error</param>
/// <param name="stopOnError">Stop dump on first error</param>
/// <param name="resume">Information for dump resuming</param>
/// <param name="dumpLog">Dump logger</param>
/// <param name="encoding">Encoding to use when analyzing dump</param>
/// <param name="outputPath">Path to output file</param>
/// <param name="formatOptions">Formats to pass to output file plugin</param>
2019-04-20 16:24:17 +01:00
/// <param name="notrim">Do not trim errors from skipped sectors</param>
/// <param name="dumpFirstTrackPregap">Try to read and dump as much first track pregap as possible</param>
2019-04-20 16:24:17 +01:00
/// <param name="preSidecar">Sidecar to store in dumped image</param>
/// <param name="skip">How many sectors to skip reading on error</param>
/// <param name="nometadata">Create metadata sidecar after dump?</param>
2019-12-25 18:07:05 +00:00
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<string, string> formatOptions,
CICMMetadataType preSidecar, uint skip, bool nometadata, bool notrim, bool dumpFirstTrackPregap,
bool fixOffset, bool debug)
{
2019-12-25 18:07:05 +00:00
_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;
_nometadata = nometadata;
_notrim = notrim;
_dumpFirstTrackPregap = dumpFirstTrackPregap;
_aborted = false;
_fixOffset = fixOffset;
_debug = debug;
_maximumReadable = 64;
}
2019-12-25 18:07:05 +00:00
/// <summary>Starts dumping with the stablished fields and autodetecting the device type</summary>
public void Start()
{
// Open master database
_ctx = DicContext.Create(Settings.Settings.MasterDbPath);
// Search for device in master database
_dbDev = _ctx.Devices.FirstOrDefault(d => d.Manufacturer == _dev.Manufacturer && d.Model == _dev.Model &&
d.Revision == _dev.Revision);
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;
}
2019-12-25 18:07:05 +00:00
if(_dev.IsUsb &&
_dev.UsbVendorId == 0x054C &&
(_dev.UsbProductId == 0x01C8 || _dev.UsbProductId == 0x01C9 || _dev.UsbProductId == 0x02D2))
PlayStationPortable();
else
2019-12-25 18:07:05 +00:00
switch(_dev.Type)
{
case DeviceType.ATA:
Ata();
2019-12-25 18:07:05 +00:00
break;
case DeviceType.MMC:
case DeviceType.SecureDigital:
SecureDigital();
2019-12-25 18:07:05 +00:00
break;
case DeviceType.NVMe:
NVMe();
2019-12-25 18:07:05 +00:00
break;
case DeviceType.ATAPI:
case DeviceType.SCSI:
Scsi();
2019-12-25 18:07:05 +00:00
break;
default:
2019-12-25 18:07:05 +00:00
_dumpLog.WriteLine("Unknown device type.");
_dumpLog.Close();
2019-04-20 14:02:25 +01:00
StoppingErrorMessage?.Invoke("Unknown device type.");
2019-12-25 18:07:05 +00:00
2019-04-20 14:02:25 +01:00
return;
}
2019-12-25 18:07:05 +00:00
_dumpLog.Close();
2019-12-25 18:07:05 +00:00
if(_resume == null ||
!_doResume)
return;
2019-12-25 18:07:05 +00:00
_resume.LastWriteDate = DateTime.UtcNow;
_resume.BadBlocks.Sort();
2019-12-25 18:07:05 +00:00
if(File.Exists(_outputPrefix + ".resume.xml"))
File.Delete(_outputPrefix + ".resume.xml");
2019-12-25 18:07:05 +00:00
var fs = new FileStream(_outputPrefix + ".resume.xml", FileMode.Create, FileAccess.ReadWrite);
var xs = new XmlSerializer(_resume.GetType());
xs.Serialize(fs, _resume);
fs.Close();
}
2019-04-20 16:40:12 +01:00
public void Abort()
{
2019-12-25 18:07:05 +00:00
_aborted = true;
_sidecarClass?.Abort();
2019-04-20 16:40:12 +01:00
}
2019-12-25 18:07:05 +00:00
/// <summary>Event raised when the progress bar is not longer needed</summary>
2019-04-20 16:24:17 +01:00
public event EndProgressHandler EndProgress;
2019-12-25 18:07:05 +00:00
/// <summary>Event raised when a progress bar is needed</summary>
2019-04-20 16:24:17 +01:00
public event InitProgressHandler InitProgress;
2019-12-25 18:07:05 +00:00
/// <summary>Event raised to report status updates</summary>
2019-04-20 16:24:17 +01:00
public event UpdateStatusHandler UpdateStatus;
2019-12-25 18:07:05 +00:00
/// <summary>Event raised to report a non-fatal error</summary>
2019-04-20 16:24:17 +01:00
public event ErrorMessageHandler ErrorMessage;
2019-12-25 18:07:05 +00:00
/// <summary>Event raised to report a fatal error that stops the dumping operation and should call user's attention</summary>
2019-04-20 16:24:17 +01:00
public event ErrorMessageHandler StoppingErrorMessage;
2019-12-25 18:07:05 +00:00
/// <summary>Event raised to update the values of a determinate progress bar</summary>
public event UpdateProgressHandler UpdateProgress;
2019-12-25 18:07:05 +00:00
/// <summary>Event raised to update the status of an undeterminate progress bar</summary>
2019-04-20 16:24:17 +01:00
public event PulseProgressHandler PulseProgress;
2019-12-25 18:07:05 +00:00
/// <summary>Event raised when the progress bar is not longer needed</summary>
2019-04-20 18:11:02 +01:00
public event EndProgressHandler2 EndProgress2;
2019-12-25 18:07:05 +00:00
/// <summary>Event raised when a progress bar is needed</summary>
2019-04-20 18:11:02 +01:00
public event InitProgressHandler2 InitProgress2;
2019-12-25 18:07:05 +00:00
/// <summary>Event raised to update the values of a determinate progress bar</summary>
2019-04-20 18:11:02 +01:00
public event UpdateProgressHandler2 UpdateProgress2;
2019-04-19 17:23:54 +01:00
}
}