mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Scan blank blocks in magneto-optical disks before dumping, and do not treat them as errors. Fixes #316
This commit is contained in:
4
.idea/.idea.Aaru/.idea/contentModel.xml
generated
4
.idea/.idea.Aaru/.idea/contentModel.xml
generated
@@ -3,7 +3,8 @@
|
|||||||
<component name="ContentModelStore">
|
<component name="ContentModelStore">
|
||||||
<e p="$USER_HOME$/.cache/JetBrains/Rider2020.2/extResources" t="IncludeRecursive" />
|
<e p="$USER_HOME$/.cache/JetBrains/Rider2020.2/extResources" t="IncludeRecursive" />
|
||||||
<e p="$USER_HOME$/.cache/JetBrains/Rider2020.2/resharper-host/local/Transient/Rider/v202/SolutionCaches/_Aaru.232757112.00" t="ExcludeRecursive" />
|
<e p="$USER_HOME$/.cache/JetBrains/Rider2020.2/resharper-host/local/Transient/Rider/v202/SolutionCaches/_Aaru.232757112.00" t="ExcludeRecursive" />
|
||||||
<e p="$USER_HOME$/.config/git/ignore" t="IncludeRecursive" />
|
<e p="$APPLICATION_CONFIG_DIR$/consoles/db" t="IncludeRecursive" />
|
||||||
|
<e p="$APPLICATION_CONFIG_DIR$/extensions" t="IncludeRecursive" />
|
||||||
<e p="$APPLICATION_PLUGINS_DIR$/puppet/lib/stubs" t="IncludeRecursive" />
|
<e p="$APPLICATION_PLUGINS_DIR$/puppet/lib/stubs" t="IncludeRecursive" />
|
||||||
<e p="$USER_HOME$/.nuget/packages/microsoft.net.test.sdk/16.4.0/build/netcoreapp2.1" t="Include">
|
<e p="$USER_HOME$/.nuget/packages/microsoft.net.test.sdk/16.4.0/build/netcoreapp2.1" t="Include">
|
||||||
<e p="Microsoft.NET.Test.Sdk.Program.cs" t="Include" />
|
<e p="Microsoft.NET.Test.Sdk.Program.cs" t="Include" />
|
||||||
@@ -277,6 +278,7 @@
|
|||||||
<e p="Data.cs" t="Include" />
|
<e p="Data.cs" t="Include" />
|
||||||
<e p="Dump.cs" t="Include" />
|
<e p="Dump.cs" t="Include" />
|
||||||
<e p="Error.cs" t="Include" />
|
<e p="Error.cs" t="Include" />
|
||||||
|
<e p="Optical.cs" t="Include" />
|
||||||
<e p="Trim.cs" t="Include" />
|
<e p="Trim.cs" t="Include" />
|
||||||
</e>
|
</e>
|
||||||
<e p="SecureDigital.cs" t="Include" />
|
<e p="SecureDigital.cs" t="Include" />
|
||||||
|
|||||||
Submodule Aaru.CommonTypes updated: 3225283e04...f4eb9f5b4a
@@ -68,6 +68,7 @@
|
|||||||
<Compile Include="Devices\Dumping\Sbc\Data.cs" />
|
<Compile Include="Devices\Dumping\Sbc\Data.cs" />
|
||||||
<Compile Include="Devices\Dumping\Sbc\Error.cs" />
|
<Compile Include="Devices\Dumping\Sbc\Error.cs" />
|
||||||
<Compile Include="Devices\Dumping\Sbc\Dump.cs" />
|
<Compile Include="Devices\Dumping\Sbc\Dump.cs" />
|
||||||
|
<Compile Include="Devices\Dumping\Sbc\Optical.cs" />
|
||||||
<Compile Include="Devices\Dumping\Sbc\Trim.cs" />
|
<Compile Include="Devices\Dumping\Sbc\Trim.cs" />
|
||||||
<Compile Include="Devices\Info\DeviceInfo.cs" />
|
<Compile Include="Devices\Info\DeviceInfo.cs" />
|
||||||
<Compile Include="Devices\Info\Plextor.cs" />
|
<Compile Include="Devices\Info\Plextor.cs" />
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)",
|
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)",
|
||||||
(long)i, (long)blocks);
|
(long)i, (long)blocks);
|
||||||
|
|
||||||
bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration, out _);
|
bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration, out _, out _);
|
||||||
|
|
||||||
if(!error)
|
if(!error)
|
||||||
{
|
{
|
||||||
@@ -383,7 +383,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
PulseProgress?.Invoke($"Trimming sector {badSector}");
|
PulseProgress?.Invoke($"Trimming sector {badSector}");
|
||||||
|
|
||||||
bool error =
|
bool error =
|
||||||
ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError);
|
ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError, out _);
|
||||||
|
|
||||||
totalDuration += duration;
|
totalDuration += duration;
|
||||||
|
|
||||||
@@ -430,7 +430,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
_persistent ? "recovering partial data, " : ""));
|
_persistent ? "recovering partial data, " : ""));
|
||||||
|
|
||||||
bool error =
|
bool error =
|
||||||
ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError);
|
ataReader.ReadBlock(out cmdBuf, badSector, out duration, out recoveredError, out _);
|
||||||
|
|
||||||
totalDuration += duration;
|
totalDuration += duration;
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
byte[] buffer;
|
byte[] buffer;
|
||||||
uint blocksToRead = maxBlocksToRead;
|
uint blocksToRead = maxBlocksToRead;
|
||||||
|
|
||||||
|
InitProgress?.Invoke();
|
||||||
|
|
||||||
for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
|
for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
|
||||||
{
|
{
|
||||||
if(_aborted)
|
if(_aborted)
|
||||||
@@ -73,7 +75,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
|
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
|
||||||
(long)blocks);
|
(long)blocks);
|
||||||
|
|
||||||
sense = scsiReader.ReadBlocks(out buffer, i, blocksToRead, out double cmdDuration, out _);
|
sense = scsiReader.ReadBlocks(out buffer, i, blocksToRead, out double cmdDuration, out _, out _);
|
||||||
totalDuration += cmdDuration;
|
totalDuration += cmdDuration;
|
||||||
|
|
||||||
if(!sense &&
|
if(!sense &&
|
||||||
@@ -138,6 +140,8 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
sectorSpeedStart = 0;
|
sectorSpeedStart = 0;
|
||||||
timeSpeedStart = DateTime.UtcNow;
|
timeSpeedStart = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EndProgress?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,6 +81,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
byte[] readBuffer;
|
byte[] readBuffer;
|
||||||
Modes.DecodedMode? decMode = null;
|
Modes.DecodedMode? decMode = null;
|
||||||
bool ret;
|
bool ret;
|
||||||
|
ExtentsULong blankExtents = null;
|
||||||
|
|
||||||
if(opticalDisc)
|
if(opticalDisc)
|
||||||
switch(dskType)
|
switch(dskType)
|
||||||
@@ -591,15 +592,21 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
_dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _);
|
_dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool newTrim = false;
|
if(_resume?.BlankExtents != null)
|
||||||
InitProgress?.Invoke();
|
blankExtents = ExtentsConverter.FromMetadata(_resume.BlankExtents);
|
||||||
|
|
||||||
ReadSbcData(blocks, blocksToRead, blockSize, currentTry, extents, ref currentSpeed, ref minSpeed,
|
bool newTrim = false;
|
||||||
ref maxSpeed, ref totalDuration, scsiReader, mhddLog, ibgLog, ref imageWriteDuration,
|
|
||||||
ref newTrim);
|
if(_dev.ScsiType == PeripheralDeviceTypes.OpticalDevice)
|
||||||
|
ReadOpticalData(blocks, blocksToRead, blockSize, currentTry, extents, ref currentSpeed, ref minSpeed,
|
||||||
|
ref maxSpeed, ref totalDuration, scsiReader, mhddLog, ibgLog, ref imageWriteDuration,
|
||||||
|
ref newTrim, ref blankExtents);
|
||||||
|
else
|
||||||
|
ReadSbcData(blocks, blocksToRead, blockSize, currentTry, extents, ref currentSpeed, ref minSpeed,
|
||||||
|
ref maxSpeed, ref totalDuration, scsiReader, mhddLog, ibgLog, ref imageWriteDuration,
|
||||||
|
ref newTrim);
|
||||||
|
|
||||||
end = DateTime.UtcNow;
|
end = DateTime.UtcNow;
|
||||||
EndProgress?.Invoke();
|
|
||||||
mhddLog.Close();
|
mhddLog.Close();
|
||||||
|
|
||||||
ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
|
ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
|
||||||
@@ -633,7 +640,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
|
|
||||||
InitProgress?.Invoke();
|
InitProgress?.Invoke();
|
||||||
|
|
||||||
TrimSbcData(scsiReader, extents, currentTry);
|
TrimSbcData(scsiReader, extents, currentTry, blankExtents);
|
||||||
|
|
||||||
EndProgress?.Invoke();
|
EndProgress?.Invoke();
|
||||||
end = DateTime.UtcNow;
|
end = DateTime.UtcNow;
|
||||||
@@ -646,7 +653,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
if(_resume.BadBlocks.Count > 0 &&
|
if(_resume.BadBlocks.Count > 0 &&
|
||||||
!_aborted &&
|
!_aborted &&
|
||||||
_retryPasses > 0)
|
_retryPasses > 0)
|
||||||
RetrySbcData(scsiReader, currentTry, extents, ref totalDuration);
|
RetrySbcData(scsiReader, currentTry, extents, ref totalDuration, blankExtents);
|
||||||
#endregion Error handling
|
#endregion Error handling
|
||||||
|
|
||||||
if(!_aborted)
|
if(!_aborted)
|
||||||
|
|||||||
@@ -41,18 +41,19 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
partial class Dump
|
partial class Dump
|
||||||
{
|
{
|
||||||
void RetrySbcData(Reader scsiReader, DumpHardwareType currentTry, ExtentsULong extents,
|
void RetrySbcData(Reader scsiReader, DumpHardwareType currentTry, ExtentsULong extents,
|
||||||
ref double totalDuration)
|
ref double totalDuration, ExtentsULong blankExtents)
|
||||||
{
|
{
|
||||||
int pass = 1;
|
int pass = 1;
|
||||||
bool forward = true;
|
bool forward = true;
|
||||||
bool runningPersistent = false;
|
bool runningPersistent = false;
|
||||||
bool sense;
|
bool sense;
|
||||||
byte[] buffer;
|
byte[] buffer;
|
||||||
bool recoveredError;
|
bool recoveredError;
|
||||||
|
|
||||||
Modes.ModePage? currentModePage = null;
|
Modes.ModePage? currentModePage = null;
|
||||||
byte[] md6;
|
byte[] md6;
|
||||||
byte[] md10;
|
byte[] md10;
|
||||||
|
bool blankCheck;
|
||||||
|
bool newBlank = false;
|
||||||
|
|
||||||
if(_persistent)
|
if(_persistent)
|
||||||
{
|
{
|
||||||
@@ -231,9 +232,23 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
forward ? "forward" : "reverse",
|
forward ? "forward" : "reverse",
|
||||||
runningPersistent ? "recovering partial data, " : ""));
|
runningPersistent ? "recovering partial data, " : ""));
|
||||||
|
|
||||||
sense = scsiReader.ReadBlock(out buffer, badSector, out double cmdDuration, out recoveredError);
|
sense = scsiReader.ReadBlock(out buffer, badSector, out double cmdDuration, out recoveredError,
|
||||||
|
out blankCheck);
|
||||||
|
|
||||||
totalDuration += cmdDuration;
|
totalDuration += cmdDuration;
|
||||||
|
|
||||||
|
if(blankCheck)
|
||||||
|
{
|
||||||
|
_resume.BadBlocks.Remove(badSector);
|
||||||
|
blankExtents.Add(badSector, badSector);
|
||||||
|
newBlank = true;
|
||||||
|
|
||||||
|
UpdateStatus?.Invoke($"Found blank block {badSector} in pass {pass}.");
|
||||||
|
_dumpLog.WriteLine("Found blank block {0} in pass {1}.", badSector, pass);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if((!sense && !_dev.Error) || recoveredError)
|
if((!sense && !_dev.Error) || recoveredError)
|
||||||
{
|
{
|
||||||
_resume.BadBlocks.Remove(badSector);
|
_resume.BadBlocks.Remove(badSector);
|
||||||
@@ -284,6 +299,9 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
_dev.ModeSelect10(md10, out _, true, false, _dev.Timeout, out _);
|
_dev.ModeSelect10(md10, out _, true, false, _dev.Timeout, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(newBlank)
|
||||||
|
_resume.BlankExtents = ExtentsConverter.ToMetadata(blankExtents);
|
||||||
|
|
||||||
EndProgress?.Invoke();
|
EndProgress?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
227
Aaru.Core/Devices/Dumping/Sbc/Optical.cs
Normal file
227
Aaru.Core/Devices/Dumping/Sbc/Optical.cs
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
using System;
|
||||||
|
using Aaru.CommonTypes.Extents;
|
||||||
|
using Aaru.Console;
|
||||||
|
using Aaru.Core.Logging;
|
||||||
|
using Schemas;
|
||||||
|
|
||||||
|
// ReSharper disable JoinDeclarationAndInitializer
|
||||||
|
// ReSharper disable InlineOutVariableDeclaration
|
||||||
|
// ReSharper disable TooWideLocalVariableScope
|
||||||
|
|
||||||
|
namespace Aaru.Core.Devices.Dumping
|
||||||
|
{
|
||||||
|
partial class Dump
|
||||||
|
{
|
||||||
|
void ReadOpticalData(in ulong blocks, in uint maxBlocksToRead, in uint blockSize, DumpHardwareType currentTry,
|
||||||
|
ExtentsULong extents, ref double currentSpeed, ref double minSpeed, ref double maxSpeed,
|
||||||
|
ref double totalDuration, Reader scsiReader, MhddLog mhddLog, IbgLog ibgLog,
|
||||||
|
ref double imageWriteDuration, ref bool newTrim, ref ExtentsULong blankExtents)
|
||||||
|
{
|
||||||
|
const uint maxBlocks = 256;
|
||||||
|
var writtenExtents = new ExtentsULong();
|
||||||
|
bool written;
|
||||||
|
uint c = maxBlocks;
|
||||||
|
bool conditionMet;
|
||||||
|
bool changingCounter;
|
||||||
|
bool changingWritten;
|
||||||
|
uint blocksToRead = maxBlocksToRead;
|
||||||
|
bool sense;
|
||||||
|
byte[] buffer;
|
||||||
|
ulong sectorSpeedStart = 0;
|
||||||
|
DateTime timeSpeedStart = DateTime.UtcNow;
|
||||||
|
|
||||||
|
InitProgress?.Invoke();
|
||||||
|
|
||||||
|
if(blankExtents is null)
|
||||||
|
{
|
||||||
|
blankExtents = new ExtentsULong();
|
||||||
|
|
||||||
|
written = _dev.MediumScan(out buffer, true, false, false, false, false, 0, 1, 1, out _, out _,
|
||||||
|
uint.MaxValue, out _);
|
||||||
|
|
||||||
|
// TODO: Find a place where MEDIUM SCAN works properly
|
||||||
|
if(buffer?.Length > 0)
|
||||||
|
AaruConsole.
|
||||||
|
WriteLine("Please open a bug report in github with the manufacturer and model of this device, as well as your operating system name and version and this message: This environment correctly supports MEDIUM SCAN command.");
|
||||||
|
|
||||||
|
changingCounter = false;
|
||||||
|
changingWritten = false;
|
||||||
|
|
||||||
|
for(uint b = 0; b < blocks; b += c)
|
||||||
|
{
|
||||||
|
if(_aborted)
|
||||||
|
{
|
||||||
|
_resume.BlankExtents = null;
|
||||||
|
UpdateStatus?.Invoke("Aborted!");
|
||||||
|
_dumpLog.WriteLine("Aborted!");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(changingWritten)
|
||||||
|
{
|
||||||
|
changingWritten = false;
|
||||||
|
written = !written;
|
||||||
|
c = maxBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(changingCounter)
|
||||||
|
{
|
||||||
|
b -= c;
|
||||||
|
changingCounter = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(b + c >= blocks)
|
||||||
|
c = (uint)(blocks - b);
|
||||||
|
|
||||||
|
UpdateProgress?.
|
||||||
|
Invoke($"Scanning for {c} {(written ? "written" : "blank")} blocks starting in block {b}", b,
|
||||||
|
(long)blocks);
|
||||||
|
|
||||||
|
conditionMet = _dev.MediumScan(out _, written, false, false, false, false, b, c, c, out _, out _,
|
||||||
|
uint.MaxValue, out _);
|
||||||
|
|
||||||
|
if(conditionMet)
|
||||||
|
{
|
||||||
|
if(written)
|
||||||
|
writtenExtents.Add(b, c, true);
|
||||||
|
else
|
||||||
|
blankExtents.Add(b, c, true);
|
||||||
|
|
||||||
|
if(c < maxBlocks)
|
||||||
|
changingWritten = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(c > 64)
|
||||||
|
c /= 2;
|
||||||
|
else
|
||||||
|
c--;
|
||||||
|
|
||||||
|
changingCounter = true;
|
||||||
|
|
||||||
|
if(c != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
written = !written;
|
||||||
|
c = maxBlocks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_resume != null)
|
||||||
|
_resume.BlankExtents = ExtentsConverter.ToMetadata(blankExtents);
|
||||||
|
|
||||||
|
EndProgress?.Invoke();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writtenExtents.Add(0, blocks - 1);
|
||||||
|
|
||||||
|
foreach(Tuple<ulong, ulong> blank in blankExtents.ToArray())
|
||||||
|
for(ulong b = blank.Item1; b <= blank.Item2; b++)
|
||||||
|
writtenExtents.Remove(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(writtenExtents.Count == 0)
|
||||||
|
{
|
||||||
|
UpdateStatus?.Invoke("Cannot dump empty media!");
|
||||||
|
_dumpLog.WriteLine("Cannot dump empty media!");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitProgress?.Invoke();
|
||||||
|
|
||||||
|
Tuple<ulong, ulong>[] extentsToDump = writtenExtents.ToArray();
|
||||||
|
|
||||||
|
foreach(Tuple<ulong, ulong> extent in extentsToDump)
|
||||||
|
{
|
||||||
|
if(extent.Item2 < _resume.NextBlock)
|
||||||
|
continue; // Skip this extent
|
||||||
|
|
||||||
|
ulong nextBlock = extent.Item1;
|
||||||
|
|
||||||
|
if(extent.Item1 < _resume.NextBlock)
|
||||||
|
nextBlock = (uint)_resume.NextBlock;
|
||||||
|
|
||||||
|
for(ulong i = nextBlock; i <= extent.Item2; i += blocksToRead)
|
||||||
|
{
|
||||||
|
if(_aborted)
|
||||||
|
{
|
||||||
|
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
|
||||||
|
UpdateStatus?.Invoke("Aborted!");
|
||||||
|
_dumpLog.WriteLine("Aborted!");
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((extent.Item2 + 1) - i < blocksToRead)
|
||||||
|
blocksToRead = (uint)((extent.Item2 + 1) - i);
|
||||||
|
|
||||||
|
if(currentSpeed > maxSpeed &&
|
||||||
|
currentSpeed > 0)
|
||||||
|
maxSpeed = currentSpeed;
|
||||||
|
|
||||||
|
if(currentSpeed < minSpeed &&
|
||||||
|
currentSpeed > 0)
|
||||||
|
minSpeed = currentSpeed;
|
||||||
|
|
||||||
|
UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
|
||||||
|
(long)blocks);
|
||||||
|
|
||||||
|
sense = scsiReader.ReadBlocks(out buffer, i, blocksToRead, out double cmdDuration, out _, out _);
|
||||||
|
totalDuration += cmdDuration;
|
||||||
|
|
||||||
|
if(!sense &&
|
||||||
|
!_dev.Error)
|
||||||
|
{
|
||||||
|
mhddLog.Write(i, cmdDuration);
|
||||||
|
ibgLog.Write(i, currentSpeed * 1024);
|
||||||
|
DateTime writeStart = DateTime.Now;
|
||||||
|
_outputPlugin.WriteSectors(buffer, i, blocksToRead);
|
||||||
|
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
|
||||||
|
extents.Add(i, blocksToRead, true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: Reset device after X errors
|
||||||
|
if(_stopOnError)
|
||||||
|
return; // TODO: Return more cleanly
|
||||||
|
|
||||||
|
if(i + _skip > extent.Item2 + 1)
|
||||||
|
_skip = (uint)((extent.Item2 + 1) - i);
|
||||||
|
|
||||||
|
// Write empty data
|
||||||
|
DateTime writeStart = DateTime.Now;
|
||||||
|
_outputPlugin.WriteSectors(new byte[blockSize * _skip], i, _skip);
|
||||||
|
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
|
||||||
|
|
||||||
|
for(ulong b = i; b < i + _skip; b++)
|
||||||
|
_resume.BadBlocks.Add(b);
|
||||||
|
|
||||||
|
mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
|
||||||
|
|
||||||
|
ibgLog.Write(i, 0);
|
||||||
|
_dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
|
||||||
|
i += _skip - blocksToRead;
|
||||||
|
newTrim = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sectorSpeedStart += blocksToRead;
|
||||||
|
_resume.NextBlock = i + blocksToRead;
|
||||||
|
|
||||||
|
double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
|
||||||
|
|
||||||
|
if(elapsed < 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
currentSpeed = (sectorSpeedStart * blockSize) / (1048576 * elapsed);
|
||||||
|
sectorSpeedStart = 0;
|
||||||
|
timeSpeedStart = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EndProgress?.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,12 +35,15 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
{
|
{
|
||||||
partial class Dump
|
partial class Dump
|
||||||
{
|
{
|
||||||
void TrimSbcData(Reader scsiReader, ExtentsULong extents, DumpHardwareType currentTry)
|
void TrimSbcData(Reader scsiReader, ExtentsULong extents, DumpHardwareType currentTry,
|
||||||
|
ExtentsULong blankExtents)
|
||||||
{
|
{
|
||||||
ulong[] tmpArray = _resume.BadBlocks.ToArray();
|
ulong[] tmpArray = _resume.BadBlocks.ToArray();
|
||||||
bool sense;
|
bool sense;
|
||||||
bool recoveredError;
|
bool recoveredError;
|
||||||
|
bool blankCheck;
|
||||||
byte[] buffer;
|
byte[] buffer;
|
||||||
|
bool newBlank = false;
|
||||||
|
|
||||||
foreach(ulong badSector in tmpArray)
|
foreach(ulong badSector in tmpArray)
|
||||||
{
|
{
|
||||||
@@ -55,7 +58,19 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
|
|
||||||
PulseProgress?.Invoke($"Trimming sector {badSector}");
|
PulseProgress?.Invoke($"Trimming sector {badSector}");
|
||||||
|
|
||||||
sense = scsiReader.ReadBlock(out buffer, badSector, out double _, out recoveredError);
|
sense = scsiReader.ReadBlock(out buffer, badSector, out double _, out recoveredError, out blankCheck);
|
||||||
|
|
||||||
|
if(blankCheck)
|
||||||
|
{
|
||||||
|
blankExtents.Add(badSector, badSector);
|
||||||
|
newBlank = true;
|
||||||
|
_resume.BadBlocks.Remove(badSector);
|
||||||
|
|
||||||
|
UpdateStatus?.Invoke($"Found blank block {badSector}.");
|
||||||
|
_dumpLog.WriteLine("Found blank block {0} in pass {1}.", badSector);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if((sense || _dev.Error) &&
|
if((sense || _dev.Error) &&
|
||||||
!recoveredError)
|
!recoveredError)
|
||||||
@@ -65,6 +80,9 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
extents.Add(badSector);
|
extents.Add(badSector);
|
||||||
_outputPlugin.WriteSector(buffer, badSector);
|
_outputPlugin.WriteSector(buffer, badSector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(newBlank)
|
||||||
|
_resume.BlankExtents = ExtentsConverter.ToMetadata(blankExtents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,24 +132,31 @@ namespace Aaru.Core.Devices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool ReadBlock(out byte[] buffer, ulong block, out double duration, out bool recoveredError) =>
|
internal bool ReadBlock(out byte[] buffer, ulong block, out double duration, out bool recoveredError,
|
||||||
ReadBlocks(out buffer, block, 1, out duration, out recoveredError);
|
out bool blankCheck) =>
|
||||||
|
ReadBlocks(out buffer, block, 1, out duration, out recoveredError, out blankCheck);
|
||||||
|
|
||||||
internal bool ReadBlocks(out byte[] buffer, ulong block, out double duration, out bool recoveredError) =>
|
internal bool ReadBlocks(out byte[] buffer, ulong block, out double duration, out bool recoveredError,
|
||||||
ReadBlocks(out buffer, block, BlocksToRead, out duration, out recoveredError);
|
out bool blankCheck) => ReadBlocks(out buffer, block, BlocksToRead, out duration,
|
||||||
|
out recoveredError, out blankCheck);
|
||||||
|
|
||||||
internal bool ReadBlocks(out byte[] buffer, ulong block, uint count, out double duration,
|
internal bool ReadBlocks(out byte[] buffer, ulong block, uint count, out double duration,
|
||||||
out bool recoveredError)
|
out bool recoveredError, out bool blankCheck)
|
||||||
{
|
{
|
||||||
switch(_dev.Type)
|
switch(_dev.Type)
|
||||||
{
|
{
|
||||||
case DeviceType.ATA: return AtaReadBlocks(out buffer, block, count, out duration, out recoveredError);
|
case DeviceType.ATA:
|
||||||
|
blankCheck = false;
|
||||||
|
|
||||||
|
return AtaReadBlocks(out buffer, block, count, out duration, out recoveredError);
|
||||||
case DeviceType.ATAPI:
|
case DeviceType.ATAPI:
|
||||||
case DeviceType.SCSI: return ScsiReadBlocks(out buffer, block, count, out duration, out recoveredError);
|
case DeviceType.SCSI:
|
||||||
|
return ScsiReadBlocks(out buffer, block, count, out duration, out recoveredError, out blankCheck);
|
||||||
default:
|
default:
|
||||||
buffer = null;
|
buffer = null;
|
||||||
duration = 0d;
|
duration = 0d;
|
||||||
recoveredError = false;
|
recoveredError = false;
|
||||||
|
blankCheck = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -571,13 +571,15 @@ namespace Aaru.Core.Devices
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ScsiReadBlocks(out byte[] buffer, ulong block, uint count, out double duration, out bool recoveredError)
|
bool ScsiReadBlocks(out byte[] buffer, ulong block, uint count, out double duration, out bool recoveredError,
|
||||||
|
out bool blankCheck)
|
||||||
{
|
{
|
||||||
bool sense;
|
bool sense;
|
||||||
byte[] senseBuf;
|
byte[] senseBuf;
|
||||||
buffer = null;
|
buffer = null;
|
||||||
duration = 0;
|
duration = 0;
|
||||||
recoveredError = false;
|
recoveredError = false;
|
||||||
|
blankCheck = false;
|
||||||
|
|
||||||
if(CanReadRaw)
|
if(CanReadRaw)
|
||||||
if(_readLong16)
|
if(_readLong16)
|
||||||
@@ -628,6 +630,9 @@ namespace Aaru.Core.Devices
|
|||||||
recoveredError = Sense.DecodeFixed(senseBuf)?.SenseKey == SenseKeys.RecoveredError ||
|
recoveredError = Sense.DecodeFixed(senseBuf)?.SenseKey == SenseKeys.RecoveredError ||
|
||||||
Sense.DecodeDescriptor(senseBuf)?.SenseKey == SenseKeys.RecoveredError;
|
Sense.DecodeDescriptor(senseBuf)?.SenseKey == SenseKeys.RecoveredError;
|
||||||
|
|
||||||
|
blankCheck = Sense.DecodeFixed(senseBuf)?.SenseKey == SenseKeys.BlankCheck ||
|
||||||
|
Sense.DecodeDescriptor(senseBuf)?.SenseKey == SenseKeys.BlankCheck;
|
||||||
|
|
||||||
AaruConsole.DebugWriteLine("SCSI Reader", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
|
AaruConsole.DebugWriteLine("SCSI Reader", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
|
||||||
|
|
||||||
return sense;
|
return sense;
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)",
|
UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)",
|
||||||
(long)i, (long)results.Blocks);
|
(long)i, (long)results.Blocks);
|
||||||
|
|
||||||
bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration, out _);
|
bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration, out _, out _);
|
||||||
|
|
||||||
if(!error)
|
if(!error)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,10 +52,11 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
MhddLog mhddLog;
|
MhddLog mhddLog;
|
||||||
IbgLog ibgLog;
|
IbgLog ibgLog;
|
||||||
byte[] senseBuf;
|
byte[] senseBuf;
|
||||||
bool sense = false;
|
bool sense = false;
|
||||||
|
uint blockSize = 0;
|
||||||
|
ushort currentProfile = 0x0001;
|
||||||
|
|
||||||
results.Blocks = 0;
|
results.Blocks = 0;
|
||||||
uint blockSize = 0;
|
|
||||||
ushort currentProfile = 0x0001;
|
|
||||||
|
|
||||||
if(_dev.IsRemovable)
|
if(_dev.IsRemovable)
|
||||||
{
|
{
|
||||||
@@ -481,7 +482,7 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)",
|
UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)",
|
||||||
(long)i, (long)results.Blocks);
|
(long)i, (long)results.Blocks);
|
||||||
|
|
||||||
sense = scsiReader.ReadBlocks(out _, i, blocksToRead, out double cmdDuration, out _);
|
sense = scsiReader.ReadBlocks(out _, i, blocksToRead, out double cmdDuration, out _, out _);
|
||||||
results.ProcessingTime += cmdDuration;
|
results.ProcessingTime += cmdDuration;
|
||||||
|
|
||||||
if(!sense &&
|
if(!sense &&
|
||||||
@@ -563,7 +564,7 @@ namespace Aaru.Core.Devices.Scanning
|
|||||||
if(scsiReader.CanSeek)
|
if(scsiReader.CanSeek)
|
||||||
scsiReader.Seek(seekPos, out seekCur);
|
scsiReader.Seek(seekPos, out seekCur);
|
||||||
else
|
else
|
||||||
scsiReader.ReadBlock(out _, seekPos, out seekCur, out _);
|
scsiReader.ReadBlock(out _, seekPos, out seekCur, out _, out _);
|
||||||
|
|
||||||
if(seekCur > results.SeekMax &&
|
if(seekCur > results.SeekMax &&
|
||||||
seekCur > 0)
|
seekCur > 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user