mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Added dump log creation.
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
138
DiscImageChef.Core/Logging/DumpLog.cs
Normal file
138
DiscImageChef.Core/Logging/DumpLog.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user