🐛No retry passes means do not retry errors, act so.

This commit is contained in:
2018-04-09 20:21:42 +01:00
parent 97073e34f0
commit 47e78ba0d4
5 changed files with 127 additions and 140 deletions

View File

@@ -74,16 +74,15 @@ namespace DiscImageChef.Core.Devices.Dumping
/// <param name="outputPath">Path to output file</param> /// <param name="outputPath">Path to output file</param>
/// <param name="formatOptions">Formats to pass to output file plugin</param> /// <param name="formatOptions">Formats to pass to output file plugin</param>
/// <exception cref="InvalidOperationException">If the resume file is invalid</exception> /// <exception cref="InvalidOperationException">If the resume file is invalid</exception>
public static void Dump(Device dev, string devicePath, IWritableImage outputPlugin, ushort retryPasses, public static void Dump(Device dev, string devicePath,
bool force, bool dumpRaw, bool persistent, bool stopOnError, IWritableImage outputPlugin, ushort retryPasses,
ref Resume resume, bool force, bool dumpRaw,
ref bool persistent, bool stopOnError, ref Resume resume,
DumpLog dumpLog, Encoding encoding, string outputPrefix, ref DumpLog dumpLog, Encoding encoding,
string outputPath, string outputPrefix, string outputPath,
Dictionary<string, string> Dictionary<string, string> formatOptions, CICMMetadataType preSidecar,
formatOptions, CICMMetadataType preSidecar, uint skip, uint skip,
bool bool nometadata)
nometadata)
{ {
bool aborted; bool aborted;
@@ -113,7 +112,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
Identify.IdentifyDevice ataId = ataIdNullable.Value; Identify.IdentifyDevice ataId = ataIdNullable.Value;
byte[] ataIdentify = cmdBuf; byte[] ataIdentify = cmdBuf;
cmdBuf = new byte[0]; cmdBuf = new byte[0];
DateTime start; DateTime start;
DateTime end; DateTime end;
@@ -273,7 +272,7 @@ namespace DiscImageChef.Core.Devices.Dumping
else else
{ {
if(i + skip > blocks) skip = (uint)(blocks - i); if(i + skip > blocks) skip = (uint)(blocks - i);
for(ulong b = i; b < i + skip; b++) resume.BadBlocks.Add(b); for(ulong b = i; b < i + skip; b++) resume.BadBlocks.Add(b);
mhddLog.Write(i, duration < 500 ? 65535 : duration); mhddLog.Write(i, duration < 500 ? 65535 : duration);
@@ -289,24 +288,23 @@ namespace DiscImageChef.Core.Devices.Dumping
double newSpeed = double newSpeed =
(double)blockSize * blocksToRead / 1048576 / (duration / 1000); (double)blockSize * blocksToRead / 1048576 / (duration / 1000);
if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed; if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed;
resume.NextBlock = i + blocksToRead; resume.NextBlock = i + blocksToRead;
} }
end = DateTime.Now; end = DateTime.Now;
DicConsole.WriteLine(); DicConsole.WriteLine();
mhddLog.Close(); mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
blockSize * blockSize * (double)(blocks + 1) / 1024 /
(double)(blocks + 1) / 1024 / (totalDuration / 1000), devicePath); (totalDuration / 1000), devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.", dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
(end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); (double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); (double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Error handling #region Error handling
if(resume.BadBlocks.Count > 0 && !aborted) if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
{ {
int pass = 0; int pass = 0;
bool forward = true; bool forward = true;
@@ -337,8 +335,7 @@ namespace DiscImageChef.Core.Devices.Dumping
outputPlugin.WriteSector(cmdBuf, badSector); outputPlugin.WriteSector(cmdBuf, badSector);
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
} }
else if(persistent) else if(persistent) outputPlugin.WriteSector(cmdBuf, badSector);
outputPlugin.WriteSector(cmdBuf, badSector);
} }
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0) if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
@@ -362,8 +359,8 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog = new IbgLog(outputPrefix + ".ibg", ATA_PROFILE); ibgLog = new IbgLog(outputPrefix + ".ibg", ATA_PROFILE);
ulong currentBlock = 0; ulong currentBlock = 0;
blocks = (ulong)(cylinders * heads * sectors); blocks = (ulong)(cylinders * heads * sectors);
start = DateTime.UtcNow; start = DateTime.UtcNow;
for(ushort cy = 0; cy < cylinders; cy++) for(ushort cy = 0; cy < cylinders; cy++)
{ {
for(byte hd = 0; hd < heads; hd++) for(byte hd = 0; hd < heads; hd++)
@@ -396,7 +393,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSector(cmdBuf, outputPlugin.WriteSector(cmdBuf,
(ulong)((cy * heads + hd) * sectors + (sc - 1))); (ulong)((cy * heads + hd) * sectors + (sc - 1)));
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
extents.Add(currentBlock); extents.Add(currentBlock);
dumpLog.WriteLine("Error reading cylinder {0} head {1} sector {2}.", cy, hd, dumpLog.WriteLine("Error reading cylinder {0} head {1} sector {2}.", cy, hd,
sc); sc);
@@ -410,7 +407,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSector(new byte[blockSize], outputPlugin.WriteSector(new byte[blockSize],
(ulong)((cy * heads + hd) * sectors + (sc - 1))); (ulong)((cy * heads + hd) * sectors + (sc - 1)));
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
} }
double newSpeed = double newSpeed =
@@ -426,14 +423,13 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
mhddLog.Close(); mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
blockSize * blockSize * (double)(blocks + 1) / 1024 /
(double)(blocks + 1) / 1024 / (totalDuration / 1000), devicePath); (totalDuration / 1000), devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.", dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
(end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); (double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (double)blockSize * (double)(blocks + 1) / 1024 /
(imageWriteDuration / 1000)); (imageWriteDuration / 1000));
} }
@@ -478,8 +474,8 @@ namespace DiscImageChef.Core.Devices.Dumping
if(ret) if(ret)
sidecar.BlockMedia[0].USB = new USBType sidecar.BlockMedia[0].USB = new USBType
{ {
ProductID = dev.UsbProductId, ProductID = dev.UsbProductId,
VendorID = dev.UsbVendorId, VendorID = dev.UsbVendorId,
Descriptors = new DumpType Descriptors = new DumpType
{ {
Image = outputPath, Image = outputPath,
@@ -532,7 +528,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer; sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer;
sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product; sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product;
sidecar.BlockMedia[0].PCMCIA.Compliance = sidecar.BlockMedia[0].PCMCIA.Compliance =
$"{vers.MajorVersion}.{vers.MinorVersion}"; $"{vers.MajorVersion}.{vers.MinorVersion}";
sidecar.BlockMedia[0].PCMCIA.AdditionalInformation = sidecar.BlockMedia[0].PCMCIA.AdditionalInformation =
vers.AdditionalInformation; vers.AdditionalInformation;
@@ -557,7 +553,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DateTime chkEnd = DateTime.UtcNow; DateTime chkEnd = DateTime.UtcNow;
totalChkDuration = (chkEnd - chkStart).TotalMilliseconds; totalChkDuration = (chkEnd - chkStart).TotalMilliseconds;
dumpLog.WriteLine("Sidecar created in {0} seconds.", (chkEnd - chkStart).TotalSeconds); dumpLog.WriteLine("Sidecar created in {0} seconds.", (chkEnd - chkStart).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); (double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000));
@@ -630,10 +626,8 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
if(dev.IsCompactFlash) Statistics.AddMedia(MediaType.CompactFlash, true); if(dev.IsCompactFlash) Statistics.AddMedia(MediaType.CompactFlash, true);
else if(dev.IsPcmcia) else if(dev.IsPcmcia) Statistics.AddMedia(MediaType.PCCardTypeI, true);
Statistics.AddMedia(MediaType.PCCardTypeI, true); else Statistics.AddMedia(MediaType.GENERIC_HDD, true);
else
Statistics.AddMedia(MediaType.GENERIC_HDD, true);
} }
else DicConsole.ErrorWriteLine("Unable to communicate with ATA device."); else DicConsole.ErrorWriteLine("Unable to communicate with ATA device.");
} }

View File

@@ -897,7 +897,7 @@ namespace DiscImageChef.Core.Devices.Dumping
#region Compact Disc Error handling #region Compact Disc Error handling
// TODO: Pass 0 should be called differently, splitting, or something like that, because we are just // TODO: Pass 0 should be called differently, splitting, or something like that, because we are just
// separating skipped good sectors from really bad sectors and it's getting too chatty on log there... // separating skipped good sectors from really bad sectors and it's getting too chatty on log there...
if(resume.BadBlocks.Count > 0 && !aborted) if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
{ {
int pass = 0; int pass = 0;
bool forward = true; bool forward = true;

View File

@@ -418,7 +418,7 @@ namespace DiscImageChef.Core.Devices.Dumping
(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); (double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Error handling #region Error handling
if(resume.BadBlocks.Count > 0 && !aborted) if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
{ {
int pass = 0; int pass = 0;
bool forward = true; bool forward = true;

View File

@@ -72,14 +72,15 @@ namespace DiscImageChef.Core.Devices.Dumping
/// <param name="outputPath">Path to output file</param> /// <param name="outputPath">Path to output file</param>
/// <param name="formatOptions">Formats to pass to output file plugin</param> /// <param name="formatOptions">Formats to pass to output file plugin</param>
/// <exception cref="ArgumentException">If you asked to dump long sectors from a SCSI Streaming device</exception> /// <exception cref="ArgumentException">If you asked to dump long sectors from a SCSI Streaming device</exception>
public static void Dump(Device dev, string devicePath, IWritableImage outputPlugin, ushort retryPasses, public static void Dump(Device dev, string devicePath,
bool force, bool dumpRaw, bool persistent, bool stopOnError, IWritableImage outputPlugin, ushort retryPasses,
ref Resume resume, bool force, bool dumpRaw,
ref bool persistent, bool stopOnError, ref Resume resume,
DumpLog dumpLog, Encoding encoding, string outputPrefix, ref DumpLog dumpLog, Encoding encoding,
string outputPath, string outputPrefix, string outputPath,
Dictionary<string, string> Dictionary<string, string> formatOptions, CICMMetadataType preSidecar,
formatOptions, CICMMetadataType preSidecar, uint skip, bool nometadata) uint skip,
bool nometadata)
{ {
bool aborted; bool aborted;
@@ -121,12 +122,11 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!sense) if(!sense)
{ {
ExtendedCSD ecsdDecoded = Decoders.MMC.Decoders.DecodeExtendedCSD(ecsd); ExtendedCSD ecsdDecoded = Decoders.MMC.Decoders.DecodeExtendedCSD(ecsd);
blocksToRead = ecsdDecoded.OptimalReadSize; blocksToRead = ecsdDecoded.OptimalReadSize;
blocks = ecsdDecoded.SectorCount; blocks = ecsdDecoded.SectorCount;
blockSize = (uint)(ecsdDecoded.SectorSize == 1 ? 4096 : 512); blockSize = (uint)(ecsdDecoded.SectorSize == 1 ? 4096 : 512);
if(ecsdDecoded.NativeSectorSize == 0) physicalBlockSize = 512; if(ecsdDecoded.NativeSectorSize == 0) physicalBlockSize = 512;
else if(ecsdDecoded.NativeSectorSize == 1) else if(ecsdDecoded.NativeSectorSize == 1) physicalBlockSize = 4096;
physicalBlockSize = 4096;
// Supposing it's high-capacity MMC if it has Extended CSD... // Supposing it's high-capacity MMC if it has Extended CSD...
byteAddressed = false; byteAddressed = false;
mediaTags.Add(MediaTagType.MMC_ExtendedCSD, null); mediaTags.Add(MediaTagType.MMC_ExtendedCSD, null);
@@ -140,9 +140,8 @@ namespace DiscImageChef.Core.Devices.Dumping
if(blocks == 0) if(blocks == 0)
{ {
CSD csdDecoded = Decoders.MMC.Decoders.DecodeCSD(csd); CSD csdDecoded = Decoders.MMC.Decoders.DecodeCSD(csd);
blocks = blocks = (ulong)((csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2));
(ulong)((csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2)); blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength);
blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength);
} }
mediaTags.Add(MediaTagType.MMC_CSD, null); mediaTags.Add(MediaTagType.MMC_CSD, null);
@@ -150,7 +149,7 @@ namespace DiscImageChef.Core.Devices.Dumping
else csd = null; else csd = null;
dumpLog.WriteLine("Reading OCR"); dumpLog.WriteLine("Reading OCR");
sense = dev.ReadOcr(out ocr, out _, TIMEOUT, out duration); sense = dev.ReadOcr(out ocr, out _, TIMEOUT, out duration);
if(sense) ocr = null; if(sense) ocr = null;
else mediaTags.Add(MediaTagType.MMC_OCR, null); else mediaTags.Add(MediaTagType.MMC_OCR, null);
@@ -163,10 +162,9 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!sense) if(!sense)
{ {
Decoders.SecureDigital.CSD csdDecoded = Decoders.SecureDigital.Decoders.DecodeCSD(csd); Decoders.SecureDigital.CSD csdDecoded = Decoders.SecureDigital.Decoders.DecodeCSD(csd);
blocks = (ulong)(csdDecoded.Structure == 0 blocks = (ulong)(csdDecoded.Structure == 0
? (csdDecoded.Size + 1) * ? (csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2)
Math.Pow(2, csdDecoded.SizeMultiplier + 2) : (csdDecoded.Size + 1) * 1024);
: (csdDecoded.Size + 1) * 1024);
blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength); blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength);
// Structure >=1 for SDHC/SDXC, so that's block addressed // Structure >=1 for SDHC/SDXC, so that's block addressed
byteAddressed = csdDecoded.Structure == 0; byteAddressed = csdDecoded.Structure == 0;
@@ -175,12 +173,12 @@ namespace DiscImageChef.Core.Devices.Dumping
else csd = null; else csd = null;
dumpLog.WriteLine("Reading OCR"); dumpLog.WriteLine("Reading OCR");
sense = dev.ReadSdocr(out ocr, out _, TIMEOUT, out duration); sense = dev.ReadSdocr(out ocr, out _, TIMEOUT, out duration);
if(sense) ocr = null; if(sense) ocr = null;
else mediaTags.Add(MediaTagType.SD_OCR, null); else mediaTags.Add(MediaTagType.SD_OCR, null);
dumpLog.WriteLine("Reading SCR"); dumpLog.WriteLine("Reading SCR");
sense = dev.ReadScr(out scr, out _, TIMEOUT, out duration); sense = dev.ReadScr(out scr, out _, TIMEOUT, out duration);
if(sense) scr = null; if(sense) scr = null;
else mediaTags.Add(MediaTagType.SD_SCR, null); else mediaTags.Add(MediaTagType.SD_SCR, null);
@@ -189,16 +187,16 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
dumpLog.WriteLine("Reading CID"); dumpLog.WriteLine("Reading CID");
sense = dev.ReadCid(out byte[] cid, out _, TIMEOUT, out duration); sense = dev.ReadCid(out byte[] cid, out _, TIMEOUT, out duration);
if(sense) cid = null; if(sense) cid = null;
else mediaTags.Add(dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID : MediaTagType.MMC_CID, null); else mediaTags.Add(dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID : MediaTagType.MMC_CID, null);
DateTime start; DateTime start;
DateTime end; DateTime end;
double totalDuration = 0; double totalDuration = 0;
double currentSpeed = 0; double currentSpeed = 0;
double maxSpeed = double.MinValue; double maxSpeed = double.MinValue;
double minSpeed = double.MaxValue; double minSpeed = double.MaxValue;
aborted = false; aborted = false;
System.Console.CancelKeyPress += (sender, e) => e.Cancel = aborted = true; System.Console.CancelKeyPress += (sender, e) => e.Cancel = aborted = true;
@@ -264,11 +262,9 @@ namespace DiscImageChef.Core.Devices.Dumping
MhddLog mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead); MhddLog mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
IbgLog ibgLog = new IbgLog(outputPrefix + ".ibg", SD_PROFILE); IbgLog ibgLog = new IbgLog(outputPrefix + ".ibg", SD_PROFILE);
ret = outputPlugin.Create(outputPath, ret = outputPlugin.Create(outputPath,
dev.Type == DeviceType.SecureDigital dev.Type == DeviceType.SecureDigital ? MediaType.SecureDigital : MediaType.MMC,
? MediaType.SecureDigital formatOptions, blocks, blockSize);
: MediaType.MMC,
formatOptions, blocks, blockSize);
// Cannot create image // Cannot create image
if(!ret) if(!ret)
@@ -282,7 +278,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock); if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
start = DateTime.UtcNow; start = DateTime.UtcNow;
double imageWriteDuration = 0; double imageWriteDuration = 0;
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead) for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
@@ -318,7 +314,7 @@ namespace DiscImageChef.Core.Devices.Dumping
else else
{ {
if(i + skip > blocks) skip = (uint)(blocks - i); if(i + skip > blocks) skip = (uint)(blocks - i);
for(ulong b = i; b < i + skip; b++) resume.BadBlocks.Add(b); for(ulong b = i; b < i + skip; b++) resume.BadBlocks.Add(b);
mhddLog.Write(i, duration < 500 ? 65535 : duration); mhddLog.Write(i, duration < 500 ? 65535 : duration);
@@ -334,24 +330,23 @@ namespace DiscImageChef.Core.Devices.Dumping
double newSpeed = double newSpeed =
(double)blockSize * blocksToRead / 1048576 / (duration / 1000); (double)blockSize * blocksToRead / 1048576 / (duration / 1000);
if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed; if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed;
resume.NextBlock = i + blocksToRead; resume.NextBlock = i + blocksToRead;
} }
end = DateTime.Now; end = DateTime.Now;
DicConsole.WriteLine(); DicConsole.WriteLine();
mhddLog.Close(); mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
blockSize * (double)(blocks + 1) / blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000),
1024 / (totalDuration / 1000), devicePath); devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.", dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
(end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); (double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); (double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Error handling #region Error handling
if(resume.BadBlocks.Count > 0 && !aborted) if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
{ {
int pass = 0; int pass = 0;
bool forward = true; bool forward = true;
@@ -384,8 +379,7 @@ namespace DiscImageChef.Core.Devices.Dumping
outputPlugin.WriteSector(cmdBuf, badSector); outputPlugin.WriteSector(cmdBuf, badSector);
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
} }
else if(runningPersistent) else if(runningPersistent) outputPlugin.WriteSector(cmdBuf, badSector);
outputPlugin.WriteSector(cmdBuf, badSector);
} }
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0) if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
@@ -573,7 +567,7 @@ namespace DiscImageChef.Core.Devices.Dumping
end = DateTime.UtcNow; end = DateTime.UtcNow;
totalChkDuration = (end - chkStart).TotalMilliseconds; totalChkDuration = (end - chkStart).TotalMilliseconds;
dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); (double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000));
@@ -601,7 +595,7 @@ namespace DiscImageChef.Core.Devices.Dumping
sidecar.BlockMedia[0].Model = dev.Model; sidecar.BlockMedia[0].Model = dev.Model;
sidecar.BlockMedia[0].Serial = dev.Serial; sidecar.BlockMedia[0].Serial = dev.Serial;
sidecar.BlockMedia[0].Size = (long)(blocks * blockSize); sidecar.BlockMedia[0].Size = (long)(blocks * blockSize);
DicConsole.WriteLine("Writing metadata sidecar"); DicConsole.WriteLine("Writing metadata sidecar");
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create); FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);

View File

@@ -80,16 +80,17 @@ namespace DiscImageChef.Core.Devices.Dumping
/// If the provided resume does not correspond with the current in progress /// If the provided resume does not correspond with the current in progress
/// dump /// dump
/// </exception> /// </exception>
internal static void Dump(Device dev, string devicePath, internal static void Dump(Device dev, string devicePath,
IWritableImage outputPlugin, ushort retryPasses, IWritableImage outputPlugin, ushort retryPasses,
bool force, bool dumpRaw, bool force, bool dumpRaw,
bool persistent, bool stopOnError, bool persistent, bool stopOnError,
Dictionary<MediaTagType, byte[]> mediaTags, ref MediaType dskType, Dictionary<MediaTagType, byte[]> mediaTags, ref MediaType dskType,
ref Resume resume, ref Resume resume,
ref DumpLog dumpLog, ref DumpLog dumpLog, Encoding encoding,
Encoding encoding, string outputPrefix, string outputPath, string outputPrefix, string outputPath,
Dictionary<string, string> formatOptions, Dictionary<string, string> formatOptions, CICMMetadataType preSidecar,
CICMMetadataType preSidecar, uint skip, bool nometadata) uint skip,
bool nometadata)
{ {
bool sense; bool sense;
ulong blocks; ulong blocks;
@@ -97,11 +98,11 @@ namespace DiscImageChef.Core.Devices.Dumping
uint blocksToRead = 64; uint blocksToRead = 64;
DateTime start; DateTime start;
DateTime end; DateTime end;
double totalDuration = 0; double totalDuration = 0;
double currentSpeed = 0; double currentSpeed = 0;
double maxSpeed = double.MinValue; double maxSpeed = double.MinValue;
double minSpeed = double.MaxValue; double minSpeed = double.MaxValue;
bool aborted = false; bool aborted = false;
System.Console.CancelKeyPress += (sender, e) => e.Cancel = aborted = true; System.Console.CancelKeyPress += (sender, e) => e.Cancel = aborted = true;
if(mediaTags.ContainsKey(MediaTagType.DVD_PFI)) mediaTags.Remove(MediaTagType.DVD_PFI); if(mediaTags.ContainsKey(MediaTagType.DVD_PFI)) mediaTags.Remove(MediaTagType.DVD_PFI);
@@ -125,7 +126,7 @@ namespace DiscImageChef.Core.Devices.Dumping
return; return;
} }
byte[] tmpBuf = new byte[ssBuf.Length - 4]; byte[] tmpBuf = new byte[ssBuf.Length - 4];
Array.Copy(ssBuf, 4, tmpBuf, 0, ssBuf.Length - 4); Array.Copy(ssBuf, 4, tmpBuf, 0, ssBuf.Length - 4);
mediaTags.Add(MediaTagType.Xbox_SecuritySector, tmpBuf); mediaTags.Add(MediaTagType.Xbox_SecuritySector, tmpBuf);
@@ -162,7 +163,7 @@ namespace DiscImageChef.Core.Devices.Dumping
return; return;
} }
tmpBuf = new byte[readBuffer.Length - 4]; tmpBuf = new byte[readBuffer.Length - 4];
Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4); Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4);
mediaTags.Add(MediaTagType.DVD_PFI, tmpBuf); mediaTags.Add(MediaTagType.DVD_PFI, tmpBuf);
DicConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors", totalSize); DicConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors", totalSize);
@@ -178,7 +179,7 @@ namespace DiscImageChef.Core.Devices.Dumping
return; return;
} }
tmpBuf = new byte[readBuffer.Length - 4]; tmpBuf = new byte[readBuffer.Length - 4];
Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4); Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4);
mediaTags.Add(MediaTagType.DVD_DMI, tmpBuf); mediaTags.Add(MediaTagType.DVD_DMI, tmpBuf);
@@ -238,13 +239,13 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
DicConsole.DebugWriteLine("Dump-media command", "Unlocked total size: {0} sectors", totalSize); DicConsole.DebugWriteLine("Dump-media command", "Unlocked total size: {0} sectors", totalSize);
blocks = totalSize + 1; blocks = totalSize + 1;
middleZone = middleZone =
totalSize - (PFI.Decode(readBuffer).Value.Layer0EndPSN - totalSize - (PFI.Decode(readBuffer).Value.Layer0EndPSN -
PFI.Decode(readBuffer).Value.DataAreaStartPSN + PFI.Decode(readBuffer).Value.DataAreaStartPSN +
1) - gameSize + 1; 1) - gameSize + 1;
tmpBuf = new byte[readBuffer.Length - 4]; tmpBuf = new byte[readBuffer.Length - 4];
Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4); Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4);
mediaTags.Add(MediaTagType.Xbox_PFI, tmpBuf); mediaTags.Add(MediaTagType.Xbox_PFI, tmpBuf);
@@ -258,12 +259,12 @@ namespace DiscImageChef.Core.Devices.Dumping
return; return;
} }
tmpBuf = new byte[readBuffer.Length - 4]; tmpBuf = new byte[readBuffer.Length - 4];
Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4); Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4);
mediaTags.Add(MediaTagType.Xbox_DMI, tmpBuf); mediaTags.Add(MediaTagType.Xbox_DMI, tmpBuf);
totalSize = l0Video + l1Video + middleZone * 2 + gameSize; totalSize = l0Video + l1Video + middleZone * 2 + gameSize;
layerBreak = l0Video + middleZone + gameSize / 2; layerBreak = l0Video + middleZone + gameSize / 2;
DicConsole.WriteLine("Video layer 0 size: {0} sectors", l0Video); DicConsole.WriteLine("Video layer 0 size: {0} sectors", l0Video);
DicConsole.WriteLine("Video layer 1 size: {0} sectors", l1Video); DicConsole.WriteLine("Video layer 1 size: {0} sectors", l1Video);
@@ -336,7 +337,7 @@ namespace DiscImageChef.Core.Devices.Dumping
MhddLog mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, BLOCK_SIZE, blocksToRead); MhddLog mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, BLOCK_SIZE, blocksToRead);
IbgLog ibgLog = new IbgLog(outputPrefix + ".ibg", 0x0010); IbgLog ibgLog = new IbgLog(outputPrefix + ".ibg", 0x0010);
ret = outputPlugin.Create(outputPath, dskType, formatOptions, blocks, BLOCK_SIZE); ret = outputPlugin.Create(outputPath, dskType, formatOptions, blocks, BLOCK_SIZE);
// Cannot create image // Cannot create image
if(!ret) if(!ret)
@@ -348,7 +349,7 @@ namespace DiscImageChef.Core.Devices.Dumping
return; return;
} }
start = DateTime.UtcNow; start = DateTime.UtcNow;
double imageWriteDuration = 0; double imageWriteDuration = 0;
double cmdDuration = 0; double cmdDuration = 0;
@@ -373,7 +374,7 @@ namespace DiscImageChef.Core.Devices.Dumping
TrackType = TrackType.Data TrackType = TrackType.Data
} }
}); });
ulong currentSector = resume.NextBlock; ulong currentSector = resume.NextBlock;
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock); if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
@@ -397,13 +398,13 @@ namespace DiscImageChef.Core.Devices.Dumping
if(xboxSs.Value.Extents[e].StartPSN <= xboxSs.Value.Layer0EndPSN) if(xboxSs.Value.Extents[e].StartPSN <= xboxSs.Value.Layer0EndPSN)
extentStart = xboxSs.Value.Extents[e].StartPSN - 0x30000; extentStart = xboxSs.Value.Extents[e].StartPSN - 0x30000;
else else
extentStart = (xboxSs.Value.Layer0EndPSN + 1) * 2 - extentStart = (xboxSs.Value.Layer0EndPSN + 1) * 2 -
((xboxSs.Value.Extents[e].StartPSN ^ 0xFFFFFF) + 1) - 0x30000; ((xboxSs.Value.Extents[e].StartPSN ^ 0xFFFFFF) + 1) - 0x30000;
if(xboxSs.Value.Extents[e].EndPSN <= xboxSs.Value.Layer0EndPSN) if(xboxSs.Value.Extents[e].EndPSN <= xboxSs.Value.Layer0EndPSN)
extentEnd = xboxSs.Value.Extents[e].EndPSN - 0x30000; extentEnd = xboxSs.Value.Extents[e].EndPSN - 0x30000;
else else
extentEnd = (xboxSs.Value.Layer0EndPSN + 1) * 2 - extentEnd = (xboxSs.Value.Layer0EndPSN + 1) * 2 -
((xboxSs.Value.Extents[e].EndPSN ^ 0xFFFFFF) + 1) - 0x30000; ((xboxSs.Value.Extents[e].EndPSN ^ 0xFFFFFF) + 1) - 0x30000;
} }
// After last extent // After last extent
else else
@@ -453,7 +454,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(stopOnError) return; // TODO: Return more cleanly if(stopOnError) return; // TODO: Return more cleanly
if(i + skip > blocks) skip = (uint)(blocks - i); if(i + skip > blocks) skip = (uint)(blocks - i);
// Write empty data // Write empty data
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSectors(new byte[BLOCK_SIZE * skip], i, skip); outputPlugin.WriteSectors(new byte[BLOCK_SIZE * skip], i, skip);
@@ -467,7 +468,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
i += skip - blocksToRead; i += skip - blocksToRead;
string[] senseLines = Sense.PrettifySense(senseBuf).Split(new[] {Environment.NewLine}, string[] senseLines = Sense.PrettifySense(senseBuf).Split(new[] {Environment.NewLine},
StringSplitOptions StringSplitOptions
.RemoveEmptyEntries); .RemoveEmptyEntries);
@@ -477,9 +478,9 @@ namespace DiscImageChef.Core.Devices.Dumping
double newSpeed = double newSpeed =
(double)BLOCK_SIZE * blocksToRead / 1048576 / (cmdDuration / 1000); (double)BLOCK_SIZE * blocksToRead / 1048576 / (cmdDuration / 1000);
if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed; if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed;
blocksToRead = saveBlocksToRead; blocksToRead = saveBlocksToRead;
currentSector = i + 1; currentSector = i + 1;
resume.NextBlock = currentSector; resume.NextBlock = currentSector;
} }
for(ulong i = extentStart; i <= extentEnd; i += blocksToRead) for(ulong i = extentStart; i <= extentEnd; i += blocksToRead)
@@ -607,7 +608,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog.Write(l1, 0); ibgLog.Write(l1, 0);
dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, l1); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, l1);
l1 += skip - blocksToRead; l1 += skip - blocksToRead;
string[] senseLines = Sense.PrettifySense(senseBuf).Split(new[] {Environment.NewLine}, string[] senseLines = Sense.PrettifySense(senseBuf).Split(new[] {Environment.NewLine},
StringSplitOptions.RemoveEmptyEntries); StringSplitOptions.RemoveEmptyEntries);
foreach(string senseLine in senseLines) dumpLog.WriteLine(senseLine); foreach(string senseLine in senseLines) dumpLog.WriteLine(senseLine);
@@ -615,9 +616,9 @@ namespace DiscImageChef.Core.Devices.Dumping
double newSpeed = double newSpeed =
(double)BLOCK_SIZE * blocksToRead / 1048576 / (cmdDuration / 1000); (double)BLOCK_SIZE * blocksToRead / 1048576 / (cmdDuration / 1000);
if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed; if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed;
currentSector += blocksToRead; currentSector += blocksToRead;
resume.NextBlock = currentSector; resume.NextBlock = currentSector;
} }
dumpLog.WriteLine("Unlocking drive (Wxripper)."); dumpLog.WriteLine("Unlocking drive (Wxripper).");
@@ -640,17 +641,16 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
mhddLog.Close(); mhddLog.Close();
ibgLog.Close(dev, blocks, BLOCK_SIZE, (end - start).TotalSeconds, currentSpeed * 1024, ibgLog.Close(dev, blocks, BLOCK_SIZE, (end - start).TotalSeconds, currentSpeed * 1024,
BLOCK_SIZE * (double)(blocks + 1) / BLOCK_SIZE * (double)(blocks + 1) / 1024 / (totalDuration / 1000),
1024 / (totalDuration / 1000), devicePath); devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.", dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
(end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
(double)BLOCK_SIZE * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); (double)BLOCK_SIZE * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)BLOCK_SIZE * (double)(blocks + 1) / 1024 / imageWriteDuration); (double)BLOCK_SIZE * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Error handling #region Error handling
if(resume.BadBlocks.Count > 0 && !aborted) if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
{ {
List<ulong> tmpList = new List<ulong>(); List<ulong> tmpList = new List<ulong>();
@@ -692,8 +692,7 @@ namespace DiscImageChef.Core.Devices.Dumping
outputPlugin.WriteSector(readBuffer, badSector); outputPlugin.WriteSector(readBuffer, badSector);
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
} }
else if(runningPersistent) else if(runningPersistent) outputPlugin.WriteSector(readBuffer, badSector);
outputPlugin.WriteSector(readBuffer, badSector);
} }
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0) if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
@@ -713,12 +712,12 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
if(dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice) if(dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
{ {
Modes.ModePage_01_MMC pgMmc = Modes.ModePage_01_MMC pgMmc =
new Modes.ModePage_01_MMC {PS = false, ReadRetryCount = 255, Parameter = 0x20}; new Modes.ModePage_01_MMC {PS = false, ReadRetryCount = 255, Parameter = 0x20};
Modes.DecodedMode md = new Modes.DecodedMode Modes.DecodedMode md = new Modes.DecodedMode
{ {
Header = new Modes.ModeHeader(), Header = new Modes.ModeHeader(),
Pages = new[] Pages = new[]
{ {
new Modes.ModePage new Modes.ModePage
{ {
@@ -749,7 +748,7 @@ namespace DiscImageChef.Core.Devices.Dumping
Modes.DecodedMode md = new Modes.DecodedMode Modes.DecodedMode md = new Modes.DecodedMode
{ {
Header = new Modes.ModeHeader(), Header = new Modes.ModeHeader(),
Pages = new[] Pages = new[]
{ {
new Modes.ModePage new Modes.ModePage
{ {
@@ -764,7 +763,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
dumpLog.WriteLine("Sending MODE SELECT to drive."); dumpLog.WriteLine("Sending MODE SELECT to drive.");
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out _); sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out _);
if(sense) sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out _); if(sense) sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out _);
runningPersistent = true; runningPersistent = true;
@@ -836,7 +835,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DateTime chkStart = DateTime.UtcNow; DateTime chkStart = DateTime.UtcNow;
CICMMetadataType sidecar = Sidecar.Create(inputPlugin, outputPath, filter.Id, encoding); CICMMetadataType sidecar = Sidecar.Create(inputPlugin, outputPath, filter.Id, encoding);
end = DateTime.UtcNow; end = DateTime.UtcNow;
if(preSidecar != null) if(preSidecar != null)
{ {
@@ -844,7 +843,7 @@ namespace DiscImageChef.Core.Devices.Dumping
sidecar = preSidecar; sidecar = preSidecar;
} }
totalChkDuration = (end - chkStart).TotalMilliseconds; totalChkDuration = (end - chkStart).TotalMilliseconds;
dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
(double)BLOCK_SIZE * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); (double)BLOCK_SIZE * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000));