[Dumping] Add paranoia mode to check integrity of sectors before writing them to the image.

This commit is contained in:
2025-11-23 13:05:43 +00:00
parent 0f78b128ac
commit 70f005f61f
9 changed files with 256 additions and 48 deletions

View File

@@ -47,6 +47,7 @@ using Aaru.Core.Logging;
using Aaru.Decoders.CD;
using Aaru.Decoders.SCSI;
using Aaru.Devices;
using Aaru.Localization;
using Aaru.Logging;
using Humanizer;
using Track = Aaru.CommonTypes.Structs.Track;
@@ -762,6 +763,7 @@ partial class Dump
mhddLog.Write(i + r, _speedStopwatch.Elapsed.TotalMilliseconds);
extents.Add(i + r, 1, true);
_writeStopwatch.Restart();
SectorStatus sectorStatus = SectorStatus.Dumped;
if(supportedSubchannel != MmcSubchannel.None)
{
@@ -772,14 +774,33 @@ partial class Dump
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
if(_paranoia)
{
// Check valid sector
CdChecksums.CheckCdSector(data,
out bool? correctEccP,
out bool? correctEccQ,
out bool? correctEdc);
if(correctEdc != true || correctEccP != true || correctEccQ != true)
{
sectorStatus = SectorStatus.Errored;
_resume.BadBlocks.Add(i + r);
if(correctEdc != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_EDC_in_sector_0, i + r));
if(correctEccP != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_P_in_sector_0, i + r));
if(correctEccQ != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_Q_in_sector_0, i + r));
}
}
if(supportsLongSectors)
{
outputFormat.WriteSectorsLong(data,
i + r,
false,
1,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
outputFormat.WriteSectorsLong(data, i + r, false, 1, [sectorStatus]);
}
else
{
@@ -797,8 +818,7 @@ partial class Dump
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
Enumerable.Repeat(sectorStatus, (int)blocksToRead).ToArray());
}
bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
@@ -844,8 +864,32 @@ partial class Dump
}
else
{
if(_paranoia)
{
// Check valid sector
CdChecksums.CheckCdSector(cmdBuf,
out bool? correctEccP,
out bool? correctEccQ,
out bool? correctEdc);
if(correctEdc != true || correctEccP != true || correctEccQ != true)
{
sectorStatus = SectorStatus.Errored;
_resume.BadBlocks.Add(i + r);
if(correctEdc != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_EDC_in_sector_0, i + r));
if(correctEccP != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_P_in_sector_0, i + r));
if(correctEccQ != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_Q_in_sector_0, i + r));
}
}
if(supportsLongSectors)
outputFormat.WriteSectorsLong(cmdBuf, i + r, false, 1, [SectorStatus.Dumped]);
outputFormat.WriteSectorsLong(cmdBuf, i + r, false, 1, [sectorStatus]);
else
{
var cooked = new MemoryStream();
@@ -862,8 +906,7 @@ partial class Dump
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
Enumerable.Repeat(sectorStatus, (int)blocksToRead).ToArray());
}
}
@@ -987,29 +1030,53 @@ partial class Dump
if(supportedSubchannel != MmcSubchannel.None)
{
var data = new byte[sectorSize * blocksToRead];
var sub = new byte[subSize * blocksToRead];
var data = new byte[sectorSize * blocksToRead];
var sub = new byte[subSize * blocksToRead];
var sectorStatus = new SectorStatus[blocksToRead];
var sector = new byte[sectorSize];
for(var b = 0; b < blocksToRead; b++)
{
Array.Copy(cmdBuf, (int)(0 + b * blockSize), data, sectorSize * b, sectorSize);
Array.Copy(cmdBuf, (int)(sectorSize + b * blockSize), sub, subSize * b, subSize);
Array.Copy(cmdBuf, (int)(0 + b * blockSize), sector, 0, sectorSize);
sectorStatus[b] = SectorStatus.Dumped;
if(inData && _paranoia)
{
// Check valid sector
CdChecksums.CheckCdSector(sector,
out bool? correctEccP,
out bool? correctEccQ,
out bool? correctEdc);
if(correctEdc != true || correctEccP != true || correctEccQ != true)
{
sectorStatus[b] = SectorStatus.Errored;
_resume.BadBlocks.Add(i + (ulong)b);
if(correctEdc != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_EDC_in_sector_0, i + (ulong)b));
if(correctEccP != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_P_in_sector_0, i + (ulong)b));
if(correctEccQ != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_Q_in_sector_0, i + (ulong)b));
}
}
}
if(supportsLongSectors)
{
outputFormat.WriteSectorsLong(data,
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead)
.ToArray());
outputFormat.WriteSectorsLong(data, i, false, blocksToRead, sectorStatus);
}
else
{
var cooked = new MemoryStream();
var sector = new byte[sectorSize];
for(var b = 0; b < blocksToRead; b++)
{
@@ -1018,11 +1085,7 @@ partial class Dump
cooked.Write(cookedSector, 0, cookedSector.Length);
}
outputFormat.WriteSectors(cooked.ToArray(),
i,
false,
blocksToRead,
Enumerable.Repeat(SectorStatus.Dumped, (int)blocksToRead).ToArray());
outputFormat.WriteSectors(cooked.ToArray(), i, false, blocksToRead, sectorStatus);
}
bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,

View File

@@ -47,6 +47,7 @@ using Aaru.Core.Logging;
using Aaru.Decoders.CD;
using Aaru.Decoders.SCSI;
using Aaru.Devices;
using Aaru.Localization;
using Aaru.Logging;
using Track = Aaru.CommonTypes.Structs.Track;
using TrackType = Aaru.CommonTypes.Enums.TrackType;
@@ -466,8 +467,9 @@ partial class Dump
// MEDIUM ERROR, retry with ignore error below
if(decSense is { ASC: 0x11 })
if(!sectorsNotEvenPartial.Contains(badSector))
sectorsNotEvenPartial.Add(badSector);
{
if(!sectorsNotEvenPartial.Contains(badSector)) sectorsNotEvenPartial.Add(badSector);
}
}
// Because one block has been partially used to fix the offset
@@ -486,17 +488,61 @@ partial class Dump
false);
}
SectorStatus sectorStatus = SectorStatus.Dumped;
if(!sense && !_dev.Error)
{
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_mediaGraph?.PaintSectorGood(badSector);
if(!audioExtents.Contains(badSector) && _paranoia)
{
var sector = new byte[sectorSize];
Array.Copy(cmdBuf, 0, sector, 0, sectorSize);
UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_sector_0_in_pass_1,
badSector,
pass));
// Check valid sector
CdChecksums.CheckCdSector(sector,
out bool? correctEccP,
out bool? correctEccQ,
out bool? correctEdc);
sectorsNotEvenPartial.Remove(badSector);
if(correctEdc != true || correctEccP != true || correctEccQ != true)
{
sectorStatus = SectorStatus.Errored;
_mediaGraph?.PaintSectorBad(badSector);
if(correctEdc != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_EDC_in_sector_0, badSector));
if(correctEccP != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_P_in_sector_0, badSector));
if(correctEccQ != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_Q_in_sector_0, badSector));
}
else
{
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_mediaGraph?.PaintSectorGood(badSector);
UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_sector_0_in_pass_1,
badSector,
pass));
sectorsNotEvenPartial.Remove(badSector);
}
}
else
{
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_mediaGraph?.PaintSectorGood(badSector);
UpdateStatus?.Invoke(string.Format(Localization.Core.Correctly_retried_sector_0_in_pass_1,
badSector,
pass));
sectorsNotEvenPartial.Remove(badSector);
}
}
else
_errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf.ToArray());
@@ -509,9 +555,9 @@ partial class Dump
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
if(supportsLongSectors)
outputOptical.WriteSectorLong(data, badSector, false, SectorStatus.Dumped);
outputOptical.WriteSectorLong(data, badSector, false, sectorStatus);
else
outputOptical.WriteSector(Sector.GetUserData(data), badSector, false, SectorStatus.Dumped);
outputOptical.WriteSector(Sector.GetUserData(data), badSector, false, sectorStatus);
bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
desiredSubchannel,
@@ -542,9 +588,9 @@ partial class Dump
else
{
if(supportsLongSectors)
outputOptical.WriteSectorLong(cmdBuf, badSector, false, SectorStatus.Dumped);
outputOptical.WriteSectorLong(cmdBuf, badSector, false, sectorStatus);
else
outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector, false, SectorStatus.Dumped);
outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector, false, sectorStatus);
}
}
@@ -697,10 +743,12 @@ partial class Dump
if(supportsLongSectors)
outputOptical.WriteSectorLong(cmdBuf, badSector, false, SectorStatus.Errored);
else
{
outputOptical.WriteSector(Sector.GetUserData(cmdBuf),
badSector,
false,
SectorStatus.Errored);
}
}
}

View File

@@ -46,6 +46,7 @@ using Aaru.Core.Logging;
using Aaru.Decoders.CD;
using Aaru.Decoders.SCSI;
using Aaru.Devices;
using Aaru.Localization;
using Humanizer;
using Track = Aaru.CommonTypes.Structs.Track;
@@ -392,11 +393,48 @@ partial class Dump
continue;
}
SectorStatus sectorStatus = SectorStatus.Dumped;
if(!sense && !_dev.Error)
{
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_mediaGraph?.PaintSectorGood(badSector);
if(!audioExtents.Contains(badSector) && _paranoia)
{
var sector = new byte[sectorSize];
Array.Copy(cmdBuf, 0, sector, 0, sectorSize);
// Check valid sector
CdChecksums.CheckCdSector(sector,
out bool? correctEccP,
out bool? correctEccQ,
out bool? correctEdc);
if(correctEdc != true || correctEccP != true || correctEccQ != true)
{
sectorStatus = SectorStatus.Errored;
_mediaGraph?.PaintSectorBad(badSector);
if(correctEdc != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_EDC_in_sector_0, badSector));
if(correctEccP != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_P_in_sector_0, badSector));
if(correctEccQ != true)
UpdateStatus?.Invoke(string.Format(UI.Incorrect_ECC_Q_in_sector_0, badSector));
}
else
{
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_mediaGraph?.PaintSectorGood(badSector);
}
}
else
{
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_mediaGraph?.PaintSectorGood(badSector);
}
}
// Because one block has been partially used to fix the offset
@@ -415,6 +453,7 @@ partial class Dump
false);
}
if(supportedSubchannel != MmcSubchannel.None)
{
var data = new byte[sectorSize];
@@ -423,9 +462,9 @@ partial class Dump
Array.Copy(cmdBuf, sectorSize, sub, 0, subSize);
if(supportsLongSectors)
outputOptical.WriteSectorLong(data, badSector, false, SectorStatus.Dumped);
outputOptical.WriteSectorLong(data, badSector, false, sectorStatus);
else
outputOptical.WriteSector(Sector.GetUserData(data), badSector, false, SectorStatus.Dumped);
outputOptical.WriteSector(Sector.GetUserData(data), badSector, false, sectorStatus);
ulong trkStartBefore = track.StartSector;
@@ -467,9 +506,9 @@ partial class Dump
}
if(supportsLongSectors)
outputOptical.WriteSectorLong(cmdBuf, badSector, false, SectorStatus.Dumped);
outputOptical.WriteSectorLong(cmdBuf, badSector, false, sectorStatus);
else
outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector, false, SectorStatus.Dumped);
outputOptical.WriteSector(Sector.GetUserData(cmdBuf), badSector, false, sectorStatus);
}
_trimStopwatch.Stop();