Split SBC dumping code in several files.

This commit is contained in:
2020-10-17 23:30:15 +01:00
parent 2d3720a9f5
commit 0fbebf367a
6 changed files with 519 additions and 377 deletions

View File

@@ -3,9 +3,6 @@
<component name="ContentModelStore">
<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="$APPLICATION_CONFIG_DIR$/consoles/db" t="IncludeRecursive" />
<e p="$APPLICATION_CONFIG_DIR$/extensions" t="IncludeRecursive" />
<e p="$APPLICATION_CONFIG_DIR$/scratches" t="IncludeRecursive" />
<e p="$USER_HOME$/.config/git/ignore" 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">
@@ -16,16 +13,6 @@
<e p="$USER_HOME$/.nuget/packages/nunit3testadapter/3.15.1/build/netcoreapp2.0/nunit.engine.api.dll" t="Include" />
<e p="$USER_HOME$/.nuget/packages/nunit3testadapter/3.15.1/build/netcoreapp2.0/nunit.engine.dll" t="Include" />
<e p="$PROJECT_DIR$" t="IncludeFlat">
<e p=".git/info/exclude" t="IncludeRecursive" />
<e p=".git/modules/Aaru.Checksums/info/exclude" t="IncludeRecursive" />
<e p=".git/modules/Aaru.CommonTypes/info/exclude" t="IncludeRecursive" />
<e p=".git/modules/Aaru.Console/info/exclude" t="IncludeRecursive" />
<e p=".git/modules/Aaru.Decoders/info/exclude" t="IncludeRecursive" />
<e p=".git/modules/Aaru.Dto/info/exclude" t="IncludeRecursive" />
<e p=".git/modules/Aaru.Helpers/info/exclude" t="IncludeRecursive" />
<e p=".git/modules/CICMMetadata/info/exclude" t="IncludeRecursive" />
<e p=".git/modules/cuetools.net/info/exclude" t="IncludeRecursive" />
<e p=".git/modules/cuetoolsnet/info/exclude" t="IncludeRecursive" />
<e p=".github/CODE_OF_CONDUCT.md" t="Include" />
<e p=".github/ISSUE_TEMPLATE.md" t="Include" />
<e p=".github/PULL_REQUEST_TEMPLATE.md" t="Include" />
@@ -284,9 +271,14 @@
<e p="UMD.cs" t="Include" />
</e>
<e p="ResumeSupport.cs" t="Include" />
<e p="SBC.cs" t="Include" />
<e p="SCSI.cs" t="Include" />
<e p="SSC.cs" t="Include" />
<e p="Sbc" t="Include">
<e p="Data.cs" t="Include" />
<e p="Dump.cs" t="Include" />
<e p="Error.cs" t="Include" />
<e p="Trim.cs" t="Include" />
</e>
<e p="SecureDigital.cs" t="Include" />
<e p="XGD.cs" t="Include" />
</e>

View File

@@ -65,6 +65,10 @@
<Compile Include="Devices\Dumping\PlayStationPortable\MemoryStick.cs" />
<Compile Include="Devices\Dumping\PlayStationPortable\PlayStationPortable.cs" />
<Compile Include="Devices\Dumping\PlayStationPortable\UMD.cs" />
<Compile Include="Devices\Dumping\Sbc\Data.cs" />
<Compile Include="Devices\Dumping\Sbc\Error.cs" />
<Compile Include="Devices\Dumping\Sbc\Dump.cs" />
<Compile Include="Devices\Dumping\Sbc\Trim.cs" />
<Compile Include="Devices\Info\DeviceInfo.cs" />
<Compile Include="Devices\Info\Plextor.cs" />
<Compile Include="Devices\Info\Properties.cs" />
@@ -116,7 +120,6 @@
<Compile Include="Devices\ReaderSCSI.cs" />
<Compile Include="Devices\Dumping\SSC.cs" />
<Compile Include="Devices\Dumping\MMC.cs" />
<Compile Include="Devices\Dumping\SBC.cs" />
<Compile Include="Devices\Dumping\XGD.cs" />
<Compile Include="Devices\Dumping\ResumeSupport.cs" />
<Compile Include="Partitions.cs" />

View File

@@ -0,0 +1,143 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Data.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System;
using Aaru.CommonTypes.Extents;
using Aaru.Core.Logging;
using Schemas;
// ReSharper disable JoinDeclarationAndInitializer
// ReSharper disable InlineOutVariableDeclaration
// ReSharper disable TooWideLocalVariableScope
namespace Aaru.Core.Devices.Dumping
{
partial class Dump
{
void ReadSbcData(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)
{
ulong sectorSpeedStart = 0;
bool sense;
DateTime timeSpeedStart = DateTime.UtcNow;
byte[] buffer;
uint blocksToRead = maxBlocksToRead;
for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
{
if(_aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
_dumpLog.WriteLine("Aborted!");
break;
}
if(blocks - i < blocksToRead)
blocksToRead = (uint)(blocks - 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 _);
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
{
if(_dev.Manufacturer.ToLowerInvariant() == "insite")
{
_resume.BadBlocks.Add(i);
_resume.NextBlock++;
_aborted = true;
_dumpLog?.
WriteLine("INSITE floptical drives get crazy on the SCSI bus when an error is found, stopping so you can reboot the computer or reset the scsi bus appropriately.");
UpdateStatus?.
Invoke("INSITE floptical drives get crazy on the SCSI bus when an error is found, stopping so you can reboot the computer or reset the scsi bus appropriately");
continue;
}
// TODO: Reset device after X errors
if(_stopOnError)
return; // TODO: Return more cleanly
if(i + _skip > blocks)
_skip = (uint)(blocks - 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;
}
}
}
}

View File

@@ -81,7 +81,6 @@ namespace Aaru.Core.Devices.Dumping
byte[] readBuffer;
Modes.DecodedMode? decMode = null;
bool ret;
bool recoveredError;
if(opticalDisc)
switch(dskType)
@@ -592,101 +591,12 @@ namespace Aaru.Core.Devices.Dumping
_dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, (ushort)_speed, 0, _dev.Timeout, out _);
}
bool newTrim = false;
DateTime timeSpeedStart = DateTime.UtcNow;
ulong sectorSpeedStart = 0;
bool newTrim = false;
InitProgress?.Invoke();
for(ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
{
if(_aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
_dumpLog.WriteLine("Aborted!");
break;
}
if(blocks - i < blocksToRead)
blocksToRead = (uint)(blocks - 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 readBuffer, i, blocksToRead, out double cmdDuration, out _);
totalDuration += cmdDuration;
if(!sense &&
!_dev.Error)
{
mhddLog.Write(i, cmdDuration);
ibgLog.Write(i, currentSpeed * 1024);
DateTime writeStart = DateTime.Now;
_outputPlugin.WriteSectors(readBuffer, i, blocksToRead);
imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
extents.Add(i, blocksToRead, true);
}
else
{
if(_dev.Manufacturer.ToLowerInvariant() == "insite")
{
_resume.BadBlocks.Add(i);
_resume.NextBlock++;
_aborted = true;
_dumpLog?.
WriteLine("INSITE floptical drives get crazy on the SCSI bus when an error is found, stopping so you can reboot the computer or reset the scsi bus appropriately.");
UpdateStatus?.
Invoke("INSITE floptical drives get crazy on the SCSI bus when an error is found, stopping so you can reboot the computer or reset the scsi bus appropriately");
continue;
}
// TODO: Reset device after X errors
if(_stopOnError)
return; // TODO: Return more cleanly
if(i + _skip > blocks)
_skip = (uint)(blocks - 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;
}
ReadSbcData(blocks, blocksToRead, blockSize, currentTry, extents, ref currentSpeed, ref minSpeed,
ref maxSpeed, ref totalDuration, scsiReader, mhddLog, ibgLog, ref imageWriteDuration,
ref newTrim);
end = DateTime.UtcNow;
EndProgress?.Invoke();
@@ -721,32 +631,9 @@ namespace Aaru.Core.Devices.Dumping
UpdateStatus?.Invoke("Trimming skipped sectors");
_dumpLog.WriteLine("Trimming skipped sectors");
ulong[] tmpArray = _resume.BadBlocks.ToArray();
InitProgress?.Invoke();
foreach(ulong badSector in tmpArray)
{
if(_aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
_dumpLog.WriteLine("Aborted!");
break;
}
PulseProgress?.Invoke($"Trimming sector {badSector}");
sense = scsiReader.ReadBlock(out readBuffer, badSector, out double _, out recoveredError);
if((sense || _dev.Error) &&
!recoveredError)
continue;
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_outputPlugin.WriteSector(readBuffer, badSector);
}
TrimSbcData(scsiReader, extents, currentTry);
EndProgress?.Invoke();
end = DateTime.UtcNow;
@@ -759,248 +646,7 @@ namespace Aaru.Core.Devices.Dumping
if(_resume.BadBlocks.Count > 0 &&
!_aborted &&
_retryPasses > 0)
{
int pass = 1;
bool forward = true;
bool runningPersistent = false;
Modes.ModePage? currentModePage = null;
byte[] md6;
byte[] md10;
if(_persistent)
{
Modes.ModePage_01_MMC pgMmc;
Modes.ModePage_01 pg;
sense = _dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01,
_dev.Timeout, out _);
if(sense)
{
sense = _dev.ModeSense10(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01,
_dev.Timeout, out _);
if(!sense)
{
Modes.DecodedMode? dcMode10 = Modes.DecodeMode10(readBuffer, _dev.ScsiType);
if(dcMode10?.Pages != null)
foreach(Modes.ModePage modePage in dcMode10.Value.Pages.Where(modePage =>
modePage.Page == 0x01 && modePage.Subpage == 0x00))
currentModePage = modePage;
}
}
else
{
Modes.DecodedMode? dcMode6 = Modes.DecodeMode6(readBuffer, _dev.ScsiType);
if(dcMode6?.Pages != null)
foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage =>
modePage.Page == 0x01 && modePage.Subpage == 0x00))
currentModePage = modePage;
}
if(currentModePage == null)
{
if(_dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
{
pgMmc = new Modes.ModePage_01_MMC
{
PS = false,
ReadRetryCount = 32,
Parameter = 0x00
};
currentModePage = new Modes.ModePage
{
Page = 0x01,
Subpage = 0x00,
PageResponse = Modes.EncodeModePage_01_MMC(pgMmc)
};
}
else
{
pg = new Modes.ModePage_01
{
PS = false,
AWRE = true,
ARRE = true,
TB = false,
RC = false,
EER = true,
PER = false,
DTE = true,
DCR = false,
ReadRetryCount = 32
};
currentModePage = new Modes.ModePage
{
Page = 0x01,
Subpage = 0x00,
PageResponse = Modes.EncodeModePage_01(pg)
};
}
}
if(_dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
{
pgMmc = new Modes.ModePage_01_MMC
{
PS = false,
ReadRetryCount = 255,
Parameter = 0x20
};
var 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);
}
else
{
pg = new Modes.ModePage_01
{
PS = false,
AWRE = false,
ARRE = false,
TB = true,
RC = false,
EER = true,
PER = false,
DTE = false,
DCR = false,
ReadRetryCount = 255
};
var md = new Modes.DecodedMode
{
Header = new Modes.ModeHeader(),
Pages = new[]
{
new Modes.ModePage
{
Page = 0x01,
Subpage = 0x00,
PageResponse = Modes.EncodeModePage_01(pg)
}
}
};
md6 = Modes.EncodeMode6(md, _dev.ScsiType);
md10 = Modes.EncodeMode10(md, _dev.ScsiType);
}
UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks).");
_dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks).");
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)
{
UpdateStatus?.
Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
AaruConsole.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;
}
}
InitProgress?.Invoke();
repeatRetry:
ulong[] tmpArray = _resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(_aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
_dumpLog.WriteLine("Aborted!");
break;
}
PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass,
forward ? "forward" : "reverse",
runningPersistent ? "recovering partial data, " : ""));
sense = scsiReader.ReadBlock(out readBuffer, badSector, out double cmdDuration, out recoveredError);
totalDuration += cmdDuration;
if((!sense && !_dev.Error) || recoveredError)
{
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_outputPlugin.WriteSector(readBuffer, badSector);
UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}.");
_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();
if(!forward)
_resume.BadBlocks.Reverse();
goto repeatRetry;
}
if(runningPersistent && currentModePage.HasValue)
{
var md = new Modes.DecodedMode
{
Header = new Modes.ModeHeader(),
Pages = new[]
{
currentModePage.Value
}
};
md6 = Modes.EncodeMode6(md, _dev.ScsiType);
md10 = Modes.EncodeMode10(md, _dev.ScsiType);
UpdateStatus?.Invoke("Sending MODE SELECT to drive (return device to previous status).");
_dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status).");
sense = _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _);
if(sense)
_dev.ModeSelect10(md10, out _, true, false, _dev.Timeout, out _);
}
EndProgress?.Invoke();
}
RetrySbcData(scsiReader, currentTry, extents, ref totalDuration);
#endregion Error handling
if(!_aborted)
@@ -1352,8 +998,6 @@ namespace Aaru.Core.Devices.Dumping
sense = _dev.ModeSense10(out cmdBuf, out _, false, true,
ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out _);
decMode = null;
if(!sense &&
!_dev.Error)
if(Modes.DecodeMode10(cmdBuf, _dev.ScsiType).HasValue)

View File

@@ -0,0 +1,290 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Error.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using System.Linq;
using Aaru.CommonTypes.Extents;
using Aaru.CommonTypes.Structs.Devices.SCSI;
using Aaru.Console;
using Aaru.Decoders.SCSI;
using Aaru.Devices;
using Schemas;
// ReSharper disable JoinDeclarationAndInitializer
// ReSharper disable InlineOutVariableDeclaration
// ReSharper disable TooWideLocalVariableScope
namespace Aaru.Core.Devices.Dumping
{
partial class Dump
{
void RetrySbcData(Reader scsiReader, DumpHardwareType currentTry, ExtentsULong extents,
ref double totalDuration)
{
int pass = 1;
bool forward = true;
bool runningPersistent = false;
bool sense;
byte[] buffer;
bool recoveredError;
Modes.ModePage? currentModePage = null;
byte[] md6;
byte[] md10;
if(_persistent)
{
Modes.ModePage_01_MMC pgMmc;
Modes.ModePage_01 pg;
sense = _dev.ModeSense6(out buffer, out _, false, ScsiModeSensePageControl.Current, 0x01, _dev.Timeout,
out _);
if(sense)
{
sense = _dev.ModeSense10(out buffer, out _, false, ScsiModeSensePageControl.Current, 0x01,
_dev.Timeout, out _);
if(!sense)
{
Modes.DecodedMode? dcMode10 = Modes.DecodeMode10(buffer, _dev.ScsiType);
if(dcMode10?.Pages != null)
foreach(Modes.ModePage modePage in dcMode10.Value.Pages.Where(modePage =>
modePage.Page == 0x01 && modePage.Subpage == 0x00))
currentModePage = modePage;
}
}
else
{
Modes.DecodedMode? dcMode6 = Modes.DecodeMode6(buffer, _dev.ScsiType);
if(dcMode6?.Pages != null)
foreach(Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage =>
modePage.Page == 0x01 && modePage.Subpage == 0x00))
currentModePage = modePage;
}
if(currentModePage == null)
{
if(_dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
{
pgMmc = new Modes.ModePage_01_MMC
{
PS = false,
ReadRetryCount = 32,
Parameter = 0x00
};
currentModePage = new Modes.ModePage
{
Page = 0x01,
Subpage = 0x00,
PageResponse = Modes.EncodeModePage_01_MMC(pgMmc)
};
}
else
{
pg = new Modes.ModePage_01
{
PS = false,
AWRE = true,
ARRE = true,
TB = false,
RC = false,
EER = true,
PER = false,
DTE = true,
DCR = false,
ReadRetryCount = 32
};
currentModePage = new Modes.ModePage
{
Page = 0x01,
Subpage = 0x00,
PageResponse = Modes.EncodeModePage_01(pg)
};
}
}
if(_dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
{
pgMmc = new Modes.ModePage_01_MMC
{
PS = false,
ReadRetryCount = 255,
Parameter = 0x20
};
var 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);
}
else
{
pg = new Modes.ModePage_01
{
PS = false,
AWRE = false,
ARRE = false,
TB = true,
RC = false,
EER = true,
PER = false,
DTE = false,
DCR = false,
ReadRetryCount = 255
};
var md = new Modes.DecodedMode
{
Header = new Modes.ModeHeader(),
Pages = new[]
{
new Modes.ModePage
{
Page = 0x01,
Subpage = 0x00,
PageResponse = Modes.EncodeModePage_01(pg)
}
}
};
md6 = Modes.EncodeMode6(md, _dev.ScsiType);
md10 = Modes.EncodeMode10(md, _dev.ScsiType);
}
UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks).");
_dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks).");
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)
{
UpdateStatus?.
Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
AaruConsole.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;
}
}
InitProgress?.Invoke();
repeatRetry:
ulong[] tmpArray = _resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(_aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
_dumpLog.WriteLine("Aborted!");
break;
}
PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass,
forward ? "forward" : "reverse",
runningPersistent ? "recovering partial data, " : ""));
sense = scsiReader.ReadBlock(out buffer, badSector, out double cmdDuration, out recoveredError);
totalDuration += cmdDuration;
if((!sense && !_dev.Error) || recoveredError)
{
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_outputPlugin.WriteSector(buffer, badSector);
UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}.");
_dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
}
else if(runningPersistent)
{
_outputPlugin.WriteSector(buffer, badSector);
}
}
if(pass < _retryPasses &&
!_aborted &&
_resume.BadBlocks.Count > 0)
{
pass++;
forward = !forward;
_resume.BadBlocks.Sort();
if(!forward)
_resume.BadBlocks.Reverse();
goto repeatRetry;
}
if(runningPersistent && currentModePage.HasValue)
{
var md = new Modes.DecodedMode
{
Header = new Modes.ModeHeader(),
Pages = new[]
{
currentModePage.Value
}
};
md6 = Modes.EncodeMode6(md, _dev.ScsiType);
md10 = Modes.EncodeMode10(md, _dev.ScsiType);
UpdateStatus?.Invoke("Sending MODE SELECT to drive (return device to previous status).");
_dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status).");
sense = _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _);
if(sense)
_dev.ModeSelect10(md10, out _, true, false, _dev.Timeout, out _);
}
EndProgress?.Invoke();
}
}
}

View File

@@ -0,0 +1,70 @@
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : Trim.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2011-2020 Natalia Portillo
// ****************************************************************************/
using Aaru.CommonTypes.Extents;
using Schemas;
// ReSharper disable JoinDeclarationAndInitializer
// ReSharper disable InlineOutVariableDeclaration
// ReSharper disable TooWideLocalVariableScope
namespace Aaru.Core.Devices.Dumping
{
partial class Dump
{
void TrimSbcData(Reader scsiReader, ExtentsULong extents, DumpHardwareType currentTry)
{
ulong[] tmpArray = _resume.BadBlocks.ToArray();
bool sense;
bool recoveredError;
byte[] buffer;
foreach(ulong badSector in tmpArray)
{
if(_aborted)
{
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
UpdateStatus?.Invoke("Aborted!");
_dumpLog.WriteLine("Aborted!");
break;
}
PulseProgress?.Invoke($"Trimming sector {badSector}");
sense = scsiReader.ReadBlock(out buffer, badSector, out double _, out recoveredError);
if((sense || _dev.Error) &&
!recoveredError)
continue;
_resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
_outputPlugin.WriteSector(buffer, badSector);
}
}
}
}