mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
🐛Fix sending error recovery MODE page to devices before trying damaged sectors. Fixes #169
This commit is contained in:
@@ -82,16 +82,16 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
/// <exception cref="NotImplementedException">If trying to dump scrambled sectors</exception>
|
||||
/// <exception cref="InvalidOperationException">If the resume file is invalid</exception>
|
||||
/// <exception cref="ArgumentOutOfRangeException">If the track type is unknown (never)</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)
|
||||
{
|
||||
uint subSize;
|
||||
DateTime start;
|
||||
@@ -335,8 +335,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
toc.Value.TrackDescriptors.OrderBy(track => track.POINT).ToArray();
|
||||
|
||||
foreach(FullTOC.TrackDataDescriptor trk in sortedTracks.Where(trk => trk.ADR == 1 || trk.ADR == 4))
|
||||
if(trk.POINT >= 0x01 &&
|
||||
trk.POINT <= 0x63)
|
||||
if(trk.POINT >= 0x01 && trk.POINT <= 0x63)
|
||||
{
|
||||
trackList.Add(new Track
|
||||
{
|
||||
@@ -732,8 +731,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
subSize = 0;
|
||||
blockSize = SECTOR_SIZE + subSize;
|
||||
for(int t = 0; t < tracks.Length; t++) tracks[t].TrackSubchannelType = TrackSubchannelType.None;
|
||||
ret =
|
||||
outputPlugin.SetTracks(tracks.ToList());
|
||||
ret = outputPlugin.SetTracks(tracks.ToList());
|
||||
if(!ret)
|
||||
{
|
||||
dumpLog.WriteLine("Error sending tracks to output image, not continuing.");
|
||||
@@ -888,10 +886,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
end = DateTime.UtcNow;
|
||||
mhddLog.Close();
|
||||
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
|
||||
blockSize * (double)(blocks + 1) /
|
||||
1024 / (totalDuration / 1000), devicePath);
|
||||
dumpLog.WriteLine("Dump finished in {0} seconds.",
|
||||
(end - start).TotalSeconds);
|
||||
blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000),
|
||||
devicePath);
|
||||
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
|
||||
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
|
||||
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
|
||||
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
|
||||
@@ -906,6 +903,44 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
bool forward = true;
|
||||
bool runningPersistent = false;
|
||||
|
||||
Modes.ModePage? currentModePage = null;
|
||||
byte[] md6;
|
||||
byte[] md10;
|
||||
|
||||
if(persistent)
|
||||
{
|
||||
Modes.ModePage_01_MMC pgMmc =
|
||||
new Modes.ModePage_01_MMC {PS = false, ReadRetryCount = 255, Parameter = 0x20};
|
||||
Modes.DecodedMode md = new Modes.DecodedMode
|
||||
{
|
||||
Header = new Modes.ModeHeader(),
|
||||
Pages = new[]
|
||||
{
|
||||
new Modes.ModePage
|
||||
{
|
||||
Page = 0x01,
|
||||
Subpage = 0x00,
|
||||
PageResponse = Modes.EncodeModePage_01_MMC(pgMmc)
|
||||
}
|
||||
}
|
||||
};
|
||||
md6 = Modes.EncodeMode6(md, dev.ScsiType);
|
||||
md10 = Modes.EncodeMode10(md, dev.ScsiType);
|
||||
|
||||
dumpLog.WriteLine("Sending MODE SELECT to drive.");
|
||||
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)
|
||||
{
|
||||
DicConsole
|
||||
.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
|
||||
DicConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf));
|
||||
dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
|
||||
}
|
||||
else runningPersistent = true;
|
||||
}
|
||||
|
||||
cdRepeatRetry:
|
||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||
foreach(ulong badSector in tmpArray)
|
||||
@@ -960,42 +995,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
goto cdRepeatRetry;
|
||||
}
|
||||
|
||||
Modes.ModePage? currentModePage = null;
|
||||
byte[] md6;
|
||||
byte[] md10;
|
||||
|
||||
if(!runningPersistent && persistent)
|
||||
{
|
||||
Modes.ModePage_01_MMC pgMmc =
|
||||
new Modes.ModePage_01_MMC {PS = false, ReadRetryCount = 255, Parameter = 0x20};
|
||||
Modes.DecodedMode md = new Modes.DecodedMode
|
||||
{
|
||||
Header = new Modes.ModeHeader(),
|
||||
Pages = new[]
|
||||
{
|
||||
new Modes.ModePage
|
||||
{
|
||||
Page = 0x01,
|
||||
Subpage = 0x00,
|
||||
PageResponse = Modes.EncodeModePage_01_MMC(pgMmc)
|
||||
}
|
||||
}
|
||||
};
|
||||
md6 = Modes.EncodeMode6(md, dev.ScsiType);
|
||||
md10 = Modes.EncodeMode10(md, dev.ScsiType);
|
||||
|
||||
dumpLog.WriteLine("Sending MODE SELECT to drive.");
|
||||
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out _);
|
||||
if(sense) sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out _);
|
||||
|
||||
runningPersistent = true;
|
||||
if(!sense && !dev.Error)
|
||||
{
|
||||
pass--;
|
||||
goto cdRepeatRetry;
|
||||
}
|
||||
}
|
||||
else if(runningPersistent && persistent && currentModePage.HasValue)
|
||||
if(runningPersistent && currentModePage.HasValue)
|
||||
{
|
||||
Modes.DecodedMode md = new Modes.DecodedMode
|
||||
{
|
||||
|
||||
@@ -83,12 +83,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
bool persistent, bool stopOnError,
|
||||
Dictionary<MediaTagType, byte[]> mediaTags, ref MediaType dskType,
|
||||
bool opticalDisc,
|
||||
ref Resume resume,
|
||||
ref DumpLog dumpLog, Encoding encoding, string outputPrefix,
|
||||
string outputPath,
|
||||
Dictionary<string, string> formatOptions,
|
||||
CICMMetadataType preSidecar,
|
||||
uint skip, bool nometadata)
|
||||
ref Resume resume, ref DumpLog dumpLog,
|
||||
Encoding encoding, string outputPrefix,
|
||||
string outputPath, Dictionary<string, string> formatOptions,
|
||||
CICMMetadataType preSidecar, uint skip,
|
||||
bool nometadata)
|
||||
{
|
||||
bool sense;
|
||||
ulong blocks;
|
||||
@@ -152,12 +151,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
mediaTags = new Dictionary<MediaTagType, byte[]>();
|
||||
|
||||
if(dev.IsUsb && dev.UsbDescriptors != null)
|
||||
mediaTags.Add(MediaTagType.USB_Descriptors, null);
|
||||
if(dev.Type == DeviceType.ATAPI)
|
||||
mediaTags.Add(MediaTagType.ATAPI_IDENTIFY, null);
|
||||
if(dev.IsPcmcia && dev.Cis != null)
|
||||
mediaTags.Add(MediaTagType.PCMCIA_CIS, null);
|
||||
if(dev.IsUsb && dev.UsbDescriptors != null) mediaTags.Add(MediaTagType.USB_Descriptors, null);
|
||||
if(dev.Type == DeviceType.ATAPI) mediaTags.Add(MediaTagType.ATAPI_IDENTIFY, null);
|
||||
if(dev.IsPcmcia && dev.Cis != null) mediaTags.Add(MediaTagType.PCMCIA_CIS, null);
|
||||
|
||||
sense = dev.ScsiInquiry(out byte[] cmdBuf, out _);
|
||||
mediaTags.Add(MediaTagType.SCSI_INQUIRY, cmdBuf);
|
||||
@@ -413,10 +409,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.WriteLine();
|
||||
mhddLog.Close();
|
||||
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
|
||||
blockSize * (double)(blocks + 1) /
|
||||
1024 / (totalDuration / 1000), devicePath);
|
||||
dumpLog.WriteLine("Dump finished in {0} seconds.",
|
||||
(end - start).TotalSeconds);
|
||||
blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000),
|
||||
devicePath);
|
||||
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
|
||||
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
|
||||
(double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000));
|
||||
dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
|
||||
@@ -429,49 +424,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
bool forward = true;
|
||||
bool runningPersistent = false;
|
||||
|
||||
repeatRetry:
|
||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||
foreach(ulong badSector in tmpArray)
|
||||
{
|
||||
if(aborted)
|
||||
{
|
||||
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
|
||||
dumpLog.WriteLine("Aborted!");
|
||||
break;
|
||||
}
|
||||
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1,
|
||||
forward ? "forward" : "reverse",
|
||||
runningPersistent ? "recovering partial data, " : "");
|
||||
|
||||
sense = scsiReader.ReadBlock(out readBuffer, badSector, out double cmdDuration);
|
||||
totalDuration += cmdDuration;
|
||||
|
||||
if(!sense && !dev.Error)
|
||||
{
|
||||
resume.BadBlocks.Remove(badSector);
|
||||
extents.Add(badSector);
|
||||
outputPlugin.WriteSector(readBuffer, badSector);
|
||||
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
|
||||
}
|
||||
else if(runningPersistent)
|
||||
outputPlugin.WriteSector(readBuffer, badSector);
|
||||
}
|
||||
|
||||
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
|
||||
{
|
||||
pass++;
|
||||
forward = !forward;
|
||||
resume.BadBlocks.Sort();
|
||||
resume.BadBlocks.Reverse();
|
||||
goto repeatRetry;
|
||||
}
|
||||
|
||||
Modes.ModePage? currentModePage = null;
|
||||
byte[] md6;
|
||||
byte[] md10;
|
||||
|
||||
if(!runningPersistent && persistent)
|
||||
if(persistent)
|
||||
{
|
||||
if(dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
|
||||
{
|
||||
@@ -526,17 +483,57 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
dumpLog.WriteLine("Sending MODE SELECT to drive.");
|
||||
sense = dev.ModeSelect(md6, out _, true, false, dev.Timeout, out _);
|
||||
if(sense) sense = dev.ModeSelect10(md10, out _, true, false, dev.Timeout, out _);
|
||||
sense = dev.ModeSelect(md6, out byte[] senseBuf, true, false, dev.Timeout, out _);
|
||||
if(sense) sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out _);
|
||||
|
||||
if(sense)
|
||||
{
|
||||
DicConsole
|
||||
.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
|
||||
DicConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf));
|
||||
dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
|
||||
}
|
||||
else runningPersistent = true;
|
||||
}
|
||||
|
||||
repeatRetry:
|
||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||
foreach(ulong badSector in tmpArray)
|
||||
{
|
||||
if(aborted)
|
||||
{
|
||||
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
|
||||
dumpLog.WriteLine("Aborted!");
|
||||
break;
|
||||
}
|
||||
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1,
|
||||
forward ? "forward" : "reverse",
|
||||
runningPersistent ? "recovering partial data, " : "");
|
||||
|
||||
sense = scsiReader.ReadBlock(out readBuffer, badSector, out double cmdDuration);
|
||||
totalDuration += cmdDuration;
|
||||
|
||||
runningPersistent = true;
|
||||
if(!sense && !dev.Error)
|
||||
{
|
||||
pass--;
|
||||
resume.BadBlocks.Remove(badSector);
|
||||
extents.Add(badSector);
|
||||
outputPlugin.WriteSector(readBuffer, badSector);
|
||||
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
|
||||
}
|
||||
else if(runningPersistent) outputPlugin.WriteSector(readBuffer, badSector);
|
||||
}
|
||||
|
||||
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
|
||||
{
|
||||
pass++;
|
||||
forward = !forward;
|
||||
resume.BadBlocks.Sort();
|
||||
resume.BadBlocks.Reverse();
|
||||
goto repeatRetry;
|
||||
}
|
||||
}
|
||||
else if(runningPersistent && persistent && currentModePage.HasValue)
|
||||
|
||||
if(runningPersistent && currentModePage.HasValue)
|
||||
{
|
||||
Modes.DecodedMode md = new Modes.DecodedMode
|
||||
{
|
||||
@@ -872,12 +869,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
if(!dev.IsRemovable || dev.IsUsb)
|
||||
if(dev.Type == DeviceType.ATAPI)
|
||||
sidecar.BlockMedia[0].Interface = "ATAPI";
|
||||
else if(dev.IsUsb)
|
||||
sidecar.BlockMedia[0].Interface = "USB";
|
||||
else if(dev.IsFireWire)
|
||||
sidecar.BlockMedia[0].Interface = "FireWire";
|
||||
else
|
||||
sidecar.BlockMedia[0].Interface = "SCSI";
|
||||
else if(dev.IsUsb) sidecar.BlockMedia[0].Interface = "USB";
|
||||
else if(dev.IsFireWire) sidecar.BlockMedia[0].Interface = "FireWire";
|
||||
else sidecar.BlockMedia[0].Interface = "SCSI";
|
||||
sidecar.BlockMedia[0].LogicalBlocks = (long)blocks;
|
||||
sidecar.BlockMedia[0].PhysicalBlockSize = (int)physicalBlockSize;
|
||||
sidecar.BlockMedia[0].LogicalBlockSize = (int)logicalBlockSize;
|
||||
|
||||
Reference in New Issue
Block a user