Separate trimming from retry pass fixes #172.

This commit is contained in:
2018-04-10 02:39:41 +01:00
parent 47e78ba0d4
commit 07f0dfe935
14 changed files with 281 additions and 80 deletions

View File

@@ -82,7 +82,7 @@ namespace DiscImageChef.Core.Devices.Dumping
string outputPrefix, string outputPath,
Dictionary<string, string> formatOptions, CICMMetadataType preSidecar,
uint skip,
bool nometadata)
bool nometadata, bool notrim)
{
bool aborted;
@@ -238,6 +238,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog = new IbgLog(outputPrefix + ".ibg", ATA_PROFILE);
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
bool newTrim = false;
start = DateTime.UtcNow;
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
@@ -283,6 +284,7 @@ namespace DiscImageChef.Core.Devices.Dumping
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
i += skip - blocksToRead;
newTrim = true;
}
double newSpeed =
@@ -303,6 +305,41 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Trimming
if(resume.BadBlocks.Count > 0 && !aborted && !notrim && newTrim)
{
start = DateTime.UtcNow;
dumpLog.WriteLine("Trimming bad sectors");
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break;
}
DicConsole.Write("\rTrimming sector {0}", badSector);
bool error = ataReader.ReadBlock(out cmdBuf, badSector, out duration);
totalDuration += duration;
if(error) continue;
resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
outputPlugin.WriteSector(cmdBuf, badSector);
}
DicConsole.WriteLine();
end = DateTime.UtcNow;
dumpLog.WriteLine("Trimmming finished in {0} seconds.", (end - start).TotalSeconds);
}
#endregion Trimming
#region Error handling
if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
{

View File

@@ -91,7 +91,7 @@ namespace DiscImageChef.Core.Devices.Dumping
string outputPrefix, string outputPath,
Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar, uint skip,
bool nometadata)
bool nometadata, bool notrim)
{
uint subSize;
DateTime start;
@@ -783,6 +783,7 @@ namespace DiscImageChef.Core.Devices.Dumping
double imageWriteDuration = 0;
if(skip < blocksToRead) skip = blocksToRead;
bool newTrim = false;
// Start reading
start = DateTime.UtcNow;
@@ -873,6 +874,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog.Write(i, 0);
dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
i += skip - blocksToRead;
newTrim = true;
}
double newSpeed =
@@ -894,6 +896,60 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Compact Disc Error trimming
if(resume.BadBlocks.Count > 0 && !aborted && !notrim && newTrim)
{
start = DateTime.UtcNow;
dumpLog.WriteLine("Trimming bad sectors");
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break;
}
DicConsole.Write("\rTrimming sector {0}", badSector);
if(readcd)
{
sense = true;
sense = dev.ReadCd(out readBuffer, out senseBuf, (uint)badSector, blockSize, 1,
MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
true, MmcErrorField.None, supportedSubchannel, dev.Timeout,
out double cmdDuration);
totalDuration += cmdDuration;
}
if(sense || dev.Error) continue;
if(!sense && !dev.Error)
{
resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
}
if(supportedSubchannel != MmcSubchannel.None)
{
byte[] data = new byte[SECTOR_SIZE];
byte[] sub = new byte[subSize];
Array.Copy(readBuffer, 0, data, 0, SECTOR_SIZE);
Array.Copy(readBuffer, SECTOR_SIZE, sub, 0, subSize);
outputPlugin.WriteSectorLong(data, badSector);
outputPlugin.WriteSectorTag(sub, badSector, SectorTagType.CdSectorSubchannel);
}
else outputPlugin.WriteSectorLong(readBuffer, badSector);
}
DicConsole.WriteLine();
end = DateTime.UtcNow;
dumpLog.WriteLine("Trimmming finished in {0} seconds.", (end - start).TotalSeconds);
}
#endregion Compact Disc Error trimming
#region Compact Disc Error handling
// 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...

View File

@@ -75,16 +75,16 @@ namespace DiscImageChef.Core.Devices.Dumping
/// <param name="outputPath">Path to output file</param>
/// <param name="formatOptions">Formats to pass to output file plugin</param>
/// <exception cref="NotImplementedException">If trying to dump GOD or WOD, or XGDs without a Kreon drive</exception>
internal static void Dump(Device dev, string devicePath, IWritableImage outputPlugin, ushort retryPasses,
bool force, bool dumpRaw, bool persistent, bool stopOnError,
ref MediaType dskType,
ref
Resume resume, ref DumpLog dumpLog, bool dumpLeadIn,
Encoding encoding,
string
outputPrefix, string outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType
preSidecar, uint skip, bool nometadata)
internal static void Dump(Device dev, string devicePath,
IWritableImage outputPlugin, ushort retryPasses,
bool force, bool dumpRaw,
bool persistent, bool stopOnError, ref MediaType dskType,
ref Resume resume, ref DumpLog dumpLog,
bool dumpLeadIn, Encoding encoding,
string outputPrefix, string outputPath,
Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar, uint skip,
bool nometadata, bool notrim)
{
bool sense;
ulong blocks;
@@ -200,7 +200,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{
CompactDisc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError,
ref dskType, ref resume, ref dumpLog, dumpLeadIn, encoding, outputPrefix, outputPath,
formatOptions, preSidecar, skip, nometadata);
formatOptions, preSidecar, skip, nometadata, notrim);
return;
}
@@ -602,13 +602,13 @@ namespace DiscImageChef.Core.Devices.Dumping
{
Xgd.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, mediaTags,
ref dskType, ref resume, ref dumpLog, encoding, outputPrefix, outputPath, formatOptions,
preSidecar, skip, nometadata);
preSidecar, skip, nometadata, notrim);
return;
}
Sbc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, mediaTags,
ref dskType, true, ref resume, ref dumpLog, encoding, outputPrefix, outputPath, formatOptions,
preSidecar, skip, nometadata);
preSidecar, skip, nometadata, notrim);
}
internal static void AddMediaTagToSidecar(string outputPath,

View File

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

View File

@@ -87,7 +87,7 @@ namespace DiscImageChef.Core.Devices.Dumping
Encoding encoding, string outputPrefix,
string outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar, uint skip,
bool nometadata)
bool nometadata, bool notrim)
{
bool sense;
ulong blocks;
@@ -347,6 +347,7 @@ namespace DiscImageChef.Core.Devices.Dumping
throw new InvalidOperationException("Could not process resume file, not continuing...");
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
bool newTrim = false;
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
{
@@ -397,6 +398,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog.Write(i, 0);
dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
i += skip - blocksToRead;
newTrim = true;
}
double newSpeed =
@@ -417,6 +419,39 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Trimming
if(resume.BadBlocks.Count > 0 && !aborted && !notrim && newTrim)
{
start = DateTime.UtcNow;
dumpLog.WriteLine("Trimming bad sectors");
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break;
}
DicConsole.Write("\rTrimming sector {0}", badSector);
sense = scsiReader.ReadBlock(out readBuffer, badSector, out double cmdDuration);
if(sense || dev.Error) continue;
resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
outputPlugin.WriteSector(readBuffer, badSector);
}
DicConsole.WriteLine();
end = DateTime.UtcNow;
dumpLog.WriteLine("Trimmming finished in {0} seconds.", (end - start).TotalSeconds);
}
#endregion Trimming
#region Error handling
if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
{

View File

@@ -70,16 +70,15 @@ namespace DiscImageChef.Core.Devices.Dumping
/// <param name="outputPath">Path to output file</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>
public static void Dump(Device dev, string devicePath, IWritableImage outputPlugin, ushort retryPasses,
bool force, bool dumpRaw, bool persistent, bool stopOnError,
ref Resume resume,
ref
DumpLog dumpLog, bool dumpLeadIn, Encoding encoding,
string outputPrefix,
string
outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType
preSidecar, uint skip, bool nometadata)
public static void Dump(Device dev, string devicePath,
IWritableImage outputPlugin, ushort retryPasses,
bool force, bool dumpRaw,
bool persistent, bool stopOnError, ref Resume resume,
ref DumpLog dumpLog, bool dumpLeadIn,
Encoding encoding, string outputPrefix,
string outputPath, Dictionary<string, string> formatOptions,
CICMMetadataType preSidecar, uint skip, bool nometadata,
bool notrim)
{
MediaType dskType = MediaType.Unknown;
int resets = 0;
@@ -212,12 +211,12 @@ namespace DiscImageChef.Core.Devices.Dumping
case PeripheralDeviceTypes.MultiMediaDevice:
Mmc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError,
ref dskType, ref resume, ref dumpLog, dumpLeadIn, encoding, outputPrefix, outputPath,
formatOptions, preSidecar, skip, nometadata);
formatOptions, preSidecar, skip, nometadata, notrim);
return;
default:
Sbc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, null,
ref dskType, false, ref resume, ref dumpLog, encoding, outputPrefix, outputPath,
formatOptions, preSidecar, skip, nometadata);
formatOptions, preSidecar, skip, nometadata, notrim);
break;
}
}

View File

@@ -80,7 +80,7 @@ namespace DiscImageChef.Core.Devices.Dumping
string outputPrefix, string outputPath,
Dictionary<string, string> formatOptions, CICMMetadataType preSidecar,
uint skip,
bool nometadata)
bool nometadata, bool notrim)
{
bool aborted;
@@ -280,6 +280,7 @@ namespace DiscImageChef.Core.Devices.Dumping
start = DateTime.UtcNow;
double imageWriteDuration = 0;
bool newTrim = false;
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
{
@@ -325,6 +326,7 @@ namespace DiscImageChef.Core.Devices.Dumping
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i);
i += skip - blocksToRead;
newTrim = true;
}
double newSpeed =
@@ -345,6 +347,42 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Trimming
if(resume.BadBlocks.Count > 0 && !aborted && !notrim && newTrim)
{
start = DateTime.UtcNow;
dumpLog.WriteLine("Trimming bad sectors");
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break;
}
DicConsole.Write("\rTrimming sector {0}", badSector);
error = dev.Read(out cmdBuf, out _, (uint)badSector, blockSize, 1, byteAddressed, TIMEOUT,
out duration);
totalDuration += duration;
if(error) continue;
resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
outputPlugin.WriteSector(cmdBuf, badSector);
}
DicConsole.WriteLine();
end = DateTime.UtcNow;
dumpLog.WriteLine("Trimmming finished in {0} seconds.", (end - start).TotalSeconds);
}
#endregion Trimming
#region Error handling
if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
{

View File

@@ -90,7 +90,7 @@ namespace DiscImageChef.Core.Devices.Dumping
string outputPrefix, string outputPath,
Dictionary<string, string> formatOptions, CICMMetadataType preSidecar,
uint skip,
bool nometadata)
bool nometadata, bool notrim)
{
bool sense;
ulong blocks;
@@ -377,6 +377,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ulong currentSector = resume.NextBlock;
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
bool newTrim = false;
dumpLog.WriteLine("Reading game partition.");
for(int e = 0; e <= 16; e++)
@@ -473,6 +474,7 @@ namespace DiscImageChef.Core.Devices.Dumping
StringSplitOptions
.RemoveEmptyEntries);
foreach(string senseLine in senseLines) dumpLog.WriteLine(senseLine);
newTrim = true;
}
double newSpeed =
@@ -649,6 +651,41 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
(double)BLOCK_SIZE * (double)(blocks + 1) / 1024 / imageWriteDuration);
#region Trimming
if(resume.BadBlocks.Count > 0 && !aborted && !notrim && newTrim)
{
start = DateTime.UtcNow;
dumpLog.WriteLine("Trimming bad sectors");
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break;
}
DicConsole.Write("\rTrimming sector {0}", badSector);
sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)badSector,
BLOCK_SIZE, 0, 1, false, dev.Timeout, out cmdDuration);
totalDuration += cmdDuration;
if(sense || dev.Error) continue;
resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
outputPlugin.WriteSector(readBuffer, badSector);
}
DicConsole.WriteLine();
end = DateTime.UtcNow;
dumpLog.WriteLine("Trimmming finished in {0} seconds.", (end - start).TotalSeconds);
}
#endregion Trimming
#region Error handling
if(resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0)
{

View File

@@ -1 +0,0 @@
../../Changelog.md

View File

@@ -1 +0,0 @@
../../DONATING.md

View File

@@ -1 +0,0 @@
../../README.md

View File

@@ -1 +0,0 @@
../../TODO.md

View File

@@ -207,26 +207,28 @@ namespace DiscImageChef.Commands
case DeviceType.ATA:
Ata.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, options.Raw,
options.Persistent, options.StopOnError, ref resume, ref dumpLog, encoding, outputPrefix,
options.OutputFile, parsedOptions, sidecar, (uint)options.Skip, options.NoMetadata);
options.OutputFile, parsedOptions, sidecar, (uint)options.Skip, options.NoMetadata,
options.NoTrim);
break;
case DeviceType.MMC:
case DeviceType.SecureDigital:
SecureDigital.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force,
options.Raw, options.Persistent, options.StopOnError, ref resume, ref dumpLog,
encoding, outputPrefix, options.OutputFile, parsedOptions, sidecar, (uint)options.Skip,
options.NoMetadata);
encoding, outputPrefix, options.OutputFile, parsedOptions, sidecar,
(uint)options.Skip, options.NoMetadata, options.NoTrim);
break;
case DeviceType.NVMe:
NvMe.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, options.Raw,
options.Persistent, options.StopOnError, ref resume, ref dumpLog, encoding, outputPrefix,
options.OutputFile, parsedOptions, sidecar, (uint)options.Skip, options.NoMetadata);
options.OutputFile, parsedOptions, sidecar, (uint)options.Skip, options.NoMetadata,
options.NoTrim);
break;
case DeviceType.ATAPI:
case DeviceType.SCSI:
Scsi.Dump(dev, options.DevicePath, outputFormat, options.RetryPasses, options.Force, options.Raw,
options.Persistent, options.StopOnError, ref resume, ref dumpLog, options.LeadIn,
encoding, outputPrefix, options.OutputFile, parsedOptions, sidecar, (uint)options.Skip,
options.NoMetadata);
options.NoMetadata, options.NoTrim);
break;
default:
dumpLog.WriteLine("Unknown device type.");

View File

@@ -93,12 +93,10 @@ namespace DiscImageChef
[Option("crc64", Default = false, HelpText = "Calculates CRC64 (ECMA).")]
public bool DoCrc64 { get; set; }
[Option("fletcher16", Default = false,
HelpText = "Calculates Fletcher-16.")]
[Option("fletcher16", Default = false, HelpText = "Calculates Fletcher-16.")]
public bool DoFletcher16 { get; set; }
[Option("fletcher32", Default = false,
HelpText = "Calculates Fletcher-32.")]
[Option("fletcher32", Default = false, HelpText = "Calculates Fletcher-32.")]
public bool DoFletcher32 { get; set; }
[Option('m', "md5", Default = true, HelpText = "Calculates MD5.")]
@@ -314,6 +312,9 @@ namespace DiscImageChef
[Option("no-metadata", Default = false, HelpText = "Disables creating CICM XML sidecar.")]
public bool NoMetadata { get; set; }
[Option("no-trim", Default = false, HelpText = "Disables trimming errored from skipped sectors.")]
public bool NoTrim { get; set; }
}
[Verb("device-report", HelpText = "Tests the device capabilities and creates an XML report of them.")]