Added dump log creation.

This commit is contained in:
2017-11-20 05:07:16 +00:00
parent 94fa71e217
commit 5fbf06c360
12 changed files with 581 additions and 120 deletions

View File

@@ -54,7 +54,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
public class ATA public class ATA
{ {
public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref Metadata.Resume resume) public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref Metadata.Resume resume, ref DumpLog dumpLog)
{ {
bool aborted; bool aborted;
MHDDLog mhddLog; MHDDLog mhddLog;
@@ -78,6 +78,7 @@ namespace DiscImageChef.Core.Devices.Dumping
uint timeout = 5; uint timeout = 5;
double duration; double duration;
dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE.");
sense = dev.AtaIdentify(out byte[] cmdBuf, out Decoders.ATA.AtaErrorRegistersCHS errorChs); sense = dev.AtaIdentify(out byte[] cmdBuf, out Decoders.ATA.AtaErrorRegistersCHS errorChs);
if(!sense && Decoders.ATA.Identify.Decode(cmdBuf).HasValue) if(!sense && Decoders.ATA.Identify.Decode(cmdBuf).HasValue)
{ {
@@ -90,6 +91,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dev.IsUSB) if(dev.IsUSB)
{ {
dumpLog.WriteLine("Reading USB descriptors.");
sidecar.BlockMedia[0].USB = new USBType sidecar.BlockMedia[0].USB = new USBType
{ {
ProductID = dev.USBProductID, ProductID = dev.USBProductID,
@@ -106,6 +108,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dev.IsPCMCIA) if(dev.IsPCMCIA)
{ {
dumpLog.WriteLine("Reading PCMCIA CIS.");
sidecar.BlockMedia[0].PCMCIA = new PCMCIAType sidecar.BlockMedia[0].PCMCIA = new PCMCIAType
{ {
CIS = new DumpType CIS = new DumpType
@@ -116,6 +119,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
}; };
DataFile.WriteTo("ATA Dump", sidecar.BlockMedia[0].PCMCIA.CIS.Image, dev.CIS); DataFile.WriteTo("ATA Dump", sidecar.BlockMedia[0].PCMCIA.CIS.Image, dev.CIS);
dumpLog.WriteLine("Decoding PCMCIA CIS.");
Decoders.PCMCIA.Tuple[] tuples = CIS.GetTuples(dev.CIS); Decoders.PCMCIA.Tuple[] tuples = CIS.GetTuples(dev.CIS);
if(tuples != null) if(tuples != null)
{ {
@@ -178,12 +182,14 @@ namespace DiscImageChef.Core.Devices.Dumping
DataFile dumpFile; DataFile dumpFile;
// Initializate reader // Initializate reader
dumpLog.WriteLine("Initializing reader.");
Reader ataReader = new Reader(dev, timeout, cmdBuf); Reader ataReader = new Reader(dev, timeout, cmdBuf);
// Fill reader blocks // Fill reader blocks
ulong blocks = ataReader.GetDeviceBlocks(); ulong blocks = ataReader.GetDeviceBlocks();
// Check block sizes // Check block sizes
if(ataReader.GetBlockSize()) if(ataReader.GetBlockSize())
{ {
dumpLog.WriteLine("ERROR: Cannot get block size: {0}.", ataReader.ErrorMessage);
DicConsole.ErrorWriteLine(ataReader.ErrorMessage); DicConsole.ErrorWriteLine(ataReader.ErrorMessage);
return; return;
} }
@@ -191,12 +197,14 @@ namespace DiscImageChef.Core.Devices.Dumping
uint physicalsectorsize = ataReader.PhysicalBlockSize; uint physicalsectorsize = ataReader.PhysicalBlockSize;
if(ataReader.FindReadCommand()) if(ataReader.FindReadCommand())
{ {
dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", ataReader.ErrorMessage);
DicConsole.ErrorWriteLine(ataReader.ErrorMessage); DicConsole.ErrorWriteLine(ataReader.ErrorMessage);
return; return;
} }
// Check how many blocks to read, if error show and return // Check how many blocks to read, if error show and return
if(ataReader.GetBlocksToRead()) if(ataReader.GetBlocksToRead())
{ {
dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", ataReader.ErrorMessage);
DicConsole.ErrorWriteLine(ataReader.ErrorMessage); DicConsole.ErrorWriteLine(ataReader.ErrorMessage);
return; return;
} }
@@ -205,6 +213,12 @@ namespace DiscImageChef.Core.Devices.Dumping
byte heads = ataReader.Heads; byte heads = ataReader.Heads;
byte sectors = ataReader.Sectors; byte sectors = ataReader.Sectors;
dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize);
dumpLog.WriteLine("Device reports {0} cylinders {1} heads {2} sectors per track.", cylinders, heads, sectors);
dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize);
dumpLog.WriteLine("Device reports {0} bytes per physical block.", physicalsectorsize);
bool removable = false || (!dev.IsCompactFlash && ataId.GeneralConfiguration.HasFlag(Decoders.ATA.Identify.GeneralConfigurationBit.Removable)); bool removable = false || (!dev.IsCompactFlash && ataId.GeneralConfiguration.HasFlag(Decoders.ATA.Identify.GeneralConfigurationBit.Removable));
DumpHardwareType currentTry = null; DumpHardwareType currentTry = null;
ExtentsULong extents = null; ExtentsULong extents = null;
@@ -219,6 +233,9 @@ namespace DiscImageChef.Core.Devices.Dumping
mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead); mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
ibgLog = new IBGLog(outputPrefix + ".ibg", currentProfile); ibgLog = new IBGLog(outputPrefix + ".ibg", currentProfile);
dumpFile = new DataFile(outputPrefix + ".bin"); dumpFile = new DataFile(outputPrefix + ".bin");
if(resume.NextBlock > 0)
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
dumpFile.Seek(resume.NextBlock, blockSize); dumpFile.Seek(resume.NextBlock, blockSize);
start = DateTime.UtcNow; start = DateTime.UtcNow;
@@ -227,6 +244,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -262,6 +280,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
dumpFile.Write(new byte[blockSize * blocksToRead]); dumpFile.Write(new byte[blockSize * blocksToRead]);
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i);
} }
#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created #pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created
@@ -276,11 +295,12 @@ namespace DiscImageChef.Core.Devices.Dumping
#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created #pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath); ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath);
#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created #pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
#region Error handling #region Error handling
if(resume.BadBlocks.Count > 0 && !aborted) if(resume.BadBlocks.Count > 0 && !aborted)
{ {
int pass = 0; int pass = 0;
bool forward = true; bool forward = true;
bool runningPersistent = false; bool runningPersistent = false;
@@ -292,6 +312,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -306,6 +327,7 @@ namespace DiscImageChef.Core.Devices.Dumping
resume.BadBlocks.Remove(badSector); resume.BadBlocks.Remove(badSector);
extents.Add(badSector); extents.Add(badSector);
dumpFile.WriteAt(cmdBuf, badSector, blockSize); dumpFile.WriteAt(cmdBuf, badSector, blockSize);
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
} }
else if(runningPersistent) else if(runningPersistent)
dumpFile.WriteAt(cmdBuf, badSector, blockSize); dumpFile.WriteAt(cmdBuf, badSector, blockSize);
@@ -344,6 +366,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -366,6 +389,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ibgLog.Write(currentBlock, currentSpeed * 1024); ibgLog.Write(currentBlock, currentSpeed * 1024);
dumpFile.Write(cmdBuf); dumpFile.Write(cmdBuf);
extents.Add(currentBlock); extents.Add(currentBlock);
dumpLog.WriteLine("Error reading cylinder {0} head {1} sector {2}.", Cy, Hd, Sc);
} }
else else
{ {
@@ -394,15 +418,21 @@ namespace DiscImageChef.Core.Devices.Dumping
#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created #pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath); ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath);
#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created #pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
} }
dataChk = new Checksum(); dataChk = new Checksum();
dumpFile.Seek(0, SeekOrigin.Begin); dumpFile.Seek(0, SeekOrigin.Begin);
blocksToRead = 500; blocksToRead = 500;
dumpLog.WriteLine("Checksum starts.");
for(ulong i = 0; i < blocks; i += blocksToRead) for(ulong i = 0; i < blocks; i += blocksToRead)
{ {
if(aborted) if(aborted)
{
dumpLog.WriteLine("Aborted!");
break; break;
}
if((blocks - i) < blocksToRead) if((blocks - i) < blocksToRead)
blocksToRead = (byte)(blocks - i); blocksToRead = (byte)(blocks - i);
@@ -423,6 +453,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
dumpFile.Close(); dumpFile.Close();
end = DateTime.UtcNow; end = DateTime.UtcNow;
dumpLog.WriteLine("Checksum finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
PluginBase plugins = new PluginBase(); PluginBase plugins = new PluginBase();
plugins.RegisterAllPlugins(); plugins.RegisterAllPlugins();
@@ -452,8 +484,10 @@ namespace DiscImageChef.Core.Devices.Dumping
if(_imageFormat != null) if(_imageFormat != null)
{ {
dumpLog.WriteLine("Getting partitions.");
List<Partition> partitions = Partitions.GetAll(_imageFormat); List<Partition> partitions = Partitions.GetAll(_imageFormat);
Partitions.AddSchemesToStats(partitions); Partitions.AddSchemesToStats(partitions);
dumpLog.WriteLine("Found {0} partitions.", partitions.Count);
if(partitions.Count > 0) if(partitions.Count > 0)
{ {
@@ -470,6 +504,8 @@ namespace DiscImageChef.Core.Devices.Dumping
Type = partitions[i].Type Type = partitions[i].Type
}; };
List<FileSystemType> lstFs = new List<FileSystemType>(); List<FileSystemType> lstFs = new List<FileSystemType>();
dumpLog.WriteLine("Getting filesystems on partition {0}, starting at {1}, ending at {2}, with type {3}, under scheme {4}.",
i, partitions[i].Start, partitions[i].End, partitions[i].Type, partitions[i].Scheme);
foreach(Filesystem _plugin in plugins.PluginsList.Values) foreach(Filesystem _plugin in plugins.PluginsList.Values)
{ {
@@ -480,6 +516,7 @@ namespace DiscImageChef.Core.Devices.Dumping
_plugin.GetInformation(_imageFormat, partitions[i], out string foo); _plugin.GetInformation(_imageFormat, partitions[i], out string foo);
lstFs.Add(_plugin.XmlFSType); lstFs.Add(_plugin.XmlFSType);
Statistics.AddFilesystem(_plugin.XmlFSType.Type); Statistics.AddFilesystem(_plugin.XmlFSType.Type);
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
} }
} }
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
@@ -496,6 +533,8 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
else else
{ {
dumpLog.WriteLine("Getting filesystem for whole device.");
xmlFileSysInfo = new PartitionType[1]; xmlFileSysInfo = new PartitionType[1];
xmlFileSysInfo[0] = new PartitionType xmlFileSysInfo[0] = new PartitionType
{ {
@@ -520,6 +559,7 @@ namespace DiscImageChef.Core.Devices.Dumping
_plugin.GetInformation(_imageFormat, wholePart, out string foo); _plugin.GetInformation(_imageFormat, wholePart, out string foo);
lstFs.Add(_plugin.XmlFSType); lstFs.Add(_plugin.XmlFSType);
Statistics.AddFilesystem(_plugin.XmlFSType.Type); Statistics.AddFilesystem(_plugin.XmlFSType.Type);
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
} }
} }
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body

View File

@@ -52,7 +52,7 @@ namespace DiscImageChef.Core.Devices.Dumping
internal class CompactDisc internal class CompactDisc
{ {
// TODO: Add support for resume file // TODO: Add support for resume file
internal static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref CICMMetadataType sidecar, ref MediaType dskType, bool separateSubchannel, ref Metadata.Resume resume) internal static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref CICMMetadataType sidecar, ref MediaType dskType, bool separateSubchannel, ref Metadata.Resume resume, ref DumpLog dumpLog)
{ {
MHDDLog mhddLog; MHDDLog mhddLog;
IBGLog ibgLog; IBGLog ibgLog;
@@ -84,6 +84,7 @@ namespace DiscImageChef.Core.Devices.Dumping
// We discarded all discs that falsify a TOC before requesting a real TOC // We discarded all discs that falsify a TOC before requesting a real TOC
// No TOC, no CD (or an empty one) // No TOC, no CD (or an empty one)
dumpLog.WriteLine("Reading full TOC");
bool tocSense = dev.ReadRawToc(out byte[] cmdBuf, out byte[] senseBuf, 1, dev.Timeout, out double duration); bool tocSense = dev.ReadRawToc(out byte[] cmdBuf, out byte[] senseBuf, 1, dev.Timeout, out double duration);
if(!tocSense) if(!tocSense)
{ {
@@ -101,6 +102,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].TOC.Image, tmpBuf); DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].TOC.Image, tmpBuf);
// ATIP exists on blank CDs // ATIP exists on blank CDs
dumpLog.WriteLine("Reading ATIP");
sense = dev.ReadAtip(out cmdBuf, out senseBuf, dev.Timeout, out duration); sense = dev.ReadAtip(out cmdBuf, out senseBuf, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -128,6 +130,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
} }
dumpLog.WriteLine("Reading Disc Information");
sense = dev.ReadDiscInformation(out cmdBuf, out senseBuf, MmcDiscInformationDataTypes.DiscInformation, dev.Timeout, out duration); sense = dev.ReadDiscInformation(out cmdBuf, out senseBuf, MmcDiscInformationDataTypes.DiscInformation, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -153,6 +156,7 @@ namespace DiscImageChef.Core.Devices.Dumping
int sessions = 1; int sessions = 1;
int firstTrackLastSession = 0; int firstTrackLastSession = 0;
dumpLog.WriteLine("Reading Session Information");
sense = dev.ReadSessionInfo(out cmdBuf, out senseBuf, dev.Timeout, out duration); sense = dev.ReadSessionInfo(out cmdBuf, out senseBuf, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -205,6 +209,7 @@ namespace DiscImageChef.Core.Devices.Dumping
dskType = MediaType.CDV; dskType = MediaType.CDV;
} }
dumpLog.WriteLine("Reading PMA");
sense = dev.ReadPma(out cmdBuf, out senseBuf, dev.Timeout, out duration); sense = dev.ReadPma(out cmdBuf, out senseBuf, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -222,6 +227,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
} }
dumpLog.WriteLine("Reading CD-Text from Lead-In");
sense = dev.ReadCdText(out cmdBuf, out senseBuf, dev.Timeout, out duration); sense = dev.ReadCdText(out cmdBuf, out senseBuf, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -395,10 +401,14 @@ namespace DiscImageChef.Core.Devices.Dumping
readBuffer = null; readBuffer = null;
dumpLog.WriteLine("Reading Lead-in");
for(int leadInBlock = -150; leadInBlock < 0 && resume.NextBlock == 0; leadInBlock++) for(int leadInBlock = -150; leadInBlock < 0 && resume.NextBlock == 0; leadInBlock++)
{ {
if(aborted) if(aborted)
{
dumpLog.WriteLine("Aborted!");
break; break;
}
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
if(currentSpeed > maxSpeed && currentSpeed != 0) if(currentSpeed > maxSpeed && currentSpeed != 0)
@@ -454,6 +464,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Got {0} lead-in sectors.", leadInSectorsGood); DicConsole.WriteLine("Got {0} lead-in sectors.", leadInSectorsGood);
dumpLog.WriteLine("Got {0} Lead-in sectors.", leadInSectorsGood);
while(true) while(true)
{ {
@@ -471,12 +482,19 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dev.Error) if(dev.Error)
{ {
DicConsole.WriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError);
DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError); DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError);
return; return;
} }
DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead);
dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize);
dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize);
dumpLog.WriteLine("SCSI device type: {0}.", dev.SCSIType);
dumpLog.WriteLine("Media identified as {0}.", dskType);
dumpFile = new DataFile(outputPrefix + ".bin"); dumpFile = new DataFile(outputPrefix + ".bin");
DataFile subFile = null; DataFile subFile = null;
if(separateSubchannel) if(separateSubchannel)
@@ -487,10 +505,15 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpFile.Seek(resume.NextBlock, (ulong)sectorSize); dumpFile.Seek(resume.NextBlock, (ulong)sectorSize);
if(separateSubchannel) if(separateSubchannel)
subFile.Seek(resume.NextBlock, subSize); subFile.Seek(resume.NextBlock, subSize);
if(resume.NextBlock > 0)
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
start = DateTime.UtcNow; start = DateTime.UtcNow;
for(int t = 0; t < tracks.Count(); t++) for(int t = 0; t < tracks.Count(); t++)
{ {
dumpLog.WriteLine("Reading track {0}", t);
tracks[t].BytesPerSector = sectorSize; tracks[t].BytesPerSector = sectorSize;
tracks[t].Image = new ImageType tracks[t].Image = new ImageType
{ {
@@ -527,6 +550,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -592,6 +616,7 @@ namespace DiscImageChef.Core.Devices.Dumping
mhddLog.Write(i, cmdDuration); mhddLog.Write(i, cmdDuration);
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
dumpLog.WriteLine("Error reading {0} sectors from sector {1}.", blocksToRead, i);
} }
if(tracks[t].TrackType1 == TrackTypeTrackType.mode1 && !checkedDataFormat) if(tracks[t].TrackType1 == TrackTypeTrackType.mode1 && !checkedDataFormat)
@@ -630,6 +655,8 @@ namespace DiscImageChef.Core.Devices.Dumping
#pragma warning disable IDE0004 // Remove Unnecessary Cast #pragma warning disable IDE0004 // Remove Unnecessary Cast
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath); ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath);
#pragma warning restore IDE0004 // Remove Unnecessary Cast #pragma warning restore IDE0004 // Remove Unnecessary Cast
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
#region Compact Disc Error handling #region Compact Disc Error handling
if(resume.BadBlocks.Count > 0 && !aborted) if(resume.BadBlocks.Count > 0 && !aborted)
@@ -645,6 +672,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -665,6 +693,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
resume.BadBlocks.Remove(badSector); resume.BadBlocks.Remove(badSector);
extents.Add(badSector); extents.Add(badSector);
dumpLog.WriteLine("Correctly retried sector {0} in pass {1}.", badSector, pass);
} }
if(separateSubchannel) if(separateSubchannel)
@@ -728,6 +757,7 @@ namespace DiscImageChef.Core.Devices.Dumping
md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType); md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType);
md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType); md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType);
dumpLog.WriteLine("Sending MODE SELECT to drive.");
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration); sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration);
if(sense) if(sense)
{ {
@@ -754,6 +784,7 @@ namespace DiscImageChef.Core.Devices.Dumping
md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType); md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType);
md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType); md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType);
dumpLog.WriteLine("Sending MODE SELECT to drive.");
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration); sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration);
if(sense) if(sense)
{ {
@@ -773,6 +804,7 @@ namespace DiscImageChef.Core.Devices.Dumping
subFile.Seek(0, SeekOrigin.Begin); subFile.Seek(0, SeekOrigin.Begin);
blocksToRead = 500; blocksToRead = 500;
dumpLog.WriteLine("Checksum starts.");
for(int t = 0; t < tracks.Count(); t++) for(int t = 0; t < tracks.Count(); t++)
{ {
Checksum trkChk = new Checksum(); Checksum trkChk = new Checksum();
@@ -781,7 +813,10 @@ namespace DiscImageChef.Core.Devices.Dumping
for(ulong i = (ulong)tracks[t].StartSector; i <= (ulong)tracks[t].EndSector; i += blocksToRead) for(ulong i = (ulong)tracks[t].StartSector; i <= (ulong)tracks[t].EndSector; i += blocksToRead)
{ {
if(aborted) if(aborted)
{
dumpLog.WriteLine("Aborted!");
break; break;
}
if(((ulong)tracks[t].EndSector + 1 - i) < blocksToRead) if(((ulong)tracks[t].EndSector + 1 - i) < blocksToRead)
blocksToRead = (uint)((ulong)tracks[t].EndSector + 1 - i); blocksToRead = (uint)((ulong)tracks[t].EndSector + 1 - i);
@@ -828,6 +863,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
dumpFile.Close(); dumpFile.Close();
end = DateTime.UtcNow; end = DateTime.UtcNow;
dumpLog.WriteLine("Checksum finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
// TODO: Correct this // TODO: Correct this
sidecar.OpticalDisc[0].Checksums = dataChk.End().ToArray(); sidecar.OpticalDisc[0].Checksums = dataChk.End().ToArray();

View File

@@ -39,13 +39,14 @@ using System;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Devices; using DiscImageChef.Devices;
using DiscImageChef.Core.Logging;
using Schemas; using Schemas;
namespace DiscImageChef.Core.Devices.Dumping namespace DiscImageChef.Core.Devices.Dumping
{ {
internal static class MMC internal static class MMC
{ {
internal static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref CICMMetadataType sidecar, ref MediaType dskType, bool separateSubchannel, ref Metadata.Resume resume) internal static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref CICMMetadataType sidecar, ref MediaType dskType, bool separateSubchannel, ref Metadata.Resume resume, ref DumpLog dumpLog)
{ {
byte[] cmdBuf = null; byte[] cmdBuf = null;
byte[] senseBuf = null; byte[] senseBuf = null;
@@ -60,11 +61,14 @@ namespace DiscImageChef.Core.Devices.Dumping
sidecar.OpticalDisc = new OpticalDiscType[1]; sidecar.OpticalDisc = new OpticalDiscType[1];
sidecar.OpticalDisc[0] = new OpticalDiscType(); sidecar.OpticalDisc[0] = new OpticalDiscType();
// TODO: Log not only what is it reading, but if it was read correctly or not.
sense = dev.GetConfiguration(out cmdBuf, out senseBuf, 0, MmcGetConfigurationRt.Current, dev.Timeout, out duration); sense = dev.GetConfiguration(out cmdBuf, out senseBuf, 0, MmcGetConfigurationRt.Current, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
Decoders.SCSI.MMC.Features.SeparatedFeatures ftr = Decoders.SCSI.MMC.Features.Separate(cmdBuf); Decoders.SCSI.MMC.Features.SeparatedFeatures ftr = Decoders.SCSI.MMC.Features.Separate(cmdBuf);
currentProfile = ftr.CurrentProfile; currentProfile = ftr.CurrentProfile;
dumpLog.WriteLine("Device reports current profile is 0x{0:X4}", ftr.CurrentProfile);
switch(ftr.CurrentProfile) switch(ftr.CurrentProfile)
{ {
@@ -163,16 +167,18 @@ namespace DiscImageChef.Core.Devices.Dumping
if(compactDisc) if(compactDisc)
{ {
CompactDisc.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, separateSubchannel, ref resume); CompactDisc.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, separateSubchannel, ref resume, ref dumpLog);
return; return;
} }
Reader scsiReader = new Reader(dev, dev.Timeout, null, dumpRaw); Reader scsiReader = new Reader(dev, dev.Timeout, null, dumpRaw);
blocks = scsiReader.GetDeviceBlocks(); blocks = scsiReader.GetDeviceBlocks();
dumpLog.WriteLine("Device reports disc has {0} blocks", blocks);
#region Nintendo #region Nintendo
if(dskType == MediaType.Unknown && blocks > 0) if(dskType == MediaType.Unknown && blocks > 0)
{ {
dumpLog.WriteLine("Reading Physical Format Information");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PhysicalInformation, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PhysicalInformation, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -182,6 +188,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(nintendoPfi.Value.DiskCategory == Decoders.DVD.DiskCategory.Nintendo && if(nintendoPfi.Value.DiskCategory == Decoders.DVD.DiskCategory.Nintendo &&
nintendoPfi.Value.PartVersion == 15) nintendoPfi.Value.PartVersion == 15)
{ {
dumpLog.WriteLine("Dumping Nintendo GameCube or Wii discs is not yet implemented.");
throw new NotImplementedException("Dumping Nintendo GameCube or Wii discs is not yet implemented."); throw new NotImplementedException("Dumping Nintendo GameCube or Wii discs is not yet implemented.");
} }
} }
@@ -200,7 +207,7 @@ namespace DiscImageChef.Core.Devices.Dumping
dskType == MediaType.HDDVDROM || dskType == MediaType.HDDVDRW || dskType == MediaType.HDDVDROM || dskType == MediaType.HDDVDRW ||
dskType == MediaType.HDDVDRWDL) dskType == MediaType.HDDVDRWDL)
{ {
dumpLog.WriteLine("Reading Physical Format Information");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PhysicalInformation, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PhysicalInformation, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -279,6 +286,8 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
} }
} }
dumpLog.WriteLine("Reading Disc Manufacturing Information");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DiscManufacturingInformation, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DiscManufacturingInformation, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -301,7 +310,10 @@ namespace DiscImageChef.Core.Devices.Dumping
if(sense || !Decoders.SCSI.Inquiry.Decode(inqBuf).HasValue || if(sense || !Decoders.SCSI.Inquiry.Decode(inqBuf).HasValue ||
(Decoders.SCSI.Inquiry.Decode(inqBuf).HasValue && !Decoders.SCSI.Inquiry.Decode(inqBuf).Value.KreonPresent)) (Decoders.SCSI.Inquiry.Decode(inqBuf).HasValue && !Decoders.SCSI.Inquiry.Decode(inqBuf).Value.KreonPresent))
{
dumpLog.WriteLine("Dumping Xbox Game Discs requires a drive with Kreon firmware.");
throw new NotImplementedException("Dumping Xbox Game Discs requires a drive with Kreon firmware."); throw new NotImplementedException("Dumping Xbox Game Discs requires a drive with Kreon firmware.");
}
if(dumpRaw && !force) if(dumpRaw && !force)
{ {
@@ -332,6 +344,7 @@ namespace DiscImageChef.Core.Devices.Dumping
#region DVD-ROM #region DVD-ROM
if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDROM) if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDROM)
{ {
dumpLog.WriteLine("Reading Lead-in Copyright Information.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.CopyrightInformation, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.CopyrightInformation, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -359,6 +372,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDROM || if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDROM ||
dskType == MediaType.HDDVDROM) dskType == MediaType.HDDVDROM)
{ {
dumpLog.WriteLine("Reading Burst Cutting Area.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.BurstCuttingArea, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.BurstCuttingArea, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -378,6 +392,7 @@ namespace DiscImageChef.Core.Devices.Dumping
#region DVD-RAM and HD DVD-RAM #region DVD-RAM and HD DVD-RAM
if(dskType == MediaType.DVDRAM || dskType == MediaType.HDDVDRAM) if(dskType == MediaType.DVDRAM || dskType == MediaType.HDDVDRAM)
{ {
dumpLog.WriteLine("Reading Disc Description Structure.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DVDRAM_DDS, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DVDRAM_DDS, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -395,6 +410,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
} }
dumpLog.WriteLine("Reading Spare Area Information.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DVDRAM_SpareAreaInformation, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DVDRAM_SpareAreaInformation, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -417,6 +433,7 @@ namespace DiscImageChef.Core.Devices.Dumping
#region DVD-R and DVD-RW #region DVD-R and DVD-RW
if(dskType == MediaType.DVDR || dskType == MediaType.DVDRW) if(dskType == MediaType.DVDR || dskType == MediaType.DVDRW)
{ {
dumpLog.WriteLine("Reading Pre-Recorded Information.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PreRecordedInfo, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PreRecordedInfo, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -436,6 +453,7 @@ namespace DiscImageChef.Core.Devices.Dumping
#region DVD-R, DVD-RW and HD DVD-R #region DVD-R, DVD-RW and HD DVD-R
if(dskType == MediaType.DVDR || dskType == MediaType.DVDRW || dskType == MediaType.HDDVDR) if(dskType == MediaType.DVDR || dskType == MediaType.DVDRW || dskType == MediaType.HDDVDR)
{ {
dumpLog.WriteLine("Reading Media Identifier.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DVDR_MediaIdentifier, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DVDR_MediaIdentifier, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -450,6 +468,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].MediaID.Image, tmpBuf); DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].MediaID.Image, tmpBuf);
} }
dumpLog.WriteLine("Reading Recordable Physical Information.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DVDR_PhysicalInformation, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DVDR_PhysicalInformation, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -470,6 +489,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dskType == MediaType.DVDPR || dskType == MediaType.DVDPRDL || if(dskType == MediaType.DVDPR || dskType == MediaType.DVDPRDL ||
dskType == MediaType.DVDPRW || dskType == MediaType.DVDPRWDL) dskType == MediaType.DVDPRW || dskType == MediaType.DVDPRWDL)
{ {
dumpLog.WriteLine("Reading ADdress In Pregroove.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.ADIP, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.ADIP, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -484,6 +504,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].ADIP.Image, tmpBuf); DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].ADIP.Image, tmpBuf);
} }
dumpLog.WriteLine("Reading Disc Control Blocks.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DCB, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DCB, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -503,6 +524,7 @@ namespace DiscImageChef.Core.Devices.Dumping
#region HD DVD-ROM #region HD DVD-ROM
if(dskType == MediaType.HDDVDROM) if(dskType == MediaType.HDDVDROM)
{ {
dumpLog.WriteLine("Reading Lead-in Copyright Information.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.HDDVD_CopyrightInformation, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.HDDVD_CopyrightInformation, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -523,6 +545,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dskType == MediaType.BDR || dskType == MediaType.BDRE || dskType == MediaType.BDROM || if(dskType == MediaType.BDR || dskType == MediaType.BDRE || dskType == MediaType.BDROM ||
dskType == MediaType.BDRXL || dskType == MediaType.BDREXL) dskType == MediaType.BDRXL || dskType == MediaType.BDREXL)
{ {
dumpLog.WriteLine("Reading Disc Information.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.DiscInformation, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.DiscInformation, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -540,6 +563,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
} }
dumpLog.WriteLine("Reading PAC.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.PAC, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.PAC, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -560,6 +584,7 @@ namespace DiscImageChef.Core.Devices.Dumping
#region BD-ROM only #region BD-ROM only
if(dskType == MediaType.BDROM) if(dskType == MediaType.BDROM)
{ {
dumpLog.WriteLine("Reading Burst Cutting Area.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.BD_BurstCuttingArea, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.BD_BurstCuttingArea, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -580,6 +605,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dskType == MediaType.BDR || dskType == MediaType.BDRE || if(dskType == MediaType.BDR || dskType == MediaType.BDRE ||
dskType == MediaType.BDRXL || dskType == MediaType.BDREXL) dskType == MediaType.BDRXL || dskType == MediaType.BDREXL)
{ {
dumpLog.WriteLine("Reading Disc Definition Structure.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.BD_DDS, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.BD_DDS, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -594,6 +620,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].DDS.Image, tmpBuf); DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].DDS.Image, tmpBuf);
} }
dumpLog.WriteLine("Reading Spare Area Information.");
sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.BD_SpareAreaInformation, 0, dev.Timeout, out duration); sense = dev.ReadDiscStructure(out cmdBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.BD_SpareAreaInformation, 0, dev.Timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -612,11 +639,11 @@ namespace DiscImageChef.Core.Devices.Dumping
if(isXbox) if(isXbox)
{ {
XGD.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, ref resume); XGD.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, ref resume, ref dumpLog);
return; return;
} }
SBC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, true, ref resume); SBC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, true, ref resume, ref dumpLog);
} }
} }
} }

View File

@@ -37,12 +37,13 @@
// //$Id$ // //$Id$
using System; using System;
using DiscImageChef.Devices; using DiscImageChef.Devices;
using DiscImageChef.Core.Logging;
namespace DiscImageChef.Core.Devices.Dumping namespace DiscImageChef.Core.Devices.Dumping
{ {
public static class NVMe public static class NVMe
{ {
public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref Metadata.Resume resume) public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref Metadata.Resume resume, ref DumpLog dumpLog)
{ {
throw new NotImplementedException("NVMe devices not yet supported."); throw new NotImplementedException("NVMe devices not yet supported.");
} }

View File

@@ -53,7 +53,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
internal static class SBC internal static class SBC
{ {
internal static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref CICMMetadataType sidecar, ref MediaType dskType, bool opticalDisc, ref Metadata.Resume resume) internal static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref CICMMetadataType sidecar, ref MediaType dskType, bool opticalDisc, ref Metadata.Resume resume, ref DumpLog dumpLog)
{ {
MHDDLog mhddLog; MHDDLog mhddLog;
IBGLog ibgLog; IBGLog ibgLog;
@@ -87,11 +87,13 @@ namespace DiscImageChef.Core.Devices.Dumping
e.Cancel = aborted = true; e.Cancel = aborted = true;
}; };
dumpLog.WriteLine("Initializing reader.");
Reader scsiReader = new Reader(dev, dev.Timeout, null, dumpRaw); Reader scsiReader = new Reader(dev, dev.Timeout, null, dumpRaw);
blocks = scsiReader.GetDeviceBlocks(); blocks = scsiReader.GetDeviceBlocks();
blockSize = scsiReader.LogicalBlockSize; blockSize = scsiReader.LogicalBlockSize;
if(scsiReader.FindReadCommand()) if(scsiReader.FindReadCommand())
{ {
dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", scsiReader.ErrorMessage);
DicConsole.ErrorWriteLine("Unable to read medium."); DicConsole.ErrorWriteLine("Unable to read medium.");
return; return;
} }
@@ -105,6 +107,7 @@ namespace DiscImageChef.Core.Devices.Dumping
// Check how many blocks to read, if error show and return // Check how many blocks to read, if error show and return
if(scsiReader.GetBlocksToRead()) if(scsiReader.GetBlocksToRead())
{ {
dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", scsiReader.ErrorMessage);
DicConsole.ErrorWriteLine(scsiReader.ErrorMessage); DicConsole.ErrorWriteLine(scsiReader.ErrorMessage);
return; return;
} }
@@ -114,6 +117,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(blocks == 0) if(blocks == 0)
{ {
dumpLog.WriteLine("ERROR: Unable to read medium or empty medium present...");
DicConsole.ErrorWriteLine("Unable to read medium or empty medium present..."); DicConsole.ErrorWriteLine("Unable to read medium or empty medium present...");
return; return;
} }
@@ -126,6 +130,16 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine("Media identified as {0}", dskType); DicConsole.WriteLine("Media identified as {0}", dskType);
dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize);
dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize);
dumpLog.WriteLine("Device reports {0} bytes per physical block.", scsiReader.LongBlockSize);
dumpLog.WriteLine("SCSI device type: {0}.", dev.SCSIType);
dumpLog.WriteLine("SCSI medium type: {0}.", scsiMediumType);
dumpLog.WriteLine("SCSI density type: {0}.", scsiDensityCode);
dumpLog.WriteLine("SCSI floppy mode page present: {0}.", containsFloppyPage);
dumpLog.WriteLine("Media identified as {0}.", dskType);
if(!opticalDisc) if(!opticalDisc)
{ {
sidecar.BlockMedia = new BlockMediaType[1]; sidecar.BlockMedia = new BlockMediaType[1];
@@ -136,6 +150,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
if(dev.IsUSB) if(dev.IsUSB)
{ {
dumpLog.WriteLine("Reading USB descriptors.");
sidecar.BlockMedia[0].USB = new USBType sidecar.BlockMedia[0].USB = new USBType
{ {
ProductID = dev.USBProductID, ProductID = dev.USBProductID,
@@ -152,6 +167,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dev.Type == DeviceType.ATAPI) if(dev.Type == DeviceType.ATAPI)
{ {
dumpLog.WriteLine("Requesting ATAPI IDENTIFY PACKET DEVICE.");
sense = dev.AtapiIdentify(out cmdBuf, out Decoders.ATA.AtaErrorRegistersCHS errorRegs); sense = dev.AtapiIdentify(out cmdBuf, out Decoders.ATA.AtaErrorRegistersCHS errorRegs);
if(!sense) if(!sense)
{ {
@@ -171,6 +187,7 @@ namespace DiscImageChef.Core.Devices.Dumping
sense = dev.ScsiInquiry(out cmdBuf, out senseBuf); sense = dev.ScsiInquiry(out cmdBuf, out senseBuf);
if(!sense) if(!sense)
{ {
dumpLog.WriteLine("Requesting SCSI INQUIRY.");
sidecar.BlockMedia[0].SCSI = new SCSIType sidecar.BlockMedia[0].SCSI = new SCSIType
{ {
Inquiry = new DumpType Inquiry = new DumpType
@@ -182,6 +199,7 @@ namespace DiscImageChef.Core.Devices.Dumping
}; };
DataFile.WriteTo("SCSI Dump", sidecar.BlockMedia[0].SCSI.Inquiry.Image, cmdBuf); DataFile.WriteTo("SCSI Dump", sidecar.BlockMedia[0].SCSI.Inquiry.Image, cmdBuf);
dumpLog.WriteLine("Reading SCSI Extended Vendor Page Descriptors.");
sense = dev.ScsiInquiry(out cmdBuf, out senseBuf, 0x00); sense = dev.ScsiInquiry(out cmdBuf, out senseBuf, 0x00);
if(!sense) if(!sense)
{ {
@@ -192,6 +210,7 @@ namespace DiscImageChef.Core.Devices.Dumping
List<EVPDType> evpds = new List<EVPDType>(); List<EVPDType> evpds = new List<EVPDType>();
foreach(byte page in pages) foreach(byte page in pages)
{ {
dumpLog.WriteLine("Requesting page {0:X2}h.", page);
sense = dev.ScsiInquiry(out cmdBuf, out senseBuf, page); sense = dev.ScsiInquiry(out cmdBuf, out senseBuf, page);
if(!sense) if(!sense)
{ {
@@ -212,6 +231,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
} }
dumpLog.WriteLine("Requesting MODE SENSE (10).");
sense = dev.ModeSense10(out cmdBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, 0xFF, 5, out duration); sense = dev.ModeSense10(out cmdBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, 0xFF, 5, out duration);
if(!sense || dev.Error) if(!sense || dev.Error)
{ {
@@ -235,6 +255,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
} }
dumpLog.WriteLine("Requesting MODE SENSE (6).");
sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration); sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration);
if(sense || dev.Error) if(sense || dev.Error)
sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration); sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration);
@@ -327,12 +348,15 @@ namespace DiscImageChef.Core.Devices.Dumping
if(currentTry == null || extents == null) if(currentTry == null || extents == null)
throw new Exception("Could not process resume file, not continuing..."); throw new Exception("Could not process resume file, not continuing...");
dumpFile.Seek(resume.NextBlock, blockSize); dumpFile.Seek(resume.NextBlock, blockSize);
if(resume.NextBlock > 0)
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead) for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
{ {
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -376,6 +400,7 @@ namespace DiscImageChef.Core.Devices.Dumping
mhddLog.Write(i, cmdDuration); mhddLog.Write(i, cmdDuration);
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i);
} }
#pragma warning disable IDE0004 // Remove Unnecessary Cast #pragma warning disable IDE0004 // Remove Unnecessary Cast
@@ -389,6 +414,8 @@ namespace DiscImageChef.Core.Devices.Dumping
#pragma warning disable IDE0004 // Remove Unnecessary Cast #pragma warning disable IDE0004 // Remove Unnecessary Cast
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath); ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath);
#pragma warning restore IDE0004 // Remove Unnecessary Cast #pragma warning restore IDE0004 // Remove Unnecessary Cast
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
#region Error handling #region Error handling
if(resume.BadBlocks.Count > 0 && !aborted) if(resume.BadBlocks.Count > 0 && !aborted)
@@ -404,6 +431,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -417,6 +445,7 @@ namespace DiscImageChef.Core.Devices.Dumping
resume.BadBlocks.Remove(badSector); resume.BadBlocks.Remove(badSector);
extents.Add(badSector); extents.Add(badSector);
dumpFile.WriteAt(readBuffer, badSector, blockSize); dumpFile.WriteAt(readBuffer, badSector, blockSize);
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
} }
else if(runningPersistent) else if(runningPersistent)
dumpFile.WriteAt(readBuffer, badSector, blockSize); dumpFile.WriteAt(readBuffer, badSector, blockSize);
@@ -507,6 +536,7 @@ namespace DiscImageChef.Core.Devices.Dumping
md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType); md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType);
} }
dumpLog.WriteLine("Sending MODE SELECT to drive.");
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration); sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration);
if(sense) if(sense)
{ {
@@ -533,6 +563,7 @@ namespace DiscImageChef.Core.Devices.Dumping
md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType); md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType);
md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType); md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType);
dumpLog.WriteLine("Sending MODE SELECT to drive.");
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration); sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration);
if(sense) if(sense)
{ {
@@ -550,10 +581,14 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpFile.Seek(0, SeekOrigin.Begin); dumpFile.Seek(0, SeekOrigin.Begin);
blocksToRead = 500; blocksToRead = 500;
dumpLog.WriteLine("Checksum starts.");
for(ulong i = 0; i < blocks; i += blocksToRead) for(ulong i = 0; i < blocks; i += blocksToRead)
{ {
if(aborted) if(aborted)
{
dumpLog.WriteLine("Aborted!");
break; break;
}
if((blocks - i) < blocksToRead) if((blocks - i) < blocksToRead)
blocksToRead = (uint)(blocks - i); blocksToRead = (uint)(blocks - i);
@@ -576,6 +611,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
dumpFile.Close(); dumpFile.Close();
end = DateTime.UtcNow; end = DateTime.UtcNow;
dumpLog.WriteLine("Checksum finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
PluginBase plugins = new PluginBase(); PluginBase plugins = new PluginBase();
plugins.RegisterAllPlugins(); plugins.RegisterAllPlugins();
@@ -604,8 +641,10 @@ namespace DiscImageChef.Core.Devices.Dumping
if(_imageFormat != null) if(_imageFormat != null)
{ {
dumpLog.WriteLine("Getting partitions.");
List<Partition> partitions = Partitions.GetAll(_imageFormat); List<Partition> partitions = Partitions.GetAll(_imageFormat);
Partitions.AddSchemesToStats(partitions); Partitions.AddSchemesToStats(partitions);
dumpLog.WriteLine("Found {0} partitions.", partitions.Count);
if(partitions.Count > 0) if(partitions.Count > 0)
{ {
@@ -622,6 +661,8 @@ namespace DiscImageChef.Core.Devices.Dumping
Type = partitions[i].Type Type = partitions[i].Type
}; };
List<FileSystemType> lstFs = new List<FileSystemType>(); List<FileSystemType> lstFs = new List<FileSystemType>();
dumpLog.WriteLine("Getting filesystems on partition {0}, starting at {1}, ending at {2}, with type {3}, under scheme {4}.",
i, partitions[i].Start, partitions[i].End, partitions[i].Type, partitions[i].Scheme);
foreach(Filesystem _plugin in plugins.PluginsList.Values) foreach(Filesystem _plugin in plugins.PluginsList.Values)
{ {
@@ -632,6 +673,7 @@ namespace DiscImageChef.Core.Devices.Dumping
_plugin.GetInformation(_imageFormat, partitions[i], out string foo); _plugin.GetInformation(_imageFormat, partitions[i], out string foo);
lstFs.Add(_plugin.XmlFSType); lstFs.Add(_plugin.XmlFSType);
Statistics.AddFilesystem(_plugin.XmlFSType.Type); Statistics.AddFilesystem(_plugin.XmlFSType.Type);
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
if(_plugin.XmlFSType.Type == "Opera") if(_plugin.XmlFSType.Type == "Opera")
dskType = MediaType.ThreeDO; dskType = MediaType.ThreeDO;
@@ -657,6 +699,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
else else
{ {
dumpLog.WriteLine("Getting filesystem for whole device.");
xmlFileSysInfo = new PartitionType[1]; xmlFileSysInfo = new PartitionType[1];
xmlFileSysInfo[0] = new PartitionType xmlFileSysInfo[0] = new PartitionType
{ {
@@ -681,6 +724,7 @@ namespace DiscImageChef.Core.Devices.Dumping
_plugin.GetInformation(_imageFormat, wholePart, out string foo); _plugin.GetInformation(_imageFormat, wholePart, out string foo);
lstFs.Add(_plugin.XmlFSType); lstFs.Add(_plugin.XmlFSType);
Statistics.AddFilesystem(_plugin.XmlFSType.Type); Statistics.AddFilesystem(_plugin.XmlFSType.Type);
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
if(_plugin.XmlFSType.Type == "Opera") if(_plugin.XmlFSType.Type == "Opera")
dskType = MediaType.ThreeDO; dskType = MediaType.ThreeDO;

View File

@@ -40,6 +40,7 @@ using System.IO;
using DiscImageChef.CommonTypes; using DiscImageChef.CommonTypes;
using DiscImageChef.Console; using DiscImageChef.Console;
using DiscImageChef.Devices; using DiscImageChef.Devices;
using DiscImageChef.Core.Logging;
using Schemas; using Schemas;
namespace DiscImageChef.Core.Devices.Dumping namespace DiscImageChef.Core.Devices.Dumping
@@ -47,7 +48,7 @@ namespace DiscImageChef.Core.Devices.Dumping
public class SCSI public class SCSI
{ {
// TODO: Get cartridge serial number from Certance vendor EVPD // TODO: Get cartridge serial number from Certance vendor EVPD
public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, bool separateSubchannel, ref Metadata.Resume resume) public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, bool separateSubchannel, ref Metadata.Resume resume, ref DumpLog dumpLog)
{ {
byte[] senseBuf = null; byte[] senseBuf = null;
bool sense = false; bool sense = false;
@@ -61,6 +62,7 @@ namespace DiscImageChef.Core.Devices.Dumping
Decoders.SCSI.FixedSense? decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); Decoders.SCSI.FixedSense? decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf);
if(decSense.HasValue) if(decSense.HasValue)
{ {
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
if(decSense.Value.ASC == 0x3A) if(decSense.Value.ASC == 0x3A)
{ {
int leftRetries = 5; int leftRetries = 5;
@@ -72,6 +74,9 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!sense) if(!sense)
break; break;
decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf);
if(decSense.HasValue)
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
leftRetries--; leftRetries--;
} }
@@ -92,6 +97,9 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!sense) if(!sense)
break; break;
decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf);
if(decSense.HasValue)
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
leftRetries--; leftRetries--;
} }
@@ -125,6 +133,9 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!sense) if(!sense)
break; break;
decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf);
if(decSense.HasValue)
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
leftRetries--; leftRetries--;
} }
@@ -155,17 +166,17 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dumpRaw) if(dumpRaw)
throw new ArgumentException("Tapes cannot be dumped raw."); throw new ArgumentException("Tapes cannot be dumped raw.");
SSC.Dump(dev, outputPrefix, devicePath, ref sidecar, ref resume); SSC.Dump(dev, outputPrefix, devicePath, ref sidecar, ref resume, ref dumpLog);
return; return;
} }
if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice) if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice)
{ {
MMC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, separateSubchannel, ref resume); MMC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, separateSubchannel, ref resume, ref dumpLog);
return; return;
} }
SBC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, false, ref resume); SBC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, false, ref resume, ref dumpLog);
} }
} }
} }

View File

@@ -48,7 +48,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
internal static class SSC internal static class SSC
{ {
internal static void Dump(Device dev, string outputPrefix, string devicePath, ref CICMMetadataType sidecar, ref Metadata.Resume resume) internal static void Dump(Device dev, string outputPrefix, string devicePath, ref CICMMetadataType sidecar, ref Metadata.Resume resume, ref DumpLog dumpLog)
{ {
Decoders.SCSI.FixedSense? fxSense; Decoders.SCSI.FixedSense? fxSense;
bool aborted; bool aborted;
@@ -73,6 +73,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(fxSense.HasValue && fxSense.Value.SenseKey != Decoders.SCSI.SenseKeys.NoSense) if(fxSense.HasValue && fxSense.Value.SenseKey != Decoders.SCSI.SenseKeys.NoSense)
{ {
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
DicConsole.ErrorWriteLine("Drive has status error, please correct. Sense follows..."); DicConsole.ErrorWriteLine("Drive has status error, please correct. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
return; return;
@@ -81,6 +82,7 @@ namespace DiscImageChef.Core.Devices.Dumping
// Not in BOM/P // Not in BOM/P
if(fxSense.HasValue && fxSense.Value.ASC == 0x00 && fxSense.Value.ASCQ != 0x00 && fxSense.Value.ASCQ != 0x04 && fxSense.Value.SenseKey != Decoders.SCSI.SenseKeys.IllegalRequest) if(fxSense.HasValue && fxSense.Value.ASC == 0x00 && fxSense.Value.ASCQ != 0x00 && fxSense.Value.ASCQ != 0x04 && fxSense.Value.SenseKey != Decoders.SCSI.SenseKeys.IllegalRequest)
{ {
dumpLog.WriteLine("Rewinding, please wait...");
DicConsole.Write("Rewinding, please wait..."); DicConsole.Write("Rewinding, please wait...");
// Rewind, let timeout apply // Rewind, let timeout apply
sense = dev.Rewind(out senseBuf, dev.Timeout, out duration); sense = dev.Rewind(out senseBuf, dev.Timeout, out duration);
@@ -104,6 +106,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
@@ -123,6 +127,8 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
DicConsole.ErrorWriteLine("Could not get position. Sense follows..."); DicConsole.ErrorWriteLine("Could not get position. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpLog.WriteLine("Could not get position. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
} }
@@ -132,6 +138,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(cmdBuf[1] != 0) if(cmdBuf[1] != 0)
{ {
DicConsole.Write("Drive not in partition 0. Rewinding, please wait..."); DicConsole.Write("Drive not in partition 0. Rewinding, please wait...");
dumpLog.WriteLine("Drive not in partition 0. Rewinding, please wait...");
// Rewind, let timeout apply // Rewind, let timeout apply
sense = dev.Locate(out senseBuf, false, 0, 0, dev.Timeout, out duration); sense = dev.Locate(out senseBuf, false, 0, 0, dev.Timeout, out duration);
if(sense) if(sense)
@@ -139,6 +146,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
@@ -159,6 +168,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
@@ -168,6 +179,8 @@ namespace DiscImageChef.Core.Devices.Dumping
fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense); fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense);
DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
@@ -175,6 +188,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(cmdBuf[1] != 0) if(cmdBuf[1] != 0)
{ {
DicConsole.ErrorWriteLine("Drive could not rewind to partition 0 but no error occurred..."); DicConsole.ErrorWriteLine("Drive could not rewind to partition 0 but no error occurred...");
dumpLog.WriteLine("Drive could not rewind to partition 0 but no error occurred...");
return; return;
} }
@@ -190,6 +204,7 @@ namespace DiscImageChef.Core.Devices.Dumping
byte scsiMediumTypeTape = 0; byte scsiMediumTypeTape = 0;
byte scsiDensityCodeTape = 0; byte scsiDensityCodeTape = 0;
dumpLog.WriteLine("Requesting MODE SENSE (10).");
sense = dev.ModeSense10(out cmdBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, 0xFF, 5, out duration); sense = dev.ModeSense10(out cmdBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, 0xFF, 5, out duration);
if(!sense || dev.Error) if(!sense || dev.Error)
{ {
@@ -213,6 +228,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
} }
dumpLog.WriteLine("Requesting MODE SENSE (6).");
sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration); sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration);
if(sense || dev.Error) if(sense || dev.Error)
sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration); sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration);
@@ -241,6 +257,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(decMode.Value.Header.BlockDescriptors != null && decMode.Value.Header.BlockDescriptors.Length >= 1) if(decMode.Value.Header.BlockDescriptors != null && decMode.Value.Header.BlockDescriptors.Length >= 1)
scsiDensityCodeTape = (byte)decMode.Value.Header.BlockDescriptors[0].Density; scsiDensityCodeTape = (byte)decMode.Value.Header.BlockDescriptors[0].Density;
blockSize = decMode.Value.Header.BlockDescriptors[0].BlockLength; blockSize = decMode.Value.Header.BlockDescriptors[0].BlockLength;
dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize);
} }
else else
blockSize = 1; blockSize = 1;
@@ -250,6 +267,11 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine("Media identified as {0}", dskType); DicConsole.WriteLine("Media identified as {0}", dskType);
dumpLog.WriteLine("SCSI device type: {0}.", dev.SCSIType);
dumpLog.WriteLine("SCSI medium type: {0}.", scsiMediumTypeTape);
dumpLog.WriteLine("SCSI density type: {0}.", scsiDensityCodeTape);
dumpLog.WriteLine("Media identified as {0}.", dskType);
bool endOfMedia = false; bool endOfMedia = false;
ulong currentBlock = 0; ulong currentBlock = 0;
ulong currentFile = 0; ulong currentFile = 0;
@@ -279,6 +301,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.ErrorWriteLine("Drive could not return back. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not return back. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpLog.WriteLine("Drive could not return back. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
} }
@@ -291,6 +315,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.ErrorWriteLine("Drive could not read. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not read. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpLog.WriteLine("Drive could not read. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
} }
@@ -299,6 +325,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.ErrorWriteLine("Drive could not read. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not read. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpLog.WriteLine("Drive could not read. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
} }
@@ -306,6 +334,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.ErrorWriteLine("Cannot read device, don't know why, exiting..."); DicConsole.ErrorWriteLine("Cannot read device, don't know why, exiting...");
dumpLog.WriteLine("Cannot read device, don't know why, exiting...");
return; return;
} }
} }
@@ -319,6 +348,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.ErrorWriteLine("Drive could not return back. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not return back. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpLog.WriteLine("Drive could not return back. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
} }
@@ -374,12 +405,16 @@ namespace DiscImageChef.Core.Devices.Dumping
while(currentPartition < totalPartitions) while(currentPartition < totalPartitions)
{ {
if(aborted) if(aborted)
{
dumpLog.WriteLine("Aborted!");
break; break;
}
if(endOfMedia) if(endOfMedia)
{ {
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Finished partition {0}", currentPartition); DicConsole.WriteLine("Finished partition {0}", currentPartition);
dumpLog.WriteLine("Finished partition {0}", currentPartition);
currentTapePartition.File = files.ToArray(); currentTapePartition.File = files.ToArray();
currentTapePartition.Checksums = partitionChk.End().ToArray(); currentTapePartition.Checksums = partitionChk.End().ToArray();
currentTapePartition.EndBlock = (long)(currentBlock - 1); currentTapePartition.EndBlock = (long)(currentBlock - 1);
@@ -451,6 +486,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Blocksize changed to {0} bytes at block {1}", blockSize, currentBlock); DicConsole.WriteLine("Blocksize changed to {0} bytes at block {1}", blockSize, currentBlock);
dumpLog.WriteLine("Blocksize changed to {0} bytes at block {1}", blockSize, currentBlock);
sense = dev.Space(out senseBuf, SscSpaceCodes.LogicalBlock, -1, dev.Timeout, out duration); sense = dev.Space(out senseBuf, SscSpaceCodes.LogicalBlock, -1, dev.Timeout, out duration);
totalDuration += duration; totalDuration += duration;
@@ -462,6 +498,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.ErrorWriteLine("Drive could not go back one block. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not go back one block. Sense follows...");
DicConsole.ErrorWriteLine("{0}", strSense); DicConsole.ErrorWriteLine("{0}", strSense);
dumpFile.Close(); dumpFile.Close();
dumpLog.WriteLine("Drive could not go back one block. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
@@ -475,6 +513,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.ErrorWriteLine("Cannot dump a blank tape..."); DicConsole.ErrorWriteLine("Cannot dump a blank tape...");
dumpFile.Close(); dumpFile.Close();
dumpLog.WriteLine("Cannot dump a blank tape...");
return; return;
} }
@@ -483,12 +522,14 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
// TODO: Detect end of partition // TODO: Detect end of partition
endOfMedia = true; endOfMedia = true;
dumpLog.WriteLine("Found end-of-tape/partition...");
continue; continue;
} }
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Blank block found, end of tape?"); DicConsole.WriteLine("Blank block found, end of tape?");
endOfMedia = true; endOfMedia = true;
dumpLog.WriteLine("Blank block found, end of tape?...");
continue; continue;
} }
@@ -497,6 +538,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
// TODO: Detect end of partition // TODO: Detect end of partition
endOfMedia = true; endOfMedia = true;
dumpLog.WriteLine("Found end-of-tape/partition...");
continue; continue;
} }
@@ -527,6 +569,7 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
DicConsole.WriteLine("Changed to file {0} at block {1}", currentFile, currentBlock); DicConsole.WriteLine("Changed to file {0} at block {1}", currentFile, currentBlock);
dumpLog.WriteLine("Changed to file {0} at block {1}", currentFile, currentBlock);
continue; continue;
} }
@@ -534,6 +577,8 @@ namespace DiscImageChef.Core.Devices.Dumping
fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense); fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense);
DicConsole.ErrorWriteLine("Drive could not read block. Sense follows..."); DicConsole.ErrorWriteLine("Drive could not read block. Sense follows...");
DicConsole.ErrorWriteLine("{0} {1}", fxSense.Value.SenseKey, strSense); DicConsole.ErrorWriteLine("{0} {1}", fxSense.Value.SenseKey, strSense);
dumpLog.WriteLine("Drive could not read block. Sense follows...");
dumpLog.WriteLine("Device not ready. Sense {0:X2}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
return; return;
} }
@@ -562,6 +607,9 @@ namespace DiscImageChef.Core.Devices.Dumping
end = DateTime.UtcNow; end = DateTime.UtcNow;
mhddLog.Close(); mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath); ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming).", (end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000); DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming).", (end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000);
#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created #pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created

View File

@@ -53,7 +53,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
public class SecureDigital public class SecureDigital
{ {
public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref Metadata.Resume resume) public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref Metadata.Resume resume, ref DumpLog dumpLog)
{ {
bool aborted; bool aborted;
MHDDLog mhddLog; MHDDLog mhddLog;
@@ -99,6 +99,7 @@ namespace DiscImageChef.Core.Devices.Dumping
ExtendedCSD ecsdDecoded = new ExtendedCSD(); ExtendedCSD ecsdDecoded = new ExtendedCSD();
CSD csdDecoded = new CSD(); CSD csdDecoded = new CSD();
dumpLog.WriteLine("Reading Extended CSD");
sense = dev.ReadExtendedCSD(out ecsd, out response, timeout, out duration); sense = dev.ReadExtendedCSD(out ecsd, out response, timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -116,6 +117,7 @@ namespace DiscImageChef.Core.Devices.Dumping
else else
ecsd = null; ecsd = null;
dumpLog.WriteLine("Reading CSD");
sense = dev.ReadCSD(out csd, out response, timeout, out duration); sense = dev.ReadCSD(out csd, out response, timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -129,6 +131,7 @@ namespace DiscImageChef.Core.Devices.Dumping
else else
csd = null; csd = null;
dumpLog.WriteLine("Reading OCR");
sense = dev.ReadOCR(out ocr, out response, timeout, out duration); sense = dev.ReadOCR(out ocr, out response, timeout, out duration);
if(sense) if(sense)
ocr = null; ocr = null;
@@ -139,6 +142,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
Decoders.SecureDigital.CSD csdDecoded = new Decoders.SecureDigital.CSD(); Decoders.SecureDigital.CSD csdDecoded = new Decoders.SecureDigital.CSD();
dumpLog.WriteLine("Reading CSD");
sense = dev.ReadCSD(out csd, out response, timeout, out duration); sense = dev.ReadCSD(out csd, out response, timeout, out duration);
if(!sense) if(!sense)
{ {
@@ -151,10 +155,12 @@ namespace DiscImageChef.Core.Devices.Dumping
else else
csd = null; csd = null;
dumpLog.WriteLine("Reading OCR");
sense = dev.ReadSDOCR(out ocr, out response, timeout, out duration); sense = dev.ReadSDOCR(out ocr, out response, timeout, out duration);
if(sense) if(sense)
ocr = null; ocr = null;
dumpLog.WriteLine("Reading SCR");
sense = dev.ReadSCR(out scr, out response, timeout, out duration); sense = dev.ReadSCR(out scr, out response, timeout, out duration);
if(sense) if(sense)
scr = null; scr = null;
@@ -162,6 +168,7 @@ namespace DiscImageChef.Core.Devices.Dumping
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType(); sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
} }
dumpLog.WriteLine("Reading CID");
sense = dev.ReadCID(out cid, out response, timeout, out duration); sense = dev.ReadCID(out cid, out response, timeout, out duration);
if(sense) if(sense)
cid = null; cid = null;
@@ -253,9 +260,11 @@ namespace DiscImageChef.Core.Devices.Dumping
if(blocks == 0) if(blocks == 0)
{ {
dumpLog.WriteLine("Cannot get device size.");
DicConsole.ErrorWriteLine("Unable to get device size."); DicConsole.ErrorWriteLine("Unable to get device size.");
return; return;
} }
dumpLog.WriteLine("Device reports {0} blocks.", blocks);
byte[] cmdBuf; byte[] cmdBuf;
bool error = true; bool error = true;
@@ -274,138 +283,151 @@ namespace DiscImageChef.Core.Devices.Dumping
if(error) if(error)
{ {
blocksToRead = 1; blocksToRead = 1;
dumpLog.WriteLine("ERROR: Cannot get blocks to read, device error {0}.", dev.LastError);
DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError); DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError);
return; return;
} }
dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
// bool removable = false || (!dev.IsCompactFlash && ataId.GeneralConfiguration.HasFlag(Decoders.ATA.Identify.GeneralConfigurationBit.Removable));
DumpHardwareType currentTry = null; DumpHardwareType currentTry = null;
ExtentsULong extents = null; ExtentsULong extents = null;
ResumeSupport.Process(true, false, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformID, ref resume, ref currentTry, ref extents); ResumeSupport.Process(true, false, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformID, ref resume, ref currentTry, ref extents);
if(currentTry == null || extents == null) if(currentTry == null || extents == null)
throw new Exception("Could not process resume file, not continuing..."); throw new Exception("Could not process resume file, not continuing...");
DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead);
mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead); mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
ibgLog = new IBGLog(outputPrefix + ".ibg", currentProfile); ibgLog = new IBGLog(outputPrefix + ".ibg", currentProfile);
dumpFile = new DataFile(outputPrefix + ".bin"); dumpFile = new DataFile(outputPrefix + ".bin");
dumpFile.Seek(resume.NextBlock, blockSize); dumpFile.Seek(resume.NextBlock, blockSize);
if(resume.NextBlock > 0)
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
start = DateTime.UtcNow; start = DateTime.UtcNow;
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead) for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
{
if(aborted)
{
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break;
}
if((blocks - i) < blocksToRead)
blocksToRead = (byte)(blocks - i);
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
if(currentSpeed > maxSpeed && currentSpeed != 0)
maxSpeed = currentSpeed;
if(currentSpeed < minSpeed && currentSpeed != 0)
minSpeed = currentSpeed;
#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed);
error = dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, byteAddressed, timeout, out duration);
if(!error)
{
mhddLog.Write(i, duration);
ibgLog.Write(i, currentSpeed * 1024);
dumpFile.Write(cmdBuf);
extents.Add(i, blocksToRead, true);
}
else
{
for(ulong b = i; b < i + blocksToRead; b++)
resume.BadBlocks.Add(b);
if(duration < 500)
mhddLog.Write(i, 65535);
else
mhddLog.Write(i, duration);
ibgLog.Write(i, 0);
dumpFile.Write(new byte[blockSize * blocksToRead]);
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i);
}
#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created
currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (duration / (double)1000);
#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created
GC.Collect();
resume.NextBlock = i + blocksToRead;
}
end = DateTime.Now;
DicConsole.WriteLine();
mhddLog.Close();
#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath);
#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
#region Error handling
if(resume.BadBlocks.Count > 0 && !aborted)
{
int pass = 0;
bool forward = true;
bool runningPersistent = false;
repeatRetryLba:
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{ {
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
if((blocks - i) < blocksToRead) DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "");
blocksToRead = (byte)(blocks - i);
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
if(currentSpeed > maxSpeed && currentSpeed != 0)
maxSpeed = currentSpeed;
if(currentSpeed < minSpeed && currentSpeed != 0)
minSpeed = currentSpeed;
#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed);
error = dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, byteAddressed, timeout, out duration);
if(!error)
{
mhddLog.Write(i, duration);
ibgLog.Write(i, currentSpeed * 1024);
dumpFile.Write(cmdBuf);
extents.Add(i, blocksToRead, true);
}
else
{
for(ulong b = i; b < i + blocksToRead; b++)
resume.BadBlocks.Add(b);
if(duration < 500)
mhddLog.Write(i, 65535);
else
mhddLog.Write(i, duration);
ibgLog.Write(i, 0);
dumpFile.Write(new byte[blockSize * blocksToRead]);
}
#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created
currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (duration / (double)1000);
#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created
GC.Collect();
resume.NextBlock = i + blocksToRead;
}
end = DateTime.Now;
DicConsole.WriteLine();
mhddLog.Close();
#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath);
#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created
#region Error handling
if(resume.BadBlocks.Count > 0 && !aborted)
{
int pass = 0;
bool forward = true;
bool runningPersistent = false;
repeatRetryLba:
ulong[] tmpArray = resume.BadBlocks.ToArray();
foreach(ulong badSector in tmpArray)
{
if(aborted)
{
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
break;
}
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "");
error = dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout, out duration); error = dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout, out duration);
totalDuration += duration; totalDuration += duration;
if(!error) if(!error)
{
resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
dumpFile.WriteAt(cmdBuf, badSector, blockSize);
}
else if(runningPersistent)
dumpFile.WriteAt(cmdBuf, badSector, blockSize);
}
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
{ {
pass++; resume.BadBlocks.Remove(badSector);
forward = !forward; extents.Add(badSector);
resume.BadBlocks.Sort(); dumpFile.WriteAt(cmdBuf, badSector, blockSize);
resume.BadBlocks.Reverse(); dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
goto repeatRetryLba;
} }
else if(runningPersistent)
DicConsole.WriteLine(); dumpFile.WriteAt(cmdBuf, badSector, blockSize);
} }
#endregion Error handling
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
{
pass++;
forward = !forward;
resume.BadBlocks.Sort();
resume.BadBlocks.Reverse();
goto repeatRetryLba;
}
dataChk = new Checksum(); DicConsole.WriteLine();
}
#endregion Error handling
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dataChk = new Checksum();
dumpFile.Seek(0, SeekOrigin.Begin); dumpFile.Seek(0, SeekOrigin.Begin);
blocksToRead = 500; blocksToRead = 500;
dumpLog.WriteLine("Checksum starts.");
for(ulong i = 0; i < blocks; i += blocksToRead) for(ulong i = 0; i < blocks; i += blocksToRead)
{ {
if(aborted) if(aborted)
{
dumpLog.WriteLine("Aborted!");
break; break;
}
if((blocks - i) < blocksToRead) if((blocks - i) < blocksToRead)
blocksToRead = (byte)(blocks - i); blocksToRead = (byte)(blocks - i);
@@ -426,6 +448,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
dumpFile.Close(); dumpFile.Close();
end = DateTime.UtcNow; end = DateTime.UtcNow;
dumpLog.WriteLine("Checksum finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
PluginBase plugins = new PluginBase(); PluginBase plugins = new PluginBase();
plugins.RegisterAllPlugins(); plugins.RegisterAllPlugins();
@@ -455,8 +479,10 @@ namespace DiscImageChef.Core.Devices.Dumping
if(_imageFormat != null) if(_imageFormat != null)
{ {
dumpLog.WriteLine("Getting partitions.");
List<Partition> partitions = Partitions.GetAll(_imageFormat); List<Partition> partitions = Partitions.GetAll(_imageFormat);
Partitions.AddSchemesToStats(partitions); Partitions.AddSchemesToStats(partitions);
dumpLog.WriteLine("Found {0} partitions.", partitions.Count);
if(partitions.Count > 0) if(partitions.Count > 0)
{ {
@@ -473,6 +499,8 @@ namespace DiscImageChef.Core.Devices.Dumping
Type = partitions[i].Type Type = partitions[i].Type
}; };
List<FileSystemType> lstFs = new List<FileSystemType>(); List<FileSystemType> lstFs = new List<FileSystemType>();
dumpLog.WriteLine("Getting filesystems on partition {0}, starting at {1}, ending at {2}, with type {3}, under scheme {4}.",
i, partitions[i].Start, partitions[i].End, partitions[i].Type, partitions[i].Scheme);
foreach(Filesystem _plugin in plugins.PluginsList.Values) foreach(Filesystem _plugin in plugins.PluginsList.Values)
{ {
@@ -483,6 +511,7 @@ namespace DiscImageChef.Core.Devices.Dumping
_plugin.GetInformation(_imageFormat, partitions[i], out string foo); _plugin.GetInformation(_imageFormat, partitions[i], out string foo);
lstFs.Add(_plugin.XmlFSType); lstFs.Add(_plugin.XmlFSType);
Statistics.AddFilesystem(_plugin.XmlFSType.Type); Statistics.AddFilesystem(_plugin.XmlFSType.Type);
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
} }
} }
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
@@ -499,6 +528,8 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
else else
{ {
dumpLog.WriteLine("Getting filesystem for whole device.");
xmlFileSysInfo = new PartitionType[1]; xmlFileSysInfo = new PartitionType[1];
xmlFileSysInfo[0] = new PartitionType xmlFileSysInfo[0] = new PartitionType
{ {
@@ -523,6 +554,7 @@ namespace DiscImageChef.Core.Devices.Dumping
_plugin.GetInformation(_imageFormat, wholePart, out string foo); _plugin.GetInformation(_imageFormat, wholePart, out string foo);
lstFs.Add(_plugin.XmlFSType); lstFs.Add(_plugin.XmlFSType);
Statistics.AddFilesystem(_plugin.XmlFSType.Type); Statistics.AddFilesystem(_plugin.XmlFSType.Type);
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
} }
} }
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body

View File

@@ -53,7 +53,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
internal static class XGD internal static class XGD
{ {
internal static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref CICMMetadataType sidecar, ref MediaType dskType, ref Metadata.Resume resume) internal static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref CICMMetadataType sidecar, ref MediaType dskType, ref Metadata.Resume resume, ref DumpLog dumpLog)
{ {
MHDDLog mhddLog; MHDDLog mhddLog;
IBGLog ibgLog; IBGLog ibgLog;
@@ -77,16 +77,20 @@ namespace DiscImageChef.Core.Devices.Dumping
e.Cancel = aborted = true; e.Cancel = aborted = true;
}; };
dumpLog.WriteLine("Reading Xbox Security Sector.");
sense = dev.KreonExtractSS(out byte[] ssBuf, out byte[] senseBuf, dev.Timeout, out double duration); sense = dev.KreonExtractSS(out byte[] ssBuf, out byte[] senseBuf, dev.Timeout, out double duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot get Xbox Security Sector, not continuing.");
DicConsole.ErrorWriteLine("Cannot get Xbox Security Sector, not continuing."); DicConsole.ErrorWriteLine("Cannot get Xbox Security Sector, not continuing.");
return; return;
} }
dumpLog.WriteLine("Decoding Xbox Security Sector.");
Decoders.Xbox.SS.SecuritySector? xboxSS = Decoders.Xbox.SS.Decode(ssBuf); Decoders.Xbox.SS.SecuritySector? xboxSS = Decoders.Xbox.SS.Decode(ssBuf);
if(!xboxSS.HasValue) if(!xboxSS.HasValue)
{ {
dumpLog.WriteLine("Cannot decode Xbox Security Sector, not continuing.");
DicConsole.ErrorWriteLine("Cannot decode Xbox Security Sector, not continuing."); DicConsole.ErrorWriteLine("Cannot decode Xbox Security Sector, not continuing.");
return; return;
} }
@@ -116,22 +120,28 @@ namespace DiscImageChef.Core.Devices.Dumping
// Get video partition size // Get video partition size
DicConsole.DebugWriteLine("Dump-media command", "Getting video partition size"); DicConsole.DebugWriteLine("Dump-media command", "Getting video partition size");
dumpLog.WriteLine("Locking drive.");
sense = dev.KreonLock(out senseBuf, dev.Timeout, out duration); sense = dev.KreonLock(out senseBuf, dev.Timeout, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot lock drive, not continuing.");
DicConsole.ErrorWriteLine("Cannot lock drive, not continuing."); DicConsole.ErrorWriteLine("Cannot lock drive, not continuing.");
return; return;
} }
dumpLog.WriteLine("Getting video partition size.");
sense = dev.ReadCapacity(out byte[] readBuffer, out senseBuf, dev.Timeout, out duration); sense = dev.ReadCapacity(out byte[] readBuffer, out senseBuf, dev.Timeout, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot get disc capacity.");
DicConsole.ErrorWriteLine("Cannot get disc capacity."); DicConsole.ErrorWriteLine("Cannot get disc capacity.");
return; return;
} }
totalSize = (ulong)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + (readBuffer[3])); totalSize = (ulong)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + (readBuffer[3]));
dumpLog.WriteLine("Reading Physical Format Information.");
sense = dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PhysicalInformation, 0, 0, out duration); sense = dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PhysicalInformation, 0, 0, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot get PFI.");
DicConsole.ErrorWriteLine("Cannot get PFI."); DicConsole.ErrorWriteLine("Cannot get PFI.");
return; return;
} }
@@ -147,9 +157,11 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors", totalSize); DicConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors", totalSize);
l0Video = Decoders.DVD.PFI.Decode(readBuffer).Value.Layer0EndPSN - Decoders.DVD.PFI.Decode(readBuffer).Value.DataAreaStartPSN + 1; l0Video = Decoders.DVD.PFI.Decode(readBuffer).Value.Layer0EndPSN - Decoders.DVD.PFI.Decode(readBuffer).Value.DataAreaStartPSN + 1;
l1Video = totalSize - l0Video + 1; l1Video = totalSize - l0Video + 1;
dumpLog.WriteLine("Reading Disc Manufacturing Information.");
sense = dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DiscManufacturingInformation, 0, 0, out duration); sense = dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DiscManufacturingInformation, 0, 0, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot get DMI.");
DicConsole.ErrorWriteLine("Cannot get DMI."); DicConsole.ErrorWriteLine("Cannot get DMI.");
return; return;
} }
@@ -165,15 +177,19 @@ namespace DiscImageChef.Core.Devices.Dumping
// Get game partition size // Get game partition size
DicConsole.DebugWriteLine("Dump-media command", "Getting game partition size"); DicConsole.DebugWriteLine("Dump-media command", "Getting game partition size");
dumpLog.WriteLine("Unlocking drive (Xtreme).");
sense = dev.KreonUnlockXtreme(out senseBuf, dev.Timeout, out duration); sense = dev.KreonUnlockXtreme(out senseBuf, dev.Timeout, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot unlock drive, not continuing.");
DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing."); DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing.");
return; return;
} }
dumpLog.WriteLine("Getting game partition size.");
sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out duration); sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot get disc capacity.");
DicConsole.ErrorWriteLine("Cannot get disc capacity."); DicConsole.ErrorWriteLine("Cannot get disc capacity.");
return; return;
} }
@@ -182,22 +198,28 @@ namespace DiscImageChef.Core.Devices.Dumping
// Get middle zone size // Get middle zone size
DicConsole.DebugWriteLine("Dump-media command", "Getting middle zone size"); DicConsole.DebugWriteLine("Dump-media command", "Getting middle zone size");
dumpLog.WriteLine("Unlocking drive (Wxripper).");
sense = dev.KreonUnlockWxripper(out senseBuf, dev.Timeout, out duration); sense = dev.KreonUnlockWxripper(out senseBuf, dev.Timeout, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot unlock drive, not continuing.");
DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing."); DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing.");
return; return;
} }
dumpLog.WriteLine("Getting disc size.");
sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out duration); sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot get disc capacity.");
DicConsole.ErrorWriteLine("Cannot get disc capacity."); DicConsole.ErrorWriteLine("Cannot get disc capacity.");
return; return;
} }
totalSize = (ulong)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + (readBuffer[3])); totalSize = (ulong)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + (readBuffer[3]));
dumpLog.WriteLine("Reading Physical Format Information.");
sense = dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PhysicalInformation, 0, 0, out duration); sense = dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.PhysicalInformation, 0, 0, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot get PFI.");
DicConsole.ErrorWriteLine("Cannot get PFI."); DicConsole.ErrorWriteLine("Cannot get PFI.");
return; return;
} }
@@ -215,9 +237,11 @@ namespace DiscImageChef.Core.Devices.Dumping
}; };
DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].Xbox.PFI.Image, tmpBuf, "Unlocked PFI", true); DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].Xbox.PFI.Image, tmpBuf, "Unlocked PFI", true);
dumpLog.WriteLine("Reading Disc Manufacturing Information.");
sense = dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DiscManufacturingInformation, 0, 0, out duration); sense = dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.DiscManufacturingInformation, 0, 0, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot get DMI.");
DicConsole.ErrorWriteLine("Cannot get DMI."); DicConsole.ErrorWriteLine("Cannot get DMI.");
return; return;
} }
@@ -243,13 +267,22 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine("Real layer break: {0}", layerBreak); DicConsole.WriteLine("Real layer break: {0}", layerBreak);
DicConsole.WriteLine(); DicConsole.WriteLine();
dumpLog.WriteLine("Video layer 0 size: {0} sectors", l0Video);
dumpLog.WriteLine("Video layer 1 size: {0} sectors", l1Video);
dumpLog.WriteLine("Middle zone 0 size: {0} sectors", middleZone);
dumpLog.WriteLine("Game data 0 size: {0} sectors", gameSize);
dumpLog.WriteLine("Total 0 size: {0} sectors", totalSize);
dumpLog.WriteLine("Real layer break: {0}", layerBreak);
bool read12 = !dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, false, dev.Timeout, out duration); bool read12 = !dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, false, dev.Timeout, out duration);
if(!read12) if(!read12)
{ {
dumpLog.WriteLine("Cannot read medium, aborting scan...");
DicConsole.ErrorWriteLine("Cannot read medium, aborting scan..."); DicConsole.ErrorWriteLine("Cannot read medium, aborting scan...");
return; return;
} }
dumpLog.WriteLine("Using SCSI READ (12) command.");
DicConsole.WriteLine("Using SCSI READ (12) command."); DicConsole.WriteLine("Using SCSI READ (12) command.");
while(true) while(true)
@@ -267,11 +300,12 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dev.Error) if(dev.Error)
{ {
dumpLog.WriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError);
DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError); DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError);
return; return;
} }
dumpLog.WriteLine("Reading {0} sectors at a time.", blocksToRead);
DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead);
mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead); mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
@@ -291,13 +325,17 @@ namespace DiscImageChef.Core.Devices.Dumping
throw new Exception("Could not process resume file, not continuing..."); throw new Exception("Could not process resume file, not continuing...");
ulong currentSector = resume.NextBlock; ulong currentSector = resume.NextBlock;
dumpFile.Seek(resume.NextBlock, blockSize); dumpFile.Seek(resume.NextBlock, blockSize);
if(resume.NextBlock > 0)
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
dumpLog.WriteLine("Reading game partition.");
for(int e = 0; e <= 16; e++) for(int e = 0; e <= 16; e++)
{ {
if(aborted) if(aborted)
{ {
resume.NextBlock = currentSector; resume.NextBlock = currentSector;
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -334,6 +372,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -378,6 +417,11 @@ namespace DiscImageChef.Core.Devices.Dumping
mhddLog.Write(i, cmdDuration); mhddLog.Write(i, cmdDuration);
ibgLog.Write(i, 0); ibgLog.Write(i, 0);
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i);
string[] senseLines = Decoders.SCSI.Sense.PrettifySense(senseBuf).Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach(string senseLine in senseLines)
dumpLog.WriteLine(senseLine);
} }
#pragma warning disable IDE0004 // Remove Unnecessary Cast #pragma warning disable IDE0004 // Remove Unnecessary Cast
@@ -394,6 +438,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -414,11 +459,13 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
// Middle Zone D // Middle Zone D
dumpLog.WriteLine("Writing Middle Zone D (empty).");
for(ulong middle = currentSector - blocks - 1; middle < (middleZone - 1); middle += blocksToRead) for(ulong middle = currentSector - blocks - 1; middle < (middleZone - 1); middle += blocksToRead)
{ {
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -438,9 +485,11 @@ namespace DiscImageChef.Core.Devices.Dumping
blocksToRead = saveBlocksToRead; blocksToRead = saveBlocksToRead;
dumpLog.WriteLine("Locking drive.");
sense = dev.KreonLock(out senseBuf, dev.Timeout, out duration); sense = dev.KreonLock(out senseBuf, dev.Timeout, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot lock drive, not continuing.");
DicConsole.ErrorWriteLine("Cannot lock drive, not continuing."); DicConsole.ErrorWriteLine("Cannot lock drive, not continuing.");
return; return;
} }
@@ -452,11 +501,13 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
// Video Layer 1 // Video Layer 1
dumpLog.WriteLine("Reading Video Layer 1.");
for(ulong l1 = currentSector - blocks - middleZone + l0Video; l1 < (l0Video + l1Video); l1 += blocksToRead) for(ulong l1 = currentSector - blocks - middleZone + l0Video; l1 < (l0Video + l1Video); l1 += blocksToRead)
{ {
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -501,6 +552,10 @@ namespace DiscImageChef.Core.Devices.Dumping
mhddLog.Write(l1, cmdDuration); mhddLog.Write(l1, cmdDuration);
ibgLog.Write(l1, 0); ibgLog.Write(l1, 0);
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, l1);
string[] senseLines = Decoders.SCSI.Sense.PrettifySense(senseBuf).Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach(string senseLine in senseLines)
dumpLog.WriteLine(senseLine);
} }
#pragma warning disable IDE0004 // Remove Unnecessary Cast #pragma warning disable IDE0004 // Remove Unnecessary Cast
@@ -510,9 +565,11 @@ namespace DiscImageChef.Core.Devices.Dumping
resume.NextBlock = currentSector; resume.NextBlock = currentSector;
} }
dumpLog.WriteLine("Unlocking drive (Wxripper).");
sense = dev.KreonUnlockWxripper(out senseBuf, dev.Timeout, out duration); sense = dev.KreonUnlockWxripper(out senseBuf, dev.Timeout, out duration);
if(sense) if(sense)
{ {
dumpLog.WriteLine("Cannot unlock drive, not continuing.");
DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing."); DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing.");
return; return;
} }
@@ -529,6 +586,8 @@ namespace DiscImageChef.Core.Devices.Dumping
#pragma warning disable IDE0004 // Remove Unnecessary Cast #pragma warning disable IDE0004 // Remove Unnecessary Cast
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath); ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000), devicePath);
#pragma warning restore IDE0004 // Remove Unnecessary Cast #pragma warning restore IDE0004 // Remove Unnecessary Cast
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
#region Error handling #region Error handling
if(resume.BadBlocks.Count > 0 && !aborted) if(resume.BadBlocks.Count > 0 && !aborted)
@@ -556,6 +615,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(aborted) if(aborted)
{ {
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents); currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
dumpLog.WriteLine("Aborted!");
break; break;
} }
@@ -571,6 +631,7 @@ namespace DiscImageChef.Core.Devices.Dumping
resume.BadBlocks.Remove(badSector); resume.BadBlocks.Remove(badSector);
extents.Add(badSector); extents.Add(badSector);
dumpFile.WriteAt(readBuffer, badSector, blockSize); dumpFile.WriteAt(readBuffer, badSector, blockSize);
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
} }
else if(runningPersistent) else if(runningPersistent)
dumpFile.WriteAt(readBuffer, badSector, blockSize); dumpFile.WriteAt(readBuffer, badSector, blockSize);
@@ -661,6 +722,7 @@ namespace DiscImageChef.Core.Devices.Dumping
md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType); md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType);
} }
dumpLog.WriteLine("Sending MODE SELECT to drive.");
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration); sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration);
if(sense) if(sense)
{ {
@@ -687,6 +749,7 @@ namespace DiscImageChef.Core.Devices.Dumping
md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType); md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType);
md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType); md10 = Decoders.SCSI.Modes.EncodeMode10(md, dev.SCSIType);
dumpLog.WriteLine("Sending MODE SELECT to drive.");
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration); sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration);
if(sense) if(sense)
{ {
@@ -706,10 +769,14 @@ namespace DiscImageChef.Core.Devices.Dumping
blocks = totalSize; blocks = totalSize;
dumpLog.WriteLine("Checksum starts.");
for(ulong i = 0; i < blocks; i += blocksToRead) for(ulong i = 0; i < blocks; i += blocksToRead)
{ {
if(aborted) if(aborted)
{
dumpLog.WriteLine("Aborted!");
break; break;
}
if((blocks - i) < blocksToRead) if((blocks - i) < blocksToRead)
blocksToRead = (uint)(blocks - i); blocksToRead = (uint)(blocks - i);
@@ -732,6 +799,8 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine(); DicConsole.WriteLine();
dumpFile.Close(); dumpFile.Close();
end = DateTime.UtcNow; end = DateTime.UtcNow;
dumpLog.WriteLine("Checksum finished in {0} seconds.", (end - start).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
PluginBase plugins = new PluginBase(); PluginBase plugins = new PluginBase();
plugins.RegisterAllPlugins(); plugins.RegisterAllPlugins();
@@ -760,8 +829,10 @@ namespace DiscImageChef.Core.Devices.Dumping
if(_imageFormat != null) if(_imageFormat != null)
{ {
dumpLog.WriteLine("Getting partitions.");
List<Partition> partitions = Partitions.GetAll(_imageFormat); List<Partition> partitions = Partitions.GetAll(_imageFormat);
Partitions.AddSchemesToStats(partitions); Partitions.AddSchemesToStats(partitions);
dumpLog.WriteLine("Found {0} partitions.", partitions.Count);
if(partitions.Count > 0) if(partitions.Count > 0)
{ {
@@ -778,6 +849,8 @@ namespace DiscImageChef.Core.Devices.Dumping
Type = partitions[i].Type Type = partitions[i].Type
}; };
List<FileSystemType> lstFs = new List<FileSystemType>(); List<FileSystemType> lstFs = new List<FileSystemType>();
dumpLog.WriteLine("Getting filesystems on partition {0}, starting at {1}, ending at {2}, with type {3}, under scheme {4}.",
i, partitions[i].Start, partitions[i].End, partitions[i].Type, partitions[i].Scheme);
foreach(Filesystem _plugin in plugins.PluginsList.Values) foreach(Filesystem _plugin in plugins.PluginsList.Values)
{ {
@@ -788,6 +861,7 @@ namespace DiscImageChef.Core.Devices.Dumping
_plugin.GetInformation(_imageFormat, partitions[i], out string foo); _plugin.GetInformation(_imageFormat, partitions[i], out string foo);
lstFs.Add(_plugin.XmlFSType); lstFs.Add(_plugin.XmlFSType);
Statistics.AddFilesystem(_plugin.XmlFSType.Type); Statistics.AddFilesystem(_plugin.XmlFSType.Type);
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
if(_plugin.XmlFSType.Type == "Opera") if(_plugin.XmlFSType.Type == "Opera")
dskType = MediaType.ThreeDO; dskType = MediaType.ThreeDO;
@@ -813,6 +887,7 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
else else
{ {
dumpLog.WriteLine("Getting filesystem for whole device.");
xmlFileSysInfo = new PartitionType[1]; xmlFileSysInfo = new PartitionType[1];
xmlFileSysInfo[0] = new PartitionType xmlFileSysInfo[0] = new PartitionType
{ {
@@ -837,6 +912,7 @@ namespace DiscImageChef.Core.Devices.Dumping
_plugin.GetInformation(_imageFormat, wholePart, out string foo); _plugin.GetInformation(_imageFormat, wholePart, out string foo);
lstFs.Add(_plugin.XmlFSType); lstFs.Add(_plugin.XmlFSType);
Statistics.AddFilesystem(_plugin.XmlFSType.Type); Statistics.AddFilesystem(_plugin.XmlFSType.Type);
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
if(_plugin.XmlFSType.Type == "Opera") if(_plugin.XmlFSType.Type == "Opera")
dskType = MediaType.ThreeDO; dskType = MediaType.ThreeDO;

View File

@@ -87,6 +87,7 @@
<Compile Include="Sidecar\LinearMedia.cs" /> <Compile Include="Sidecar\LinearMedia.cs" />
<Compile Include="Sidecar\AudioMedia.cs" /> <Compile Include="Sidecar\AudioMedia.cs" />
<Compile Include="Sidecar\BlockTape.cs" /> <Compile Include="Sidecar\BlockTape.cs" />
<Compile Include="Logging\DumpLog.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\DiscImageChef.Console\DiscImageChef.Console.csproj"> <ProjectReference Include="..\DiscImageChef.Console\DiscImageChef.Console.csproj">
@@ -161,7 +162,7 @@
<Properties> <Properties>
<Policies> <Policies>
<TextStylePolicy FileWidth="120" TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" TabsToSpaces="True" scope="text/x-csharp" /> <TextStylePolicy FileWidth="120" TabWidth="4" IndentWidth="4" RemoveTrailingWhitespace="True" NoTabsAfterNonTabs="False" EolMarker="Native" TabsToSpaces="True" scope="text/x-csharp" />
<CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchSection="True" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" SpacingAfterMethodDeclarationName="False" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceAfterMethodCallName="False" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceAfterControlFlowStatementKeyword="False" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBeforeOpenSquareBracket="False" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeColonInBaseTypeDeclaration="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" NewLineForMembersInObjectInit="False" NewLineForMembersInAnonymousTypes="False" NewLineForClausesInQuery="False" scope="text/x-csharp" /> <CSharpFormattingPolicy IndentBlock="True" IndentBraces="False" IndentSwitchSection="True" IndentSwitchCaseSection="True" LabelPositioning="OneLess" NewLinesForBracesInTypes="True" NewLinesForBracesInMethods="True" NewLinesForBracesInProperties="True" NewLinesForBracesInAccessors="True" NewLinesForBracesInAnonymousMethods="True" NewLinesForBracesInControlBlocks="True" NewLinesForBracesInAnonymousTypes="True" NewLinesForBracesInObjectCollectionArrayInitializers="True" NewLinesForBracesInLambdaExpressionBody="True" NewLineForElse="True" NewLineForCatch="True" NewLineForFinally="True" SpacingAfterMethodDeclarationName="False" SpaceWithinMethodDeclarationParenthesis="False" SpaceBetweenEmptyMethodDeclarationParentheses="False" SpaceAfterMethodCallName="False" SpaceWithinMethodCallParentheses="False" SpaceBetweenEmptyMethodCallParentheses="False" SpaceWithinExpressionParentheses="False" SpaceWithinCastParentheses="False" SpaceWithinOtherParentheses="False" SpaceAfterCast="False" SpacesIgnoreAroundVariableDeclaration="False" SpaceBeforeOpenSquareBracket="False" SpaceBetweenEmptySquareBrackets="False" SpaceWithinSquareBrackets="False" SpaceAfterColonInBaseTypeDeclaration="True" SpaceAfterComma="True" SpaceAfterDot="False" SpaceAfterSemicolonsInForStatement="True" SpaceBeforeColonInBaseTypeDeclaration="True" SpaceBeforeComma="False" SpaceBeforeDot="False" SpaceBeforeSemicolonsInForStatement="False" SpacingAroundBinaryOperator="Single" WrappingPreserveSingleLine="True" WrappingKeepStatementsOnSingleLine="True" PlaceSystemDirectiveFirst="True" NewLineForMembersInObjectInit="False" NewLineForMembersInAnonymousTypes="False" NewLineForClausesInQuery="False" SpaceAfterControlFlowStatementKeyword="False" scope="text/x-csharp" />
<DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" /> <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
</Policies> </Policies>
</Properties> </Properties>

View File

@@ -0,0 +1,138 @@
// /***************************************************************************
// The Disc Image Chef
// ----------------------------------------------------------------------------
//
// Filename : DumpLog.cs
// Version : 1.0
// Author(s) : Natalia Portillo
//
// Component : Component
//
// Revision : $Revision$
// Last change by : $Author$
// Date : $Date$
//
// --[ Description ] ----------------------------------------------------------
//
// Description
//
// --[ 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 (C) 2011-2015 Claunia.com
// ****************************************************************************/
// //$Id$
using System;
using System.IO;
using System.Reflection;
using DiscImageChef.Devices;
namespace DiscImageChef.Core.Logging
{
public class DumpLog
{
readonly StreamWriter logSw;
public DumpLog(string outputFile, Device dev)
{
if(!string.IsNullOrEmpty(outputFile))
{
logSw = new StreamWriter(outputFile, true);
logSw.WriteLine("Start logging at {0}", DateTime.Now);
Interop.PlatformID platId = Interop.DetectOS.GetRealPlatformID();
string platVer = Interop.DetectOS.GetVersion();
Type monoRunType = Type.GetType("Mono.Runtime");
logSw.WriteLine("################# System information #################");
logSw.WriteLine("{0} {1} ({2}-bit)", Interop.DetectOS.GetPlatformName(platId, platVer), platVer, Environment.Is64BitOperatingSystem ? 64 : 32);
if(monoRunType != null)
{
string monoVer = "unknown version";
MethodInfo monoDisplayName = monoRunType.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
if(monoDisplayName != null)
monoVer = (string)monoDisplayName.Invoke(null, null);
logSw.WriteLine("Mono {0}", monoVer);
}
else
logSw.WriteLine(".NET Framework {0}", Environment.Version);
logSw.WriteLine();
logSw.WriteLine("################# Program information ################");
logSw.WriteLine("DiscImageChef {0} running in {1}-bit", Version.GetVersion(), Environment.Is64BitProcess ? 64 : 32);
#if DEBUG
logSw.WriteLine("DEBUG version");
#endif
logSw.WriteLine("Command line: {0}", Environment.CommandLine);
logSw.WriteLine();
logSw.WriteLine("################# Device information #################");
logSw.WriteLine("Manufacturer: {0}", dev.Manufacturer);
logSw.WriteLine("Model: {0}", dev.Model);
logSw.WriteLine("Firmware revision: {0}", dev.Revision);
logSw.WriteLine("Serial number: {0}", dev.Serial);
logSw.WriteLine("Removable device: {0}", dev.IsRemovable);
logSw.WriteLine("Device type: {0}", dev.Type);
logSw.WriteLine("CompactFlash device: {0}", dev.IsCompactFlash);
logSw.WriteLine("PCMCIA device: {0}", dev.IsPCMCIA);
logSw.WriteLine("USB device: {0}", dev.IsUSB);
if(dev.IsUSB)
{
logSw.WriteLine("USB manufacturer: {0}", dev.USBManufacturerString);
logSw.WriteLine("USB product: {0}", dev.USBProductString);
logSw.WriteLine("USB serial: {0}", dev.USBSerialString);
logSw.WriteLine("USB vendor ID: {0:X4}h", dev.USBVendorID);
logSw.WriteLine("USB product ID: {0:X4}h", dev.USBProductID);
}
logSw.WriteLine("FireWire device: {0}", dev.IsFireWire);
if(dev.IsFireWire)
{
logSw.WriteLine("FireWire vendor: {0}", dev.FireWireVendorName);
logSw.WriteLine("FireWire model: {0}", dev.FireWireModelName);
logSw.WriteLine("FireWire GUID: 0x{0:X16}", dev.FireWireGUID);
logSw.WriteLine("FireWire vendor ID: 0x{0:X8}", dev.FireWireVendor);
logSw.WriteLine("FireWire product ID: 0x{0:X8}", dev.FireWireModel);
}
logSw.WriteLine();
logSw.WriteLine("######################################################");
logSw.WriteLine();
logSw.WriteLine("################ Dumping progress log ################");
logSw.Flush();
}
}
public void WriteLine(string format, params object[] args)
{
if(logSw != null)
{
string text = string.Format(format, args);
logSw.WriteLine("{0:s} {1}", DateTime.Now, text);
logSw.Flush();
}
}
public void Close()
{
if(logSw != null)
{
logSw.WriteLine("######################################################");
logSw.WriteLine("End logging at {0}", DateTime.Now);
logSw.Close();
}
}
}
}

View File

@@ -105,23 +105,27 @@ namespace DiscImageChef.Commands
return; return;
} }
DumpLog dumpLog = new DumpLog(options.OutputPrefix + ".log", dev);
switch(dev.Type) switch(dev.Type)
{ {
case DeviceType.ATA: case DeviceType.ATA:
ATA.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError, ref resume); ATA.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError, ref resume, ref dumpLog);
break; break;
case DeviceType.MMC: case DeviceType.MMC:
case DeviceType.SecureDigital: case DeviceType.SecureDigital:
SecureDigital.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError, ref resume); SecureDigital.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError, ref resume, ref dumpLog);
break; break;
case DeviceType.NVMe: case DeviceType.NVMe:
NVMe.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError, ref resume); NVMe.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError, ref resume, ref dumpLog);
break; break;
case DeviceType.ATAPI: case DeviceType.ATAPI:
case DeviceType.SCSI: case DeviceType.SCSI:
SCSI.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError, options.SeparateSubchannel, ref resume); SCSI.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError, options.SeparateSubchannel, ref resume, ref dumpLog);
break; break;
default: default:
dumpLog.WriteLine("Unknown device type.");
dumpLog.Close();
throw new NotSupportedException("Unknown device type."); throw new NotSupportedException("Unknown device type.");
} }
@@ -139,6 +143,8 @@ namespace DiscImageChef.Commands
fs.Close(); fs.Close();
} }
dumpLog.Close();
Core.Statistics.AddCommand("dump-media"); Core.Statistics.AddCommand("dump-media");
} }
} }