Add option to skip more sectors than tried to read when a bad sector is found.

This commit is contained in:
2018-02-02 18:44:28 +00:00
parent 2a26a22e21
commit efcf1720e2
10 changed files with 91 additions and 61 deletions

View File

@@ -81,7 +81,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DumpLog dumpLog, Encoding encoding, string outputPrefix, DumpLog dumpLog, Encoding encoding, string outputPrefix,
string outputPath, string outputPath,
Dictionary<string, string> Dictionary<string, string>
formatOptions, CICMMetadataType preSidecar) formatOptions, CICMMetadataType preSidecar, uint skip)
{ {
bool aborted; bool aborted;
@@ -98,10 +98,10 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
bool sense; bool sense;
const ushort ATA_PROFILE = 0x0001; const ushort ATA_PROFILE = 0x0001;
const uint TIMEOUT = 5; const uint TIMEOUT = 5;
double imageWriteDuration = 0; double imageWriteDuration = 0;
dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE."); dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE.");
sense = dev.AtaIdentify(out byte[] cmdBuf, out _); sense = dev.AtaIdentify(out byte[] cmdBuf, out _);
if(!sense && Identify.Decode(cmdBuf).HasValue) if(!sense && Identify.Decode(cmdBuf).HasValue)
@@ -232,6 +232,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(ataReader.IsLba) if(ataReader.IsLba)
{ {
DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead);
if(skip < blocksToRead) skip = blocksToRead;
mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead); mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
ibgLog = new IbgLog(outputPrefix + ".ibg", ATA_PROFILE); ibgLog = new IbgLog(outputPrefix + ".ibg", ATA_PROFILE);
@@ -270,15 +271,16 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
else else
{ {
for(ulong b = i; b < i + blocksToRead; 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);
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSectors(new byte[blockSize * blocksToRead], i, blocksToRead); outputPlugin.WriteSectors(new byte[blockSize * skip], i, skip);
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
i += skip - blocksToRead;
} }
double newSpeed = double newSpeed =
@@ -391,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);
@@ -405,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 =
@@ -428,7 +430,8 @@ namespace DiscImageChef.Core.Devices.Dumping
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 / 1000)); (double)blockSize * (double)(blocks + 1) / 1024 /
(imageWriteDuration / 1000));
} }
foreach(ulong bad in resume.BadBlocks) dumpLog.WriteLine("Sector {0} could not be read.", bad); foreach(ulong bad in resume.BadBlocks) dumpLog.WriteLine("Sector {0} could not be read.", bad);
@@ -594,8 +597,10 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).", DicConsole
(end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000, imageWriteDuration, (closeEnd -closeStart).TotalSeconds); .WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).",
(end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000,
imageWriteDuration, (closeEnd - closeStart).TotalSeconds);
DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.", DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000)); (double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000));
DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed); DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed);

View File

@@ -91,7 +91,7 @@ namespace DiscImageChef.Core.Devices.Dumping
string string
outputPrefix, string outputPath, Dictionary<string, string> formatOptions, outputPrefix, string outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType CICMMetadataType
preSidecar) preSidecar, uint skip)
{ {
uint subSize; uint subSize;
DateTime start; DateTime start;
@@ -661,7 +661,9 @@ 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);
double imageWriteDuration = 0; double imageWriteDuration = 0;
if(skip < blocksToRead) skip = blocksToRead;
// Start reading // Start reading
start = DateTime.UtcNow; start = DateTime.UtcNow;
for(int t = 0; t < tracks.Length; t++) for(int t = 0; t < tracks.Length; t++)
@@ -733,20 +735,22 @@ namespace DiscImageChef.Core.Devices.Dumping
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
if(supportedSubchannel != MmcSubchannel.None) if(supportedSubchannel != MmcSubchannel.None)
{ {
outputPlugin.WriteSectorsLong(new byte[SECTOR_SIZE * blocksToRead], i, blocksToRead); outputPlugin.WriteSectorsLong(new byte[SECTOR_SIZE * skip], i, skip);
outputPlugin.WriteSectorsTag(new byte[subSize * blocksToRead], i, blocksToRead, outputPlugin.WriteSectorsTag(new byte[subSize * skip], i, skip,
SectorTagType.CdSectorSubchannel); SectorTagType.CdSectorSubchannel);
} }
else outputPlugin.WriteSectorsLong(new byte[blockSize * blocksToRead], i, blocksToRead); else outputPlugin.WriteSectorsLong(new byte[blockSize * skip], i, skip);
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
for(ulong b = i; b < i + blocksToRead; b++) resume.BadBlocks.Add(b); for(ulong b = i; b < i + skip; b++) resume.BadBlocks.Add(b);
DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
dumpLog.WriteLine("Error reading {0} sectors from sector {1}.", blocksToRead, i); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
i += skip - blocksToRead;
} }
double newSpeed = double newSpeed =
@@ -963,7 +967,9 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).", DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).",
(end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000, imageWriteDuration, (closeEnd-closeStart).TotalSeconds); (end - start).TotalSeconds, totalDuration / 1000,
totalChkDuration / 1000,
imageWriteDuration, (closeEnd - closeStart).TotalSeconds);
DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.", DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000)); (double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000));
DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed); DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed);

View File

@@ -84,7 +84,7 @@ namespace DiscImageChef.Core.Devices.Dumping
string string
outputPrefix, string outputPath, Dictionary<string, string> formatOptions, outputPrefix, string outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType CICMMetadataType
preSidecar) preSidecar, uint skip)
{ {
bool sense; bool sense;
ulong blocks; ulong blocks;
@@ -200,7 +200,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
CompactDisc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, CompactDisc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError,
ref dskType, ref resume, ref dumpLog, dumpLeadIn, encoding, outputPrefix, outputPath, ref dskType, ref resume, ref dumpLog, dumpLeadIn, encoding, outputPrefix, outputPath,
formatOptions, preSidecar); formatOptions, preSidecar, skip);
return; return;
} }
@@ -602,13 +602,13 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
Xgd.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, mediaTags, Xgd.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, mediaTags,
ref dskType, ref resume, ref dumpLog, encoding, outputPrefix, outputPath, formatOptions, ref dskType, ref resume, ref dumpLog, encoding, outputPrefix, outputPath, formatOptions,
preSidecar); preSidecar, skip);
return; return;
} }
Sbc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, mediaTags, Sbc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, mediaTags,
ref dskType, true, ref resume, ref dumpLog, encoding, outputPrefix, outputPath, formatOptions, ref dskType, true, ref resume, ref dumpLog, encoding, outputPrefix, outputPath, formatOptions,
preSidecar); preSidecar, skip);
} }
internal static void AddMediaTagToSidecar(string outputPath, internal static void AddMediaTagToSidecar(string outputPath,
@@ -798,8 +798,8 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
new BorderType new BorderType
{ {
Image = outputPath, Image = outputPath,
Size = tag.Value.Length, Size = tag.Value.Length,
Checksums = Checksum.GetChecksums(tag.Value).ToArray() Checksums = Checksum.GetChecksums(tag.Value).ToArray()
} }
}; };

View File

@@ -50,7 +50,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DumpLog dumpLog, Encoding encoding, string outputPrefix, DumpLog dumpLog, Encoding encoding, string outputPrefix,
string outputPath, string outputPath,
Dictionary<string, string> Dictionary<string, string>
formatOptions, CICMMetadataType preSidecar) formatOptions, CICMMetadataType preSidecar, uint skip)
{ {
throw new NotImplementedException("NVMe devices not yet supported."); throw new NotImplementedException("NVMe devices not yet supported.");
} }

View File

@@ -86,7 +86,8 @@ namespace DiscImageChef.Core.Devices.Dumping
ref DumpLog dumpLog, Encoding encoding, string outputPrefix, ref DumpLog dumpLog, Encoding encoding, string outputPrefix,
string outputPath, string outputPath,
Dictionary<string, string> formatOptions, Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar) CICMMetadataType preSidecar,
uint skip)
{ {
bool sense; bool sense;
ulong blocks; ulong blocks;
@@ -287,9 +288,9 @@ namespace DiscImageChef.Core.Devices.Dumping
return; return;
} }
start = DateTime.UtcNow; start = DateTime.UtcNow;
double imageWriteDuration = 0; double imageWriteDuration = 0;
if(opticalDisc) if(opticalDisc)
outputPlugin.SetTracks(new List<Track> outputPlugin.SetTracks(new List<Track>
{ {
@@ -387,15 +388,16 @@ namespace DiscImageChef.Core.Devices.Dumping
// Write empty data // Write empty data
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSectors(new byte[blockSize * blocksToRead], i, blocksToRead); outputPlugin.WriteSectors(new byte[blockSize * skip], i, skip);
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
for(ulong b = i; b < i + blocksToRead; b++) resume.BadBlocks.Add(b); for(ulong b = i; b < i + skip; b++) resume.BadBlocks.Add(b);
mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
i += skip - blocksToRead;
} }
double newSpeed = double newSpeed =
@@ -883,7 +885,9 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).", DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).",
(end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000, imageWriteDuration, (closeEnd -closeStart).TotalSeconds); (end - start).TotalSeconds, totalDuration / 1000,
totalChkDuration / 1000,
imageWriteDuration, (closeEnd - closeStart).TotalSeconds);
DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.", DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000)); (double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000));
DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed); DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed);

View File

@@ -79,7 +79,7 @@ namespace DiscImageChef.Core.Devices.Dumping
string string
outputPath, Dictionary<string, string> formatOptions, outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType CICMMetadataType
preSidecar) preSidecar, uint skip)
{ {
MediaType dskType = MediaType.Unknown; MediaType dskType = MediaType.Unknown;
int resets = 0; int resets = 0;
@@ -212,12 +212,12 @@ namespace DiscImageChef.Core.Devices.Dumping
case PeripheralDeviceTypes.MultiMediaDevice: case PeripheralDeviceTypes.MultiMediaDevice:
Mmc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, Mmc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError,
ref dskType, ref resume, ref dumpLog, dumpLeadIn, encoding, outputPrefix, outputPath, ref dskType, ref resume, ref dumpLog, dumpLeadIn, encoding, outputPrefix, outputPath,
formatOptions, preSidecar); formatOptions, preSidecar, skip);
return; return;
default: default:
Sbc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, null, Sbc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, null,
ref dskType, false, ref resume, ref dumpLog, encoding, outputPrefix, outputPath, ref dskType, false, ref resume, ref dumpLog, encoding, outputPrefix, outputPath,
formatOptions, preSidecar); formatOptions, preSidecar, skip);
break; break;
} }
} }

View File

@@ -79,7 +79,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DumpLog dumpLog, Encoding encoding, string outputPrefix, DumpLog dumpLog, Encoding encoding, string outputPrefix,
string outputPath, string outputPath,
Dictionary<string, string> Dictionary<string, string>
formatOptions, CICMMetadataType preSidecar) formatOptions, CICMMetadataType preSidecar, uint skip)
{ {
bool aborted; bool aborted;
@@ -234,6 +234,8 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead); dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
if(skip < blocksToRead) skip = blocksToRead;
DumpHardwareType currentTry = null; DumpHardwareType currentTry = null;
ExtentsULong extents = null; ExtentsULong extents = null;
ResumeSupport.Process(true, false, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformId, ResumeSupport.Process(true, false, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformId,
@@ -281,9 +283,9 @@ 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)
{ {
if(aborted) if(aborted)
@@ -316,15 +318,16 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
else else
{ {
for(ulong b = i; b < i + blocksToRead; 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);
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSectors(new byte[blockSize * blocksToRead], i, blocksToRead); outputPlugin.WriteSectors(new byte[blockSize * skip], i, skip);
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
i += skip - blocksToRead;
} }
double newSpeed = double newSpeed =
@@ -598,7 +601,9 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).", DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).",
(end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000, imageWriteDuration, (closeEnd -closeStart).TotalSeconds); (end - start).TotalSeconds, totalDuration / 1000,
totalChkDuration / 1000,
imageWriteDuration, (closeEnd - closeStart).TotalSeconds);
DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.", DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000)); (double)blockSize * (double)(blocks + 1) / 1048576 / (totalDuration / 1000));
DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed); DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed);

View File

@@ -88,7 +88,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ref DumpLog dumpLog, ref DumpLog dumpLog,
Encoding encoding, string outputPrefix, string outputPath, Encoding encoding, string outputPrefix, string outputPath,
Dictionary<string, string> formatOptions, Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar) CICMMetadataType preSidecar, uint skip)
{ {
bool sense; bool sense;
ulong blocks; ulong blocks;
@@ -311,6 +311,8 @@ namespace DiscImageChef.Core.Devices.Dumping
return; return;
} }
if(skip < blocksToRead) skip = blocksToRead;
bool ret = true; bool ret = true;
foreach(MediaTagType tag in mediaTags.Keys) foreach(MediaTagType tag in mediaTags.Keys)
@@ -346,9 +348,9 @@ 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;
uint saveBlocksToRead = blocksToRead; uint saveBlocksToRead = blocksToRead;
DumpHardwareType currentTry = null; DumpHardwareType currentTry = null;
@@ -438,17 +440,18 @@ namespace DiscImageChef.Core.Devices.Dumping
// Write empty data // Write empty data
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSectors(new byte[BLOCK_SIZE * blocksToRead], i, blocksToRead); outputPlugin.WriteSectors(new byte[BLOCK_SIZE * skip], i, skip);
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
for(ulong b = i; b < i + blocksToRead; b++) resume.BadBlocks.Add(b); for(ulong b = i; b < i + skip; b++) resume.BadBlocks.Add(b);
DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
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);
@@ -481,7 +484,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSectors(new byte[BLOCK_SIZE * blocksToRead], i, blocksToRead); outputPlugin.WriteSectors(new byte[BLOCK_SIZE * blocksToRead], i, blocksToRead);
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
blocksToRead = saveBlocksToRead; blocksToRead = saveBlocksToRead;
extents.Add(i, blocksToRead, true); extents.Add(i, blocksToRead, true);
currentSector = i + 1; currentSector = i + 1;
resume.NextBlock = currentSector; resume.NextBlock = currentSector;
@@ -511,7 +514,7 @@ namespace DiscImageChef.Core.Devices.Dumping
// Write empty data // Write empty data
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSectors(new byte[BLOCK_SIZE * blocksToRead], middle + currentSector, blocksToRead); outputPlugin.WriteSectors(new byte[BLOCK_SIZE * blocksToRead], middle + currentSector, blocksToRead);
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
extents.Add(currentSector, blocksToRead, true); extents.Add(currentSector, blocksToRead, true);
currentSector += blocksToRead; currentSector += blocksToRead;
@@ -577,7 +580,7 @@ namespace DiscImageChef.Core.Devices.Dumping
// Write empty data // Write empty data
DateTime writeStart = DateTime.Now; DateTime writeStart = DateTime.Now;
outputPlugin.WriteSectors(new byte[BLOCK_SIZE * blocksToRead], currentSector, blocksToRead); outputPlugin.WriteSectors(new byte[BLOCK_SIZE * skip], currentSector, skip);
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
// TODO: Handle errors in video partition // TODO: Handle errors in video partition
@@ -587,7 +590,8 @@ namespace DiscImageChef.Core.Devices.Dumping
mhddLog.Write(l1, cmdDuration < 500 ? 65535 : cmdDuration); mhddLog.Write(l1, cmdDuration < 500 ? 65535 : cmdDuration);
ibgLog.Write(l1, 0); ibgLog.Write(l1, 0);
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, l1); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, l1);
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);
@@ -861,7 +865,9 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).", DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).",
(end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000, imageWriteDuration, (closeEnd -closeStart).TotalSeconds); (end - start).TotalSeconds, totalDuration / 1000,
totalChkDuration / 1000,
imageWriteDuration, (closeEnd - closeStart).TotalSeconds);
DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.", DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.",
(double)BLOCK_SIZE * (double)(blocks + 1) / 1048576 / (totalDuration / 1000)); (double)BLOCK_SIZE * (double)(blocks + 1) / 1048576 / (totalDuration / 1000));
DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed); DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed);

View File

@@ -76,6 +76,7 @@ namespace DiscImageChef.Commands
DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", options.Force); DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", options.Force);
DicConsole.DebugWriteLine("Dump-Media command", "--options={0}", options.Options); DicConsole.DebugWriteLine("Dump-Media command", "--options={0}", options.Options);
DicConsole.DebugWriteLine("Dump-Media command", "--cicm-xml={0}", options.CicmXml); DicConsole.DebugWriteLine("Dump-Media command", "--cicm-xml={0}", options.CicmXml);
DicConsole.DebugWriteLine("Dump-Media command", "--skip={0}", options.Skip);
Dictionary<string, string> parsedOptions = Options.Parse(options.Options); Dictionary<string, string> parsedOptions = Options.Parse(options.Options);
DicConsole.DebugWriteLine("Dump-Media command", "Parsed options:"); DicConsole.DebugWriteLine("Dump-Media command", "Parsed options:");
@@ -205,24 +206,24 @@ namespace DiscImageChef.Commands
case DeviceType.ATA: case DeviceType.ATA:
Ata.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, options.Raw, Ata.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, options.Raw,
options.Persistent, options.StopOnError, ref resume, ref dumpLog, encoding, outputPrefix, options.Persistent, options.StopOnError, ref resume, ref dumpLog, encoding, outputPrefix,
options.OutputFile, parsedOptions, sidecar); options.OutputFile, parsedOptions, sidecar, options.Skip);
break; break;
case DeviceType.MMC: case DeviceType.MMC:
case DeviceType.SecureDigital: case DeviceType.SecureDigital:
SecureDigital.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, SecureDigital.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force,
options.Raw, options.Persistent, options.StopOnError, ref resume, ref dumpLog, options.Raw, options.Persistent, options.StopOnError, ref resume, ref dumpLog,
encoding, outputPrefix, options.OutputFile, parsedOptions, sidecar); encoding, outputPrefix, options.OutputFile, parsedOptions, sidecar, options.Skip);
break; break;
case DeviceType.NVMe: case DeviceType.NVMe:
NvMe.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, options.Raw, NvMe.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, options.Raw,
options.Persistent, options.StopOnError, ref resume, ref dumpLog, encoding, outputPrefix, options.Persistent, options.StopOnError, ref resume, ref dumpLog, encoding, outputPrefix,
options.OutputFile, parsedOptions, sidecar); options.OutputFile, parsedOptions, sidecar, options.Skip);
break; break;
case DeviceType.ATAPI: case DeviceType.ATAPI:
case DeviceType.SCSI: case DeviceType.SCSI:
Scsi.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, options.Raw, Scsi.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, options.Raw,
options.Persistent, options.StopOnError, ref resume, ref dumpLog, options.LeadIn, options.Persistent, options.StopOnError, ref resume, ref dumpLog, options.LeadIn,
encoding, outputPrefix, options.OutputFile, parsedOptions, sidecar); encoding, outputPrefix, options.OutputFile, parsedOptions, sidecar, options.Skip);
break; break;
default: default:
dumpLog.WriteLine("Unknown device type."); dumpLog.WriteLine("Unknown device type.");

View File

@@ -308,6 +308,9 @@ namespace DiscImageChef
[Option('x', "cicm-xml", Default = null, HelpText = "Take metadata from existing CICM XML sidecar.")] [Option('x', "cicm-xml", Default = null, HelpText = "Take metadata from existing CICM XML sidecar.")]
public string CicmXml { get; set; } public string CicmXml { get; set; }
[Option('k', "skip", Default = 512, HelpText = "When an unreadable sector is found skip this many sectors.")]
public uint Skip { get; set; }
} }
[Verb("device-report", HelpText = "Tests the device capabilities and creates an XML report of them.")] [Verb("device-report", HelpText = "Tests the device capabilities and creates an XML report of them.")]
@@ -432,7 +435,7 @@ namespace DiscImageChef
[Option('O', "options", Default = null, [Option('O', "options", Default = null,
HelpText = "Comma separated name=value pairs of options to pass to output image plugin")] HelpText = "Comma separated name=value pairs of options to pass to output image plugin")]
public string Options { get; set; } public string Options { get; set; }
[Option('x', "cicm-xml", Default = null, HelpText = "Take metadata from existing CICM XML sidecar.")] [Option('x', "cicm-xml", Default = null, HelpText = "Take metadata from existing CICM XML sidecar.")]
public string CicmXml { get; set; } public string CicmXml { get; set; }