diff --git a/.idea/.idea.Aaru/.idea/contentModel.xml b/.idea/.idea.Aaru/.idea/contentModel.xml index c9f617210..ce5a26acc 100644 --- a/.idea/.idea.Aaru/.idea/contentModel.xml +++ b/.idea/.idea.Aaru/.idea/contentModel.xml @@ -5,8 +5,6 @@ - - @@ -16,6 +14,16 @@ + + + + + + + + + + @@ -316,6 +324,7 @@ + diff --git a/Aaru.Core/Aaru.Core.csproj b/Aaru.Core/Aaru.Core.csproj index c0897963c..9cb70a684 100644 --- a/Aaru.Core/Aaru.Core.csproj +++ b/Aaru.Core/Aaru.Core.csproj @@ -77,6 +77,7 @@ + diff --git a/Aaru.Core/Devices/Dumping/ATA.cs b/Aaru.Core/Devices/Dumping/ATA.cs index fb434c6de..5cf7912d0 100644 --- a/Aaru.Core/Devices/Dumping/ATA.cs +++ b/Aaru.Core/Devices/Dumping/ATA.cs @@ -39,11 +39,12 @@ using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Extents; using Aaru.CommonTypes.Interfaces; -using Aaru.CommonTypes.Structs.Devices.ATA; using Aaru.Core.Devices.Report; using Aaru.Core.Logging; +using Aaru.Decoders.ATA; using Aaru.Decoders.PCMCIA; using Schemas; +using Identify = Aaru.CommonTypes.Structs.Devices.ATA.Identify; using Tuple = Aaru.Decoders.PCMCIA.Tuple; using Version = Aaru.CommonTypes.Interop.Version; @@ -74,10 +75,11 @@ namespace Aaru.Core.Devices.Dumping UpdateStatus?.Invoke("Requesting ATA IDENTIFY DEVICE."); _dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE."); - bool sense = _dev.AtaIdentify(out byte[] cmdBuf, out _); + bool sense = _dev.AtaIdentify(out byte[] cmdBuf, out AtaErrorRegistersChs errorChs); - if(!sense && - Identify.Decode(cmdBuf).HasValue) + if(sense) + _errorLog?.WriteLine("ATA IDENTIFY DEVICE", _dev.Error, _dev.LastError, errorChs); + else if(Identify.Decode(cmdBuf).HasValue) { Identify.IdentifyDevice? ataIdNullable = Identify.Decode(cmdBuf); @@ -97,7 +99,7 @@ namespace Aaru.Core.Devices.Dumping // Initializate reader UpdateStatus?.Invoke("Initializing reader."); _dumpLog.WriteLine("Initializing reader."); - var ataReader = new Reader(_dev, TIMEOUT, ataIdentify); + var ataReader = new Reader(_dev, TIMEOUT, ataIdentify, _errorLog); // Fill reader blocks ulong blocks = ataReader.GetDeviceBlocks(); diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs b/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs index bfa17a88b..6d8614e5e 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/CdiReady.cs @@ -291,6 +291,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(i + r, _dev.Error, _dev.LastError, senseBuf); + leadOutExtents.Add(i + r, firstTrack.TrackStartSector - 1); UpdateStatus?. @@ -388,6 +390,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); + _resume.NextBlock = firstTrack.TrackStartSector; break; diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs index 443368e94..1f3d731cd 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Data.cs @@ -434,6 +434,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(i + r, _dev.Error, _dev.LastError, senseBuf); + // Write empty data DateTime writeStart = DateTime.Now; @@ -574,6 +576,8 @@ namespace Aaru.Core.Devices.Dumping continue; } + _errorLog?.WriteLine(firstSectorToRead, _dev.Error, _dev.LastError, senseBuf); + // TODO: Reset device after X errors if(_stopOnError) return; // TODO: Return more cleanly diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Error.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Error.cs index 7359e50ff..c1614a5d8 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Error.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Error.cs @@ -247,6 +247,8 @@ namespace Aaru.Core.Devices.Dumping if(sense || _dev.Error) { + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + if(!runningPersistent) continue; @@ -279,6 +281,8 @@ namespace Aaru.Core.Devices.Dumping _dumpLog.WriteLine("Correctly retried sector {0} in pass {1}.", badSector, pass); sectorsNotEvenPartial.Remove(badSector); } + else + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); if(supportedSubchannel != MmcSubchannel.None) { @@ -390,7 +394,11 @@ namespace Aaru.Core.Devices.Dumping } if(sense || _dev.Error) + { + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + continue; + } _dumpLog.WriteLine("Got partial data for sector {0} in pass {1}.", badSector, pass); @@ -541,7 +549,11 @@ namespace Aaru.Core.Devices.Dumping } if(sense || _dev.Error) + { + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + continue; + } WriteSubchannelToImage(supportedSubchannel, desiredSubchannel, cmdBuf, badSector, 5, subLog, isrcs, (byte)track.TrackSequence, ref mcn, tracks, subchannelExtents); diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/LeadOuts.cs b/Aaru.Core/Devices/Dumping/CompactDisc/LeadOuts.cs index b82061d90..c8eaf92e1 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/LeadOuts.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/LeadOuts.cs @@ -80,6 +80,7 @@ namespace Aaru.Core.Devices.Dumping byte[] cmdBuf = null; // Data buffer const uint sectorSize = 2352; // Full sector size bool sense = true; // Sense indicator + byte[] senseBuf = null; UpdateStatus?.Invoke("Reading lead-outs"); _dumpLog.WriteLine("Reading lead-outs"); @@ -117,23 +118,24 @@ namespace Aaru.Core.Devices.Dumping if(readcd) { - sense = _dev.ReadCd(out cmdBuf, out _, (uint)i, blockSize, 1, MmcSectorTypes.AllTypes, false, - false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, MmcSectorTypes.AllTypes, + false, false, true, MmcHeaderCodes.AllHeaders, true, true, + MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); totalDuration += cmdDuration; } else if(read16) - sense = _dev.Read16(out cmdBuf, out _, 0, false, true, false, i, blockSize, 0, 1, false, + sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, i, blockSize, 0, 1, false, _dev.Timeout, out cmdDuration); else if(read12) - sense = _dev.Read12(out cmdBuf, out _, 0, false, true, false, false, (uint)i, blockSize, 0, 1, - false, _dev.Timeout, out cmdDuration); + sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, + 0, 1, false, _dev.Timeout, out cmdDuration); else if(read10) - sense = _dev.Read10(out cmdBuf, out _, 0, false, true, false, false, (uint)i, blockSize, 0, 1, - _dev.Timeout, out cmdDuration); + sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, + 0, 1, _dev.Timeout, out cmdDuration); else if(read6) - sense = _dev.Read6(out cmdBuf, out _, (uint)i, blockSize, 1, _dev.Timeout, out cmdDuration); + sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, _dev.Timeout, + out cmdDuration); if(!sense && !_dev.Error) @@ -178,6 +180,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); + // TODO: Reset device after X errors if(_stopOnError) return; // TODO: Return more cleanly @@ -244,6 +248,7 @@ namespace Aaru.Core.Devices.Dumping byte[] cmdBuf = null; // Data buffer const uint sectorSize = 2352; // Full sector size bool sense = true; // Sense indicator + byte[] senseBuf = null; _dumpLog.WriteLine("Retrying lead-outs"); @@ -281,23 +286,24 @@ namespace Aaru.Core.Devices.Dumping if(readcd) { - sense = _dev.ReadCd(out cmdBuf, out _, (uint)i, blockSize, 1, MmcSectorTypes.AllTypes, false, - false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, - supportedSubchannel, _dev.Timeout, out cmdDuration); + sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, MmcSectorTypes.AllTypes, + false, false, true, MmcHeaderCodes.AllHeaders, true, true, + MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); totalDuration += cmdDuration; } else if(read16) - sense = _dev.Read16(out cmdBuf, out _, 0, false, true, false, i, blockSize, 0, 1, false, + sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, i, blockSize, 0, 1, false, _dev.Timeout, out cmdDuration); else if(read12) - sense = _dev.Read12(out cmdBuf, out _, 0, false, true, false, false, (uint)i, blockSize, 0, 1, - false, _dev.Timeout, out cmdDuration); + sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, + 0, 1, false, _dev.Timeout, out cmdDuration); else if(read10) - sense = _dev.Read10(out cmdBuf, out _, 0, false, true, false, false, (uint)i, blockSize, 0, 1, - _dev.Timeout, out cmdDuration); + sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, + 0, 1, _dev.Timeout, out cmdDuration); else if(read6) - sense = _dev.Read6(out cmdBuf, out _, (uint)i, blockSize, 1, _dev.Timeout, out cmdDuration); + sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, _dev.Timeout, + out cmdDuration); if(!sense && !_dev.Error) @@ -342,6 +348,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); + // TODO: Reset device after X errors if(_stopOnError) return; // TODO: Return more cleanly diff --git a/Aaru.Core/Devices/Dumping/CompactDisc/Trim.cs b/Aaru.Core/Devices/Dumping/CompactDisc/Trim.cs index 5323cdc73..a0a098285 100644 --- a/Aaru.Core/Devices/Dumping/CompactDisc/Trim.cs +++ b/Aaru.Core/Devices/Dumping/CompactDisc/Trim.cs @@ -62,6 +62,7 @@ namespace Aaru.Core.Devices.Dumping double cmdDuration = 0; // Command execution time const uint sectorSize = 2352; // Full sector size PlextorSubchannel supportedPlextorSubchannel; + byte[] senseBuf = null; switch(supportedSubchannel) { @@ -135,32 +136,36 @@ namespace Aaru.Core.Devices.Dumping if(_supportsPlextorD8 && audioExtents.Contains(badSector)) { - sense = ReadPlextorWithSubchannel(out cmdBuf, out _, badSectorToRead, blockSize, sectorsToTrim, - supportedPlextorSubchannel, out cmdDuration); + sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, badSectorToRead, blockSize, + sectorsToTrim, supportedPlextorSubchannel, out cmdDuration); totalDuration += cmdDuration; } else if(readcd) - sense = _dev.ReadCd(out cmdBuf, out _, badSectorToRead, blockSize, sectorsToTrim, + sense = _dev.ReadCd(out cmdBuf, out senseBuf, badSectorToRead, blockSize, sectorsToTrim, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); else if(read16) - sense = _dev.Read16(out cmdBuf, out _, 0, false, true, false, badSectorToRead, blockSize, 0, + sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, badSectorToRead, blockSize, 0, sectorsToTrim, false, _dev.Timeout, out cmdDuration); else if(read12) - sense = _dev.Read12(out cmdBuf, out _, 0, false, true, false, false, badSectorToRead, blockSize, 0, - sectorsToTrim, false, _dev.Timeout, out cmdDuration); + sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, badSectorToRead, + blockSize, 0, sectorsToTrim, false, _dev.Timeout, out cmdDuration); else if(read10) - sense = _dev.Read10(out cmdBuf, out _, 0, false, true, false, false, badSectorToRead, blockSize, 0, - sectorsToTrim, _dev.Timeout, out cmdDuration); + sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, badSectorToRead, + blockSize, 0, sectorsToTrim, _dev.Timeout, out cmdDuration); else if(read6) - sense = _dev.Read6(out cmdBuf, out _, badSectorToRead, blockSize, sectorsToTrim, _dev.Timeout, - out cmdDuration); + sense = _dev.Read6(out cmdBuf, out senseBuf, badSectorToRead, blockSize, sectorsToTrim, + _dev.Timeout, out cmdDuration); totalDuration += cmdDuration; if(sense || _dev.Error) + { + _errorLog?.WriteLine(badSectorToRead, _dev.Error, _dev.LastError, senseBuf); + continue; + } if(!sense && !_dev.Error) diff --git a/Aaru.Core/Devices/Dumping/Dump.cs b/Aaru.Core/Devices/Dumping/Dump.cs index 33771bef1..0b958f6f5 100644 --- a/Aaru.Core/Devices/Dumping/Dump.cs +++ b/Aaru.Core/Devices/Dumping/Dump.cs @@ -61,6 +61,7 @@ namespace Aaru.Core.Devices.Dumping readonly DumpLog _dumpLog; readonly bool _dumpRaw; readonly Encoding _encoding; + readonly ErrorLog _errorLog; readonly bool _fixSubchannel; readonly bool _fixSubchannelCrc; readonly bool _fixSubchannelPosition; @@ -119,7 +120,7 @@ namespace Aaru.Core.Devices.Dumping CICMMetadataType preSidecar, uint skip, bool metadata, bool trim, bool dumpFirstTrackPregap, bool fixOffset, bool debug, DumpSubchannel subchannel, int speed, bool @private, bool fixSubchannelPosition, bool retrySubchannel, bool fixSubchannel, bool fixSubchannelCrc, - bool skipCdireadyHole) + bool skipCdireadyHole, ErrorLog errorLog) { _doResume = doResume; _dev = dev; @@ -154,6 +155,7 @@ namespace Aaru.Core.Devices.Dumping _fixSubchannel = fixSubchannel; _fixSubchannelCrc = fixSubchannelCrc; _skipCdireadyHole = skipCdireadyHole; + _errorLog = errorLog; } /// Starts dumping with the stablished fields and autodetecting the device type @@ -215,6 +217,7 @@ namespace Aaru.Core.Devices.Dumping return; } + _errorLog.Close(); _dumpLog.Close(); if(_resume == null || diff --git a/Aaru.Core/Devices/Dumping/MMC.cs b/Aaru.Core/Devices/Dumping/MMC.cs index 79edd679d..1856f30f3 100644 --- a/Aaru.Core/Devices/Dumping/MMC.cs +++ b/Aaru.Core/Devices/Dumping/MMC.cs @@ -203,7 +203,7 @@ namespace Aaru.Core.Devices.Dumping _speedMultiplier *= 150; - var scsiReader = new Reader(_dev, _dev.Timeout, null, _dumpRaw); + var scsiReader = new Reader(_dev, _dev.Timeout, null, _errorLog, _dumpRaw); ulong blocks = scsiReader.GetDeviceBlocks(); _dumpLog.WriteLine("Device reports disc has {0} blocks", blocks); Dictionary mediaTags = new Dictionary(); diff --git a/Aaru.Core/Devices/Dumping/MiniDisc.cs b/Aaru.Core/Devices/Dumping/MiniDisc.cs index fd65ac609..8fe635887 100644 --- a/Aaru.Core/Devices/Dumping/MiniDisc.cs +++ b/Aaru.Core/Devices/Dumping/MiniDisc.cs @@ -72,7 +72,7 @@ namespace Aaru.Core.Devices.Dumping bool ret; _dumpLog.WriteLine("Initializing reader."); - var scsiReader = new Reader(_dev, _dev.Timeout, null); + var scsiReader = new Reader(_dev, _dev.Timeout, null, _errorLog); ulong blocks = scsiReader.GetDeviceBlocks(); uint blockSize = scsiReader.LogicalBlockSize; diff --git a/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs b/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs index fbdc040d1..90f68e313 100644 --- a/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs +++ b/Aaru.Core/Devices/Dumping/PlayStationPortable/MemoryStick.cs @@ -65,6 +65,7 @@ namespace Aaru.Core.Devices.Dumping DateTime end; MediaType dskType; bool sense; + byte[] senseBuf; sense = _dev.ReadCapacity(out byte[] readBuffer, out _, _dev.Timeout, out _); @@ -195,7 +196,7 @@ namespace Aaru.Core.Devices.Dumping UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, blocks); - sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)i, BLOCK_SIZE, 0, + sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)i, BLOCK_SIZE, 0, blocksToRead, false, _dev.Timeout, out double cmdDuration); totalDuration += cmdDuration; @@ -212,6 +213,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); + // TODO: Reset device after X errors if(_stopOnError) return; // TODO: Return more cleanly @@ -297,11 +300,15 @@ namespace Aaru.Core.Devices.Dumping PulseProgress?.Invoke($"Trimming sector {badSector}"); - sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)badSector, + sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)badSector, BLOCK_SIZE, 0, 1, false, _dev.Timeout, out double cmdDuration); if(sense || _dev.Error) + { + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + continue; + } _resume.BadBlocks.Remove(badSector); extents.Add(badSector); @@ -397,7 +404,7 @@ namespace Aaru.Core.Devices.Dumping 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 _); + sense = _dev.ModeSelect(md6, out senseBuf, true, false, _dev.Timeout, out _); if(sense) { @@ -431,11 +438,14 @@ namespace Aaru.Core.Devices.Dumping forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "")); - sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)badSector, + sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)badSector, BLOCK_SIZE, 0, 1, false, _dev.Timeout, out double cmdDuration); totalDuration += cmdDuration; + if(sense || _dev.Error) + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + if(!sense && !_dev.Error) { diff --git a/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs b/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs index b69657ed3..1705a10e1 100644 --- a/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs +++ b/Aaru.Core/Devices/Dumping/PlayStationPortable/UMD.cs @@ -61,6 +61,7 @@ namespace Aaru.Core.Devices.Dumping double minSpeed = double.MaxValue; DateTime start; DateTime end; + byte[] senseBuf; bool sense = _dev.Read12(out byte[] readBuffer, out _, 0, false, true, false, false, 0, 512, 0, 1, false, _dev.Timeout, out _); @@ -212,8 +213,9 @@ namespace Aaru.Core.Devices.Dumping UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, (long)blocks); - sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)(umdStart + (i * 4)), - 512, 0, blocksToRead * 4, false, _dev.Timeout, out double cmdDuration); + sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, + (uint)(umdStart + (i * 4)), 512, 0, blocksToRead * 4, false, _dev.Timeout, + out double cmdDuration); totalDuration += cmdDuration; @@ -229,6 +231,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); + // TODO: Reset device after X errors if(_stopOnError) return; // TODO: Return more cleanly @@ -312,12 +316,16 @@ namespace Aaru.Core.Devices.Dumping PulseProgress?.Invoke($"Trimming sector {badSector}"); - sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, + sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)(umdStart + (badSector * 4)), 512, 0, 4, false, _dev.Timeout, out double cmdDuration); if(sense || _dev.Error) + { + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + continue; + } _resume.BadBlocks.Remove(badSector); extents.Add(badSector); @@ -396,7 +404,7 @@ namespace Aaru.Core.Devices.Dumping md6 = Modes.EncodeMode6(md, _dev.ScsiType); _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks)."); - sense = _dev.ModeSelect(md6, out byte[] senseBuf, true, false, _dev.Timeout, out _); + sense = _dev.ModeSelect(md6, out senseBuf, true, false, _dev.Timeout, out _); if(sense) { @@ -429,12 +437,15 @@ namespace Aaru.Core.Devices.Dumping PulseProgress?. Invoke($"Retrying sector {badSector}, pass {pass}, {(runningPersistent ? "recovering partial data, " : "")}{(forward ? "forward" : "reverse")}"); - sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, + sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)(umdStart + (badSector * 4)), 512, 0, 4, false, _dev.Timeout, out double cmdDuration); totalDuration += cmdDuration; + if(sense || _dev.Error) + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + if(!sense && !_dev.Error) { diff --git a/Aaru.Core/Devices/Dumping/SBC.cs b/Aaru.Core/Devices/Dumping/SBC.cs index bbffe8323..38a54b0bd 100644 --- a/Aaru.Core/Devices/Dumping/SBC.cs +++ b/Aaru.Core/Devices/Dumping/SBC.cs @@ -92,7 +92,7 @@ namespace Aaru.Core.Devices.Dumping } _dumpLog.WriteLine("Initializing reader."); - var scsiReader = new Reader(_dev, _dev.Timeout, null, _dumpRaw); + var scsiReader = new Reader(_dev, _dev.Timeout, null, _errorLog, _dumpRaw); ulong blocks = scsiReader.GetDeviceBlocks(); uint blockSize = scsiReader.LogicalBlockSize; diff --git a/Aaru.Core/Devices/Dumping/SecureDigital.cs b/Aaru.Core/Devices/Dumping/SecureDigital.cs index c6c299f3c..519a5aff0 100644 --- a/Aaru.Core/Devices/Dumping/SecureDigital.cs +++ b/Aaru.Core/Devices/Dumping/SecureDigital.cs @@ -82,6 +82,7 @@ namespace Aaru.Core.Devices.Dumping byte[] scr = null; uint physicalBlockSize = 0; bool byteAddressed = true; + uint[] response; Dictionary mediaTags = new Dictionary(); @@ -91,7 +92,7 @@ namespace Aaru.Core.Devices.Dumping { UpdateStatus?.Invoke("Reading Extended CSD"); _dumpLog.WriteLine("Reading Extended CSD"); - sense = _dev.ReadExtendedCsd(out ecsd, out _, TIMEOUT, out duration); + sense = _dev.ReadExtendedCsd(out ecsd, out response, TIMEOUT, out duration); if(!sense) { @@ -110,11 +111,14 @@ namespace Aaru.Core.Devices.Dumping mediaTags.Add(MediaTagType.MMC_ExtendedCSD, null); } else + { + _errorLog?.WriteLine("Read eCSD", _dev.Error, _dev.LastError, response); ecsd = null; + } UpdateStatus?.Invoke("Reading CSD"); _dumpLog.WriteLine("Reading CSD"); - sense = _dev.ReadCsd(out csd, out _, TIMEOUT, out duration); + sense = _dev.ReadCsd(out csd, out response, TIMEOUT, out duration); if(!sense) { @@ -128,14 +132,20 @@ namespace Aaru.Core.Devices.Dumping mediaTags.Add(MediaTagType.MMC_CSD, null); } else + { + _errorLog?.WriteLine("Read CSD", _dev.Error, _dev.LastError, response); csd = null; + } UpdateStatus?.Invoke("Reading OCR"); _dumpLog.WriteLine("Reading OCR"); - sense = _dev.ReadOcr(out ocr, out _, TIMEOUT, out duration); + sense = _dev.ReadOcr(out ocr, out response, TIMEOUT, out duration); if(sense) + { + _errorLog?.WriteLine("Read OCR", _dev.Error, _dev.LastError, response); ocr = null; + } else mediaTags.Add(MediaTagType.MMC_OCR, null); @@ -146,7 +156,7 @@ namespace Aaru.Core.Devices.Dumping { UpdateStatus?.Invoke("Reading CSD"); _dumpLog.WriteLine("Reading CSD"); - sense = _dev.ReadCsd(out csd, out _, TIMEOUT, out duration); + sense = _dev.ReadCsd(out csd, out response, TIMEOUT, out duration); if(!sense) { @@ -163,23 +173,32 @@ namespace Aaru.Core.Devices.Dumping mediaTags.Add(MediaTagType.SD_CSD, null); } else + { + _errorLog?.WriteLine("Read CSD", _dev.Error, _dev.LastError, response); csd = null; + } UpdateStatus?.Invoke("Reading OCR"); _dumpLog.WriteLine("Reading OCR"); - sense = _dev.ReadSdocr(out ocr, out _, TIMEOUT, out duration); + sense = _dev.ReadSdocr(out ocr, out response, TIMEOUT, out duration); if(sense) + { + _errorLog?.WriteLine("Read OCR", _dev.Error, _dev.LastError, response); ocr = null; + } else mediaTags.Add(MediaTagType.SD_OCR, null); UpdateStatus?.Invoke("Reading SCR"); _dumpLog.WriteLine("Reading SCR"); - sense = _dev.ReadScr(out scr, out _, TIMEOUT, out duration); + sense = _dev.ReadScr(out scr, out response, TIMEOUT, out duration); if(sense) + { + _errorLog?.WriteLine("Read SCR", _dev.Error, _dev.LastError, response); scr = null; + } else mediaTags.Add(MediaTagType.SD_SCR, null); @@ -189,10 +208,13 @@ namespace Aaru.Core.Devices.Dumping UpdateStatus?.Invoke("Reading CID"); _dumpLog.WriteLine("Reading CID"); - sense = _dev.ReadCid(out byte[] cid, out _, TIMEOUT, out duration); + sense = _dev.ReadCid(out byte[] cid, out response, TIMEOUT, out duration); if(sense) + { + _errorLog?.WriteLine("Read CID", _dev.Error, _dev.LastError, response); cid = null; + } else mediaTags.Add(_dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID : MediaTagType.MMC_CID, null); @@ -345,7 +367,7 @@ namespace Aaru.Core.Devices.Dumping UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, (long)blocks); - error = _dev.Read(out cmdBuf, out _, (uint)i, blockSize, blocksToRead, byteAddressed, TIMEOUT, + error = _dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, byteAddressed, TIMEOUT, out duration); if(!error) @@ -359,6 +381,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, byteAddressed, response); + if(i + _skip > blocks) _skip = (uint)(blocks - i); @@ -438,13 +462,17 @@ namespace Aaru.Core.Devices.Dumping PulseProgress?.Invoke($"Trimming sector {badSector}"); - error = _dev.Read(out cmdBuf, out _, (uint)badSector, blockSize, 1, byteAddressed, TIMEOUT, + error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, TIMEOUT, out duration); totalDuration += duration; if(error) + { + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, byteAddressed, response); + continue; + } _resume.BadBlocks.Remove(badSector); extents.Add(badSector); @@ -486,11 +514,14 @@ namespace Aaru.Core.Devices.Dumping forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "")); - error = _dev.Read(out cmdBuf, out _, (uint)badSector, blockSize, 1, byteAddressed, TIMEOUT, + error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, TIMEOUT, out duration); totalDuration += duration; + if(error) + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, byteAddressed, response); + if(!error) { _resume.BadBlocks.Remove(badSector); diff --git a/Aaru.Core/Devices/Dumping/XGD.cs b/Aaru.Core/Devices/Dumping/XGD.cs index 0065a651f..0d349bd8b 100644 --- a/Aaru.Core/Devices/Dumping/XGD.cs +++ b/Aaru.Core/Devices/Dumping/XGD.cs @@ -151,6 +151,8 @@ namespace Aaru.Core.Devices.Dumping if(sense) { + _errorLog?.WriteLine("Kreon lock", _dev.Error, _dev.LastError, senseBuf); + _dumpLog.WriteLine("Cannot lock drive, not continuing."); StoppingErrorMessage?.Invoke("Cannot lock drive, not continuing."); @@ -251,6 +253,7 @@ namespace Aaru.Core.Devices.Dumping if(sense) { + _errorLog?.WriteLine("Kreon Xtreme unlock", _dev.Error, _dev.LastError, senseBuf); _dumpLog.WriteLine("Cannot unlock drive, not continuing."); StoppingErrorMessage?.Invoke("Cannot unlock drive, not continuing."); @@ -282,6 +285,7 @@ namespace Aaru.Core.Devices.Dumping if(sense) { + _errorLog?.WriteLine("Kreon Wxripper unlock", _dev.Error, _dev.LastError, senseBuf); _dumpLog.WriteLine("Cannot unlock drive, not continuing."); StoppingErrorMessage?.Invoke("Cannot unlock drive, not continuing."); @@ -600,6 +604,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf); + // TODO: Reset device after X errors if(_stopOnError) return; // TODO: Return more cleanly @@ -794,6 +800,8 @@ namespace Aaru.Core.Devices.Dumping } else { + _errorLog?.WriteLine(currentSector, _dev.Error, _dev.LastError, senseBuf); + // TODO: Reset device after X errors if(_stopOnError) return; // TODO: Return more cleanly @@ -844,6 +852,7 @@ namespace Aaru.Core.Devices.Dumping if(sense) { + _errorLog?.WriteLine("Kreon Wxripper unlock", _dev.Error, _dev.LastError, senseBuf); _dumpLog.WriteLine("Cannot unlock drive, not continuing."); StoppingErrorMessage?.Invoke("Cannot unlock drive, not continuing."); @@ -913,7 +922,11 @@ namespace Aaru.Core.Devices.Dumping totalDuration += cmdDuration; if(sense || _dev.Error) + { + _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf); + continue; + } _resume.BadBlocks.Remove(badSector); extents.Add(badSector); @@ -1062,6 +1075,9 @@ namespace Aaru.Core.Devices.Dumping totalDuration += cmdDuration; + if(sense || _dev.Error) + _errorLog?.WriteLine(currentSector, _dev.Error, _dev.LastError, senseBuf); + if(!sense && !_dev.Error) { diff --git a/Aaru.Core/Devices/Reader.cs b/Aaru.Core/Devices/Reader.cs index afc7ef4a7..f294da930 100644 --- a/Aaru.Core/Devices/Reader.cs +++ b/Aaru.Core/Devices/Reader.cs @@ -33,6 +33,7 @@ using System; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Structs.Devices.ATA; +using Aaru.Core.Logging; using Aaru.Devices; namespace Aaru.Core.Devices @@ -40,15 +41,17 @@ namespace Aaru.Core.Devices /// Reduces common code used for scanning and dumping internal partial class Reader { - readonly Device _dev; - readonly uint _timeout; + readonly Device _dev; + readonly ErrorLog _errorLog; + readonly uint _timeout; - internal Reader(Device dev, uint timeout, byte[] identification, bool raw = false) + internal Reader(Device dev, uint timeout, byte[] identification, ErrorLog errorLog, bool raw = false) { _dev = dev; _timeout = timeout; BlocksToRead = 64; CanReadRaw = raw; + _errorLog = errorLog; switch(dev.Type) { diff --git a/Aaru.Core/Devices/ReaderATA.cs b/Aaru.Core/Devices/ReaderATA.cs index 4b1c56129..1947c6a55 100644 --- a/Aaru.Core/Devices/ReaderATA.cs +++ b/Aaru.Core/Devices/ReaderATA.cs @@ -361,6 +361,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorLba48.Status & 0x27) == 0 && errorLba48.Error == 0 && buffer.Length > 0); status = errorLba48.Status; errorByte = errorLba48.Error; + + if(error) + _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba48); } else if(_ataReadLba48) { @@ -368,6 +371,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorLba48.Status & 0x27) == 0 && errorLba48.Error == 0 && buffer.Length > 0); status = errorLba48.Status; errorByte = errorLba48.Error; + + if(error) + _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba48); } else if(_ataReadDmaRetryLba) { @@ -376,6 +382,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorLba.Status & 0x27) == 0 && errorLba.Error == 0 && buffer.Length > 0); status = errorLba.Status; errorByte = errorLba.Error; + + if(error) + _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); } else if(_ataReadDmaLba) { @@ -384,6 +393,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorLba.Status & 0x27) == 0 && errorLba.Error == 0 && buffer.Length > 0); status = errorLba.Status; errorByte = errorLba.Error; + + if(error) + _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); } else if(_ataReadRetryLba) { @@ -391,6 +403,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorLba.Status & 0x27) == 0 && errorLba.Error == 0 && buffer.Length > 0); status = errorLba.Status; errorByte = errorLba.Error; + + if(error) + _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); } else if(_ataReadLba) { @@ -398,6 +413,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorLba.Status & 0x27) == 0 && errorLba.Error == 0 && buffer.Length > 0); status = errorLba.Status; errorByte = errorLba.Error; + + if(error) + _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); } if(error) @@ -422,6 +440,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorChs.Status & 0x27) == 0 && errorChs.Error == 0 && buffer.Length > 0); status = errorChs.Status; errorByte = errorChs.Error; + + if(error) + _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); } else if(_ataReadDma) { @@ -431,6 +452,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorChs.Status & 0x27) == 0 && errorChs.Error == 0 && buffer.Length > 0); status = errorChs.Status; errorByte = errorChs.Error; + + if(error) + _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); } else if(_ataReadRetry) { @@ -438,6 +462,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorChs.Status & 0x27) == 0 && errorChs.Error == 0 && buffer.Length > 0); status = errorChs.Status; errorByte = errorChs.Error; + + if(error) + _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); } else if(_ataRead) { @@ -445,6 +472,9 @@ namespace Aaru.Core.Devices error = !(!sense && (errorChs.Status & 0x27) == 0 && errorChs.Error == 0 && buffer.Length > 0); status = errorChs.Status; errorByte = errorChs.Error; + + if(error) + _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); } if(error) @@ -457,6 +487,9 @@ namespace Aaru.Core.Devices { bool sense = _dev.Seek(out AtaErrorRegistersLba28 errorLba, (uint)block, _timeout, out duration); + if(!(!sense && (errorLba.Status & 0x27) == 0 && errorLba.Error == 0)) + _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, errorLba); + return !(!sense && (errorLba.Status & 0x27) == 0 && errorLba.Error == 0); } @@ -464,6 +497,9 @@ namespace Aaru.Core.Devices { bool sense = _dev.Seek(out AtaErrorRegistersChs errorChs, cylinder, head, sector, _timeout, out duration); + if(!(!sense && (errorChs.Status & 0x27) == 0 && errorChs.Error == 0)) + _errorLog?.WriteLine(cylinder, head, sector, _dev.Error, _dev.LastError, errorChs); + return !(!sense && (errorChs.Status & 0x27) == 0 && errorChs.Error == 0); } } diff --git a/Aaru.Core/Devices/ReaderSCSI.cs b/Aaru.Core/Devices/ReaderSCSI.cs index 20313642a..46bf31a22 100644 --- a/Aaru.Core/Devices/ReaderSCSI.cs +++ b/Aaru.Core/Devices/ReaderSCSI.cs @@ -622,6 +622,9 @@ namespace Aaru.Core.Devices return true; } + if(sense || _dev.Error) + _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, senseBuf); + if(!sense && !_dev.Error) return false; diff --git a/Aaru.Core/Devices/Scanning/ATA.cs b/Aaru.Core/Devices/Scanning/ATA.cs index aa1b1a424..0fdcba477 100644 --- a/Aaru.Core/Devices/Scanning/ATA.cs +++ b/Aaru.Core/Devices/Scanning/ATA.cs @@ -56,7 +56,7 @@ namespace Aaru.Core.Devices.Scanning Identify.Decode(cmdBuf).HasValue) { // Initializate reader - var ataReader = new Reader(_dev, TIMEOUT, cmdBuf); + var ataReader = new Reader(_dev, TIMEOUT, cmdBuf, null); // Fill reader blocks results.Blocks = ataReader.GetDeviceBlocks(); @@ -204,8 +204,7 @@ namespace Aaru.Core.Devices.Scanning mhddLog.Close(); ibgLog.Close(_dev, results.Blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - (blockSize * (double)(results.Blocks + 1)) / 1024 / - (results.ProcessingTime / 1000), + (blockSize * (double)(results.Blocks + 1)) / 1024 / (results.ProcessingTime / 1000), _devicePath); InitProgress?.Invoke(); @@ -325,8 +324,7 @@ namespace Aaru.Core.Devices.Scanning mhddLog.Close(); ibgLog.Close(_dev, results.Blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, - (blockSize * (double)(results.Blocks + 1)) / 1024 / - (results.ProcessingTime / 1000), + (blockSize * (double)(results.Blocks + 1)) / 1024 / (results.ProcessingTime / 1000), _devicePath); InitProgress?.Invoke(); diff --git a/Aaru.Core/Devices/Scanning/SCSI.cs b/Aaru.Core/Devices/Scanning/SCSI.cs index 20c983be6..397131d1a 100644 --- a/Aaru.Core/Devices/Scanning/SCSI.cs +++ b/Aaru.Core/Devices/Scanning/SCSI.cs @@ -169,7 +169,7 @@ namespace Aaru.Core.Devices.Scanning case PeripheralDeviceTypes.OpticalDevice: case PeripheralDeviceTypes.SimplifiedDevice: case PeripheralDeviceTypes.WriteOnceDevice: - scsiReader = new Reader(_dev, _dev.Timeout, null); + scsiReader = new Reader(_dev, _dev.Timeout, null, null); results.Blocks = scsiReader.GetDeviceBlocks(); if(scsiReader.FindReadCommand()) diff --git a/Aaru.Core/Logging/ErrorLog.cs b/Aaru.Core/Logging/ErrorLog.cs new file mode 100644 index 000000000..70a61c0ed --- /dev/null +++ b/Aaru.Core/Logging/ErrorLog.cs @@ -0,0 +1,554 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Aaru.Decoders.ATA; +using Aaru.Decoders.SCSI; + +namespace Aaru.Core.Logging +{ + public class ErrorLog + { + readonly StreamWriter _logSw; + + /// Initializes the error log + /// Output log file + public ErrorLog(string outputFile) + { + if(string.IsNullOrEmpty(outputFile)) + return; + + _logSw = new StreamWriter(outputFile, true); + + _logSw.WriteLine("Start error logging at {0}", DateTime.Now); + _logSw.WriteLine("######################################################"); + _logSw.Flush(); + } + + /// Finishes and closes the error log + public void Close() + { + _logSw.WriteLine("######################################################"); + _logSw.WriteLine("End logging at {0}", DateTime.Now); + _logSw.Close(); + } + + /// Register an ATA error after sending a CHS command + /// Command + /// true if operating system returned an error status instead of the device + /// Operating system error number + /// Error registers + public void WriteLine(string command, bool osError, int errno, AtaErrorRegistersChs registers) + { + if(osError) + { + _logSw.WriteLine("ATA command {0} operating system error: {1}.", command, errno); + _logSw.Flush(); + } + else + { + List error = new List(); + List status = new List(); + + if((registers.Status & 0x01) == 0x01) + status.Add("ERR"); + + if((registers.Status & 0x02) == 0x02) + status.Add("IDX"); + + if((registers.Status & 0x04) == 0x04) + status.Add("CORR"); + + if((registers.Status & 0x08) == 0x08) + status.Add("DRQ"); + + if((registers.Status & 0x10) == 0x10) + status.Add("SRV"); + + if((registers.Status & 0x20) == 0x20) + status.Add("DF"); + + if((registers.Status & 0x40) == 0x40) + status.Add("RDY"); + + if((registers.Status & 0x80) == 0x80) + status.Add("BSY"); + + if((registers.Error & 0x01) == 0x01) + error.Add("AMNF"); + + if((registers.Error & 0x02) == 0x02) + error.Add("T0NF"); + + if((registers.Error & 0x04) == 0x04) + error.Add("ABRT"); + + if((registers.Error & 0x08) == 0x08) + error.Add("MCR"); + + if((registers.Error & 0x10) == 0x10) + error.Add("IDNF"); + + if((registers.Error & 0x20) == 0x20) + error.Add("MC"); + + if((registers.Error & 0x40) == 0x40) + error.Add("UNC"); + + if((registers.Error & 0x80) == 0x80) + error.Add("BBK"); + + _logSw.WriteLine("ATA command {0} error: status = {1}, error = {2}.", command, string.Join(' ', status), + string.Join(' ', error)); + + _logSw.Flush(); + } + } + + /// Register an ATA error after trying to read using CHS commands + /// Cylinder + /// Head + /// Sector + /// true if operating system returned an error status instead of the device + /// Operating system error number + /// Error registers + public void WriteLine(ushort cylinder, byte head, byte sector, bool osError, int errno, + AtaErrorRegistersChs registers) + { + if(osError) + { + _logSw.WriteLine("ATA reading C/H/S {0}/{1}/{2} operating system error: {3}.", cylinder, head, sector, + errno); + + _logSw.Flush(); + } + else + { + List error = new List(); + List status = new List(); + + if((registers.Status & 0x01) == 0x01) + status.Add("ERR"); + + if((registers.Status & 0x02) == 0x02) + status.Add("IDX"); + + if((registers.Status & 0x04) == 0x04) + status.Add("CORR"); + + if((registers.Status & 0x08) == 0x08) + status.Add("DRQ"); + + if((registers.Status & 0x10) == 0x10) + status.Add("SRV"); + + if((registers.Status & 0x20) == 0x20) + status.Add("DF"); + + if((registers.Status & 0x40) == 0x40) + status.Add("RDY"); + + if((registers.Status & 0x80) == 0x80) + status.Add("BSY"); + + if((registers.Error & 0x01) == 0x01) + error.Add("AMNF"); + + if((registers.Error & 0x02) == 0x02) + error.Add("T0NF"); + + if((registers.Error & 0x04) == 0x04) + error.Add("ABRT"); + + if((registers.Error & 0x08) == 0x08) + error.Add("MCR"); + + if((registers.Error & 0x10) == 0x10) + error.Add("IDNF"); + + if((registers.Error & 0x20) == 0x20) + error.Add("MC"); + + if((registers.Error & 0x40) == 0x40) + error.Add("UNC"); + + if((registers.Error & 0x80) == 0x80) + error.Add("BBK"); + + _logSw.WriteLine("ATA reading C/H/S {0}/{1}/{2} error: status = {3}, error = {4}.", cylinder, head, + sector, string.Join(' ', status), string.Join(' ', error)); + + _logSw.Flush(); + } + } + + /// Register an ATA error after trying to read using 28-bit LBA commands + /// Starting block + /// true if operating system returned an error status instead of the device + /// Operating system error number + /// Error registers + public void WriteLine(ulong block, bool osError, int errno, AtaErrorRegistersLba28 registers) + { + if(osError) + { + _logSw.WriteLine("ATA reading LBA {0} operating system error: {1}.", block, errno); + _logSw.Flush(); + } + else + { + List error = new List(); + List status = new List(); + + if((registers.Status & 0x01) == 0x01) + status.Add("ERR"); + + if((registers.Status & 0x02) == 0x02) + status.Add("IDX"); + + if((registers.Status & 0x04) == 0x04) + status.Add("CORR"); + + if((registers.Status & 0x08) == 0x08) + status.Add("DRQ"); + + if((registers.Status & 0x10) == 0x10) + status.Add("SRV"); + + if((registers.Status & 0x20) == 0x20) + status.Add("DF"); + + if((registers.Status & 0x40) == 0x40) + status.Add("RDY"); + + if((registers.Status & 0x80) == 0x80) + status.Add("BSY"); + + if((registers.Error & 0x01) == 0x01) + error.Add("AMNF"); + + if((registers.Error & 0x02) == 0x02) + error.Add("T0NF"); + + if((registers.Error & 0x04) == 0x04) + error.Add("ABRT"); + + if((registers.Error & 0x08) == 0x08) + error.Add("MCR"); + + if((registers.Error & 0x10) == 0x10) + error.Add("IDNF"); + + if((registers.Error & 0x20) == 0x20) + error.Add("MC"); + + if((registers.Error & 0x40) == 0x40) + error.Add("UNC"); + + if((registers.Error & 0x80) == 0x80) + error.Add("BBK"); + + _logSw.WriteLine("ATA reading LBA {0} error: status = {1}, error = {2}.", block, + string.Join(' ', status), string.Join(' ', error)); + + _logSw.Flush(); + } + } + + /// Register an ATA error after trying to read using 48-bit LBA commands + /// Starting block + /// true if operating system returned an error status instead of the device + /// Operating system error number + /// Error registers + public void WriteLine(ulong block, bool osError, int errno, AtaErrorRegistersLba48 registers) + { + if(osError) + { + _logSw.WriteLine("ATA reading LBA {0} operating system error: {1}.", block, errno); + _logSw.Flush(); + } + else + { + List error = new List(); + List status = new List(); + + if((registers.Status & 0x01) == 0x01) + status.Add("ERR"); + + if((registers.Status & 0x02) == 0x02) + status.Add("IDX"); + + if((registers.Status & 0x04) == 0x04) + status.Add("CORR"); + + if((registers.Status & 0x08) == 0x08) + status.Add("DRQ"); + + if((registers.Status & 0x10) == 0x10) + status.Add("SRV"); + + if((registers.Status & 0x20) == 0x20) + status.Add("DF"); + + if((registers.Status & 0x40) == 0x40) + status.Add("RDY"); + + if((registers.Status & 0x80) == 0x80) + status.Add("BSY"); + + if((registers.Error & 0x01) == 0x01) + error.Add("AMNF"); + + if((registers.Error & 0x02) == 0x02) + error.Add("T0NF"); + + if((registers.Error & 0x04) == 0x04) + error.Add("ABRT"); + + if((registers.Error & 0x08) == 0x08) + error.Add("MCR"); + + if((registers.Error & 0x10) == 0x10) + error.Add("IDNF"); + + if((registers.Error & 0x20) == 0x20) + error.Add("MC"); + + if((registers.Error & 0x40) == 0x40) + error.Add("UNC"); + + if((registers.Error & 0x80) == 0x80) + error.Add("BBK"); + + _logSw.WriteLine("ATA reading LBA {0} error: status = {1}, error = {2}.", block, + string.Join(' ', status), string.Join(' ', error)); + + _logSw.Flush(); + } + } + + /// Register a SCSI error after sending a command + /// Command + /// true if operating system returned an error status instead of the device + /// Operating system error number + /// REQUEST SENSE response buffer + public void WriteLine(string command, bool osError, int errno, byte[] senseBuffer) + { + if(osError) + { + _logSw.WriteLine("SCSI command {0} operating system error: {1}.", command, errno); + _logSw.Flush(); + + return; + } + + FixedSense? decodedFixedSense = Sense.DecodeFixed(senseBuffer); + DescriptorSense? decodedDescriptorSense = Sense.DecodeDescriptor(senseBuffer); + string prettySense = Sense.PrettifySense(senseBuffer); + string hexSense = string.Join(' ', senseBuffer.Select(b => $"{b:X2}")); + + if(decodedFixedSense.HasValue) + { + if(prettySense != null) + { + if(prettySense.StartsWith("SCSI SENSE: ")) + prettySense = prettySense.Substring(12); + + if(prettySense.EndsWith("\n")) + prettySense = prettySense.Substring(0, prettySense.Length - 1); + + prettySense = prettySense.Replace("\n", " - "); + + _logSw.WriteLine("SCSI command {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}, {5}.", command, + decodedFixedSense?.SenseKey, decodedFixedSense?.ASC, decodedFixedSense?.ASCQ, + hexSense, prettySense); + } + else + { + _logSw.WriteLine("SCSI command {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}.", command, + decodedFixedSense?.SenseKey, decodedFixedSense?.ASC, decodedFixedSense?.ASCQ, + hexSense); + } + } + else if(decodedDescriptorSense.HasValue) + { + if(prettySense != null) + { + if(prettySense.StartsWith("SCSI SENSE: ")) + prettySense = prettySense.Substring(12); + + if(prettySense.EndsWith("\n")) + prettySense = prettySense.Substring(0, prettySense.Length - 1); + + prettySense = prettySense.Replace("\n", " - "); + + _logSw.WriteLine("SCSI command {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}, {5}.", command, + decodedDescriptorSense?.SenseKey, decodedDescriptorSense?.ASC, + decodedDescriptorSense?.ASCQ, hexSense, prettySense); + } + else + { + _logSw.WriteLine("SCSI command {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}.", command, + decodedDescriptorSense?.SenseKey, decodedDescriptorSense?.ASC, + decodedDescriptorSense?.ASCQ, hexSense); + } + } + else + { + if(prettySense != null) + { + if(prettySense.StartsWith("SCSI SENSE: ")) + prettySense = prettySense.Substring(12); + + if(prettySense.EndsWith("\n")) + prettySense = prettySense.Substring(0, prettySense.Length - 1); + + prettySense = prettySense.Replace("\n", " - "); + + _logSw.WriteLine("SCSI command {0} error: {1}, {2}.", command, hexSense, prettySense); + } + else + { + _logSw.WriteLine("SCSI command {0} error: {1}", command, hexSense); + } + } + + _logSw.Flush(); + } + + /// Register an SCSI error after trying to read + /// Starting block + /// true if operating system returned an error status instead of the device + /// Operating system error number + /// REQUEST SENSE response buffer + public void WriteLine(ulong block, bool osError, int errno, byte[] senseBuffer) + { + if(osError) + { + _logSw.WriteLine("SCSI reading LBA {0} operating system error: {1}.", block, errno); + _logSw.Flush(); + + return; + } + + FixedSense? decodedFixedSense = Sense.DecodeFixed(senseBuffer); + DescriptorSense? decodedDescriptorSense = Sense.DecodeDescriptor(senseBuffer); + string prettySense = Sense.PrettifySense(senseBuffer); + string hexSense = string.Join(' ', senseBuffer.Select(b => $"{b:X2}")); + + if(decodedFixedSense.HasValue) + { + if(prettySense != null) + { + if(prettySense.StartsWith("SCSI SENSE: ")) + prettySense = prettySense.Substring(12); + + if(prettySense.EndsWith("\n")) + prettySense = prettySense.Substring(0, prettySense.Length - 1); + + prettySense = prettySense.Replace("\n", " - "); + + _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}, {5}.", block, + decodedFixedSense?.SenseKey, decodedFixedSense?.ASC, decodedFixedSense?.ASCQ, + hexSense, prettySense); + } + else + { + _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}.", block, + decodedFixedSense?.SenseKey, decodedFixedSense?.ASC, decodedFixedSense?.ASCQ, + hexSense); + } + } + else if(decodedDescriptorSense.HasValue) + { + if(prettySense != null) + { + if(prettySense.StartsWith("SCSI SENSE: ")) + prettySense = prettySense.Substring(12); + + if(prettySense.EndsWith("\n")) + prettySense = prettySense.Substring(0, prettySense.Length - 1); + + prettySense = prettySense.Replace("\n", " - "); + + _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}, {5}.", block, + decodedDescriptorSense?.SenseKey, decodedDescriptorSense?.ASC, + decodedDescriptorSense?.ASCQ, hexSense, prettySense); + } + else + { + _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}.", block, + decodedDescriptorSense?.SenseKey, decodedDescriptorSense?.ASC, + decodedDescriptorSense?.ASCQ, hexSense); + } + } + else + { + if(prettySense != null) + { + if(prettySense.StartsWith("SCSI SENSE: ")) + prettySense = prettySense.Substring(12); + + if(prettySense.EndsWith("\n")) + prettySense = prettySense.Substring(0, prettySense.Length - 1); + + prettySense = prettySense.Replace("\n", " - "); + + _logSw.WriteLine("SCSI reading LBA {0} error: {1}, {2}.", block, hexSense, prettySense); + } + else + { + _logSw.WriteLine("SCSI reading LBA {0} error: {1}", block, hexSense); + } + } + + _logSw.Flush(); + } + + /// Register a SecureDigital / MultiMediaCard error after sending a command + /// Command + /// true if operating system returned an error status instead of the device + /// Operating system error number + /// Response + public void WriteLine(string command, bool osError, int errno, uint[] response) + { + if(osError) + { + _logSw.WriteLine("SD/MMC command {0} operating system error: {1}.", command, errno); + _logSw.Flush(); + + return; + } + + // TODO: Decode response + _logSw.WriteLine("SD/MMC command {0} error: {1}", command, + string.Join(" - ", response.Select(r => $"0x{r:X8}"))); + + _logSw.Flush(); + } + + /// Register a SecureDigital / MultiMediaCard error after trying to read + /// Starting block + /// true if operating system returned an error status instead of the device + /// Operating system error number + /// Byte addressed + /// Response + public void WriteLine(ulong block, bool osError, int errno, bool byteAddressed, uint[] response) + + { + if(osError) + { + _logSw.WriteLine("SD/MMC reading LBA {0} ({1}-addressed) operating system error: {2}.", block, + byteAddressed ? "byte" : "block", errno); + + _logSw.Flush(); + + return; + } + + _logSw.WriteLine("SD/MMC reading LBA {0} ({1}-addressed) error: {2}", block, + byteAddressed ? "byte" : "block", string.Join(" - ", response.Select(r => $"0x{r:X8}"))); + + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs b/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs index 1364f1a47..0af5da691 100644 --- a/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs +++ b/Aaru.Gui/ViewModels/Windows/MediaDumpViewModel.cs @@ -797,11 +797,13 @@ namespace Aaru.Gui.ViewModels.Windows dumpLog.WriteLine("Output image format: {0}.", SelectedPlugin.Name); + var errorLog = new ErrorLog(_outputPrefix + ".error.log"); + _dumper = new Dump(Resume, _dev, _devicePath, SelectedPlugin.Plugin, (ushort)Retries, Force, false, Persistent, StopOnError, _resume, dumpLog, encoding, _outputPrefix, Destination, parsedOptions, _sidecar, (uint)Skipped, ExistingMetadata == false, Trim == false, Track1Pregap, true, false, DumpSubchannel.Any, 0, false, false, false, false, false, - true); + true, errorLog); new Thread(DoWork).Start(); } diff --git a/Aaru/Commands/Media/Dump.cs b/Aaru/Commands/Media/Dump.cs index 374a5dd4b..25b94a9b0 100644 --- a/Aaru/Commands/Media/Dump.cs +++ b/Aaru/Commands/Media/Dump.cs @@ -469,11 +469,13 @@ namespace Aaru.Commands.Media AaruConsole.WriteLine("Output image format: {0}.", outputFormat.Name); } + var errorLog = new ErrorLog(outputPrefix + ".error.log"); + var dumper = new Dump(resume, dev, devicePath, outputFormat, retryPasses, force, false, persistent, stopOnError, resumeClass, dumpLog, encodingClass, outputPrefix, outputPath, parsedOptions, sidecar, skip, metadata, trim, firstPregap, fixOffset, debug, wantedSubchannel, speed, @private, fixSubchannelPosition, retrySubchannel, - fixSubchannel, fixSubchannelCrc, skipCdireadyHole); + fixSubchannel, fixSubchannelCrc, skipCdireadyHole, errorLog); dumper.UpdateStatus += Progress.UpdateStatus; dumper.ErrorMessage += Progress.ErrorMessage; @@ -499,4 +501,4 @@ namespace Aaru.Commands.Media return (int)ErrorNumber.NoError; } } -} +} \ No newline at end of file