mirror of
https://github.com/aaru-dps/Aaru.Server.git
synced 2025-12-16 19:24:27 +00:00
REFACTOR: Reformat code.
This commit is contained in:
@@ -50,7 +50,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
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, ref DumpLog dumpLog, Encoding encoding)
|
||||
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, Encoding encoding)
|
||||
{
|
||||
bool aborted;
|
||||
MHDDLog mhddLog;
|
||||
@@ -60,8 +62,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Raw dumping not yet supported in ATA devices.");
|
||||
|
||||
if(force)
|
||||
DicConsole.ErrorWriteLine("Continuing...");
|
||||
if(force) DicConsole.ErrorWriteLine("Continuing...");
|
||||
else
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Aborting...");
|
||||
@@ -80,10 +81,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
Decoders.ATA.Identify.IdentifyDevice ataId = Decoders.ATA.Identify.Decode(cmdBuf).Value;
|
||||
|
||||
CICMMetadataType sidecar = new CICMMetadataType()
|
||||
{
|
||||
BlockMedia = new BlockMediaType[] { new BlockMediaType() }
|
||||
};
|
||||
CICMMetadataType sidecar =
|
||||
new CICMMetadataType() {BlockMedia = new BlockMediaType[] {new BlockMediaType()}};
|
||||
|
||||
if(dev.IsUSB)
|
||||
{
|
||||
@@ -123,7 +122,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
if(tuple.Code == TupleCodes.CISTPL_MANFID)
|
||||
{
|
||||
ManufacturerIdentificationTuple manfid = CIS.DecodeManufacturerIdentificationTuple(tuple);
|
||||
ManufacturerIdentificationTuple manfid =
|
||||
CIS.DecodeManufacturerIdentificationTuple(tuple);
|
||||
|
||||
if(manfid != null)
|
||||
{
|
||||
@@ -141,7 +141,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer;
|
||||
sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product;
|
||||
sidecar.BlockMedia[0].PCMCIA.Compliance = string.Format("{0}.{1}", vers.MajorVersion, vers.MinorVersion);
|
||||
sidecar.BlockMedia[0].PCMCIA.Compliance =
|
||||
string.Format("{0}.{1}", vers.MajorVersion, vers.MinorVersion);
|
||||
sidecar.BlockMedia[0].PCMCIA.AdditionalInformation = vers.AdditionalInformation;
|
||||
}
|
||||
}
|
||||
@@ -170,10 +171,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Checksum dataChk;
|
||||
|
||||
aborted = false;
|
||||
System.Console.CancelKeyPress += (sender, e) =>
|
||||
{
|
||||
e.Cancel = aborted = true;
|
||||
};
|
||||
System.Console.CancelKeyPress += (sender, e) => { e.Cancel = aborted = true; };
|
||||
|
||||
DataFile dumpFile;
|
||||
|
||||
@@ -189,6 +187,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine(ataReader.ErrorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
uint blockSize = ataReader.LogicalBlockSize;
|
||||
uint physicalsectorsize = ataReader.PhysicalBlockSize;
|
||||
if(ataReader.FindReadCommand())
|
||||
@@ -204,21 +203,27 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine(ataReader.ErrorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
uint blocksToRead = ataReader.BlocksToRead;
|
||||
ushort cylinders = ataReader.Cylinders;
|
||||
byte heads = ataReader.Heads;
|
||||
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 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;
|
||||
ExtentsULong extents = null;
|
||||
ResumeSupport.Process(ataReader.IsLBA, removable, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformID, ref resume, ref currentTry, ref extents);
|
||||
ResumeSupport.Process(ataReader.IsLBA, removable, blocks, dev.Manufacturer, dev.Model, dev.Serial,
|
||||
dev.PlatformID, ref resume, ref currentTry, ref extents);
|
||||
if(currentTry == null || extents == null)
|
||||
throw new Exception("Could not process resume file, not continuing...");
|
||||
|
||||
@@ -229,8 +234,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
|
||||
ibgLog = new IBGLog(outputPrefix + ".ibg", currentProfile);
|
||||
dumpFile = new DataFile(outputPrefix + ".bin");
|
||||
if(resume.NextBlock > 0)
|
||||
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
|
||||
dumpFile.Seek(resume.NextBlock, blockSize);
|
||||
|
||||
@@ -244,14 +248,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if((blocks - i) < blocksToRead)
|
||||
blocksToRead = (byte)(blocks - i);
|
||||
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;
|
||||
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);
|
||||
@@ -267,12 +268,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
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);
|
||||
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]);
|
||||
@@ -285,14 +284,18 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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);
|
||||
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));
|
||||
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)
|
||||
@@ -301,7 +304,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
bool forward = true;
|
||||
bool runningPersistent = false;
|
||||
|
||||
repeatRetryLba:
|
||||
repeatRetryLba:
|
||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||
foreach(ulong badSector in tmpArray)
|
||||
{
|
||||
@@ -312,7 +315,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "");
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1,
|
||||
forward ? "forward" : "reverse",
|
||||
runningPersistent ? "recovering partial data, " : "");
|
||||
|
||||
bool error = ataReader.ReadBlock(out cmdBuf, badSector, out duration);
|
||||
|
||||
@@ -325,8 +330,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dumpFile.WriteAt(cmdBuf, badSector, blockSize);
|
||||
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
|
||||
}
|
||||
else if(runningPersistent)
|
||||
dumpFile.WriteAt(cmdBuf, badSector, blockSize);
|
||||
else if(runningPersistent) dumpFile.WriteAt(cmdBuf, badSector, blockSize);
|
||||
}
|
||||
|
||||
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
|
||||
@@ -367,13 +371,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
#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;
|
||||
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 cylinder {0} head {1} sector {2} ({3:F3} MiB/sec.)", Cy, Hd, Sc, currentSpeed);
|
||||
DicConsole.Write("\rReading cylinder {0} head {1} sector {2} ({3:F3} MiB/sec.)", Cy, Hd,
|
||||
Sc, currentSpeed);
|
||||
|
||||
bool error = ataReader.ReadCHS(out cmdBuf, Cy, Hd, Sc, out duration);
|
||||
|
||||
@@ -390,10 +393,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
else
|
||||
{
|
||||
resume.BadBlocks.Add(currentBlock);
|
||||
if(duration < 500)
|
||||
mhddLog.Write(currentBlock, 65535);
|
||||
else
|
||||
mhddLog.Write(currentBlock, duration);
|
||||
if(duration < 500) mhddLog.Write(currentBlock, 65535);
|
||||
else mhddLog.Write(currentBlock, duration);
|
||||
|
||||
ibgLog.Write(currentBlock, 0);
|
||||
dumpFile.Write(new byte[blockSize]);
|
||||
@@ -408,15 +409,20 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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
|
||||
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 dump speed {0:F3} KiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
|
||||
}
|
||||
|
||||
dataChk = new Checksum();
|
||||
dumpFile.Seek(0, SeekOrigin.Begin);
|
||||
blocksToRead = 500;
|
||||
@@ -430,8 +436,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if((blocks - i) < blocksToRead)
|
||||
blocksToRead = (byte)(blocks - i);
|
||||
if((blocks - i) < blocksToRead) blocksToRead = (byte)(blocks - i);
|
||||
|
||||
DicConsole.Write("\rChecksumming sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed);
|
||||
|
||||
@@ -446,11 +451,13 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (chkDuration / (double)1000);
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
dumpFile.Close();
|
||||
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));
|
||||
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
|
||||
|
||||
PluginBase plugins = new PluginBase();
|
||||
plugins.RegisterAllPlugins(encoding);
|
||||
@@ -468,15 +475,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
_imageFormat = ImageFormat.Detect(inputFilter);
|
||||
PartitionType[] xmlFileSysInfo = null;
|
||||
|
||||
try
|
||||
{
|
||||
if(!_imageFormat.OpenImage(inputFilter))
|
||||
_imageFormat = null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_imageFormat = null;
|
||||
}
|
||||
try { if(!_imageFormat.OpenImage(inputFilter)) _imageFormat = null; }
|
||||
catch { _imageFormat = null; }
|
||||
|
||||
if(_imageFormat != null)
|
||||
{
|
||||
@@ -500,8 +500,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Type = partitions[i].Type
|
||||
};
|
||||
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);
|
||||
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)
|
||||
{
|
||||
@@ -523,8 +525,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
|
||||
if(lstFs.Count > 0)
|
||||
xmlFileSysInfo[i].FileSystems = lstFs.ToArray();
|
||||
if(lstFs.Count > 0) xmlFileSysInfo[i].FileSystems = lstFs.ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -532,11 +533,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dumpLog.WriteLine("Getting filesystem for whole device.");
|
||||
|
||||
xmlFileSysInfo = new PartitionType[1];
|
||||
xmlFileSysInfo[0] = new PartitionType
|
||||
{
|
||||
EndSector = (int)(blocks - 1),
|
||||
StartSector = 0
|
||||
};
|
||||
xmlFileSysInfo[0] = new PartitionType {EndSector = (int)(blocks - 1), StartSector = 0};
|
||||
List<FileSystemType> lstFs = new List<FileSystemType>();
|
||||
|
||||
Partition wholePart = new Partition
|
||||
@@ -566,8 +563,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
|
||||
if(lstFs.Count > 0)
|
||||
xmlFileSysInfo[0].FileSystems = lstFs.ToArray();
|
||||
if(lstFs.Count > 0) xmlFileSysInfo[0].FileSystems = lstFs.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -577,8 +573,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Metadata.MediaType.MediaTypeToString(MediaType.CompactFlash, out xmlDskTyp, out xmlDskSubTyp);
|
||||
else if(dev.IsPCMCIA)
|
||||
Metadata.MediaType.MediaTypeToString(MediaType.PCCardTypeI, out xmlDskTyp, out xmlDskSubTyp);
|
||||
else
|
||||
Metadata.MediaType.MediaTypeToString(MediaType.GENERIC_HDD, out xmlDskTyp, out xmlDskSubTyp);
|
||||
else Metadata.MediaType.MediaTypeToString(MediaType.GENERIC_HDD, out xmlDskTyp, out xmlDskSubTyp);
|
||||
sidecar.BlockMedia[0].DiskType = xmlDskTyp;
|
||||
sidecar.BlockMedia[0].DiskSubType = xmlDskSubTyp;
|
||||
// TODO: Implement device firmware revision
|
||||
@@ -595,8 +590,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
sidecar.BlockMedia[0].Model = dev.Model;
|
||||
sidecar.BlockMedia[0].Serial = dev.Serial;
|
||||
sidecar.BlockMedia[0].Size = (long)(blocks * blockSize);
|
||||
if(xmlFileSysInfo != null)
|
||||
sidecar.BlockMedia[0].FileSystemInformation = xmlFileSysInfo;
|
||||
if(xmlFileSysInfo != null) sidecar.BlockMedia[0].FileSystemInformation = xmlFileSysInfo;
|
||||
if(cylinders > 0 && heads > 0 && sectors > 0)
|
||||
{
|
||||
sidecar.BlockMedia[0].Cylinders = cylinders;
|
||||
@@ -609,31 +603,31 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
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("Avegare speed: {0:F3} MiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1048576) / (totalDuration / 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("Avegare speed: {0:F3} MiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1048576) / (totalDuration / 1000));
|
||||
DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed);
|
||||
DicConsole.WriteLine("Slowest speed burst: {0:F3} MiB/sec.", minSpeed);
|
||||
DicConsole.WriteLine("{0} sectors could not be read.", resume.BadBlocks.Count);
|
||||
if(resume.BadBlocks.Count > 0)
|
||||
resume.BadBlocks.Sort();
|
||||
if(resume.BadBlocks.Count > 0) resume.BadBlocks.Sort();
|
||||
DicConsole.WriteLine();
|
||||
|
||||
if(!aborted)
|
||||
{
|
||||
DicConsole.WriteLine("Writing metadata sidecar");
|
||||
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml",
|
||||
FileMode.Create);
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
|
||||
|
||||
System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
System.Xml.Serialization.XmlSerializer xmlSer =
|
||||
new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
xmlSer.Serialize(xmlFs, sidecar);
|
||||
xmlFs.Close();
|
||||
}
|
||||
|
||||
Statistics.AddMedia(MediaType.GENERIC_HDD, true);
|
||||
}
|
||||
else
|
||||
DicConsole.ErrorWriteLine("Unable to communicate with ATA device.");
|
||||
else DicConsole.ErrorWriteLine("Unable to communicate with ATA device.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,23 +47,17 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct AlcoholHeader
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
|
||||
public string signature;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public byte[] version;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] public string signature;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public byte[] version;
|
||||
public AlcoholMediumType type;
|
||||
public ushort sessions;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public ushort[] unknown1;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public ushort[] unknown1;
|
||||
public ushort bcaLength;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
|
||||
public uint[] unknown2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public uint[] unknown2;
|
||||
public uint bcaOffset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public uint[] unknown3;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] public uint[] unknown3;
|
||||
public uint structuresOffset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
|
||||
public uint[] unknown4;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] public uint[] unknown4;
|
||||
public uint sessionOffset;
|
||||
public uint dpmOffset;
|
||||
}
|
||||
@@ -99,14 +93,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
public byte pframe;
|
||||
public uint extraOffset;
|
||||
public ushort sectorSize;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)]
|
||||
public byte[] unknown;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 18)] public byte[] unknown;
|
||||
public uint startLba;
|
||||
public ulong startOffset;
|
||||
public uint files;
|
||||
public uint footerOffset;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
||||
public byte[] unknown2;
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)] public byte[] unknown2;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
@@ -172,24 +164,23 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
header = new AlcoholHeader
|
||||
{
|
||||
signature = "MEDIA DESCRIPTOR",
|
||||
unknown1 = new ushort[] { 0x0002, 0x0000 },
|
||||
unknown1 = new ushort[] {0x0002, 0x0000},
|
||||
unknown2 = new uint[2],
|
||||
unknown3 = new uint[6],
|
||||
unknown4 = new uint[3],
|
||||
version = new byte[] { 1, 5 }
|
||||
version = new byte[] {1, 5}
|
||||
};
|
||||
header.version[0] = 1;
|
||||
header.version[1] = 5;
|
||||
tracks = new List<AlcoholTrack>();
|
||||
sessions = new List<AlcoholSession>();
|
||||
trackLengths = new Dictionary<byte, uint>();
|
||||
footer = new AlcoholFooter { widechar = 1 };
|
||||
footer = new AlcoholFooter {widechar = 1};
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if(sessions.Count == 0 || tracks.Count == 0)
|
||||
return;
|
||||
if(sessions.Count == 0 || tracks.Count == 0) return;
|
||||
|
||||
// Calculate first offsets
|
||||
header.sessions = (ushort)sessions.Count;
|
||||
@@ -201,7 +192,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
for(int i = 0; i < sessionsArray.Length; i++)
|
||||
{
|
||||
sessionsArray[i].allBlocks = (byte)(((sessionsArray[i].lastTrack - sessionsArray[i].firstTrack) + 1) +
|
||||
sessionsArray[i].nonTrackBlocks);
|
||||
sessionsArray[i].nonTrackBlocks);
|
||||
sessionsArray[i].trackOffset = (uint)nextOffset;
|
||||
nextOffset += sessionsArray[i].allBlocks * 80;
|
||||
}
|
||||
@@ -214,10 +205,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
if(tracksArray[i].point >= 0xA0) continue;
|
||||
if(!trackLengths.TryGetValue(tracksArray[i].point, out uint trkLen)) continue;
|
||||
|
||||
if(tracksArray[i].mode == AlcoholTrackMode.DVD)
|
||||
{
|
||||
tracksArray[i].extraOffset = trkLen;
|
||||
}
|
||||
if(tracksArray[i].mode == AlcoholTrackMode.DVD) { tracksArray[i].extraOffset = trkLen; }
|
||||
else
|
||||
{
|
||||
AlcoholTrackExtra extra = new AlcoholTrackExtra();
|
||||
@@ -247,15 +235,15 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
nextOffset += 4100;
|
||||
}
|
||||
|
||||
for(int i = 0; i < tracksArray.Length; i++)
|
||||
tracksArray[i].footerOffset = (uint)nextOffset;
|
||||
for(int i = 0; i < tracksArray.Length; i++) tracksArray[i].footerOffset = (uint)nextOffset;
|
||||
|
||||
footer.filenameOffset = (uint)(nextOffset + 16);
|
||||
|
||||
byte[] filename = Encoding.Unicode.GetBytes(outputPrefix + extension);
|
||||
|
||||
// Open descriptor file here
|
||||
FileStream descriptorFile = new FileStream(outputPrefix + ".mds", FileMode.Create, FileAccess.ReadWrite, FileShare.None);
|
||||
FileStream descriptorFile =
|
||||
new FileStream(outputPrefix + ".mds", FileMode.Create, FileAccess.ReadWrite, FileShare.None);
|
||||
|
||||
byte[] tmp = new byte[88];
|
||||
IntPtr hdrPtr = Marshal.AllocHGlobal(88);
|
||||
@@ -284,7 +272,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Marshal.FreeHGlobal(trkPtr);
|
||||
}
|
||||
|
||||
if(header.type == AlcoholMediumType.CD || header.type == AlcoholMediumType.CDR || header.type == AlcoholMediumType.CDRW)
|
||||
if(header.type == AlcoholMediumType.CD || header.type == AlcoholMediumType.CDR ||
|
||||
header.type == AlcoholMediumType.CDRW)
|
||||
{
|
||||
foreach(AlcoholTrackExtra extra in extrasArray)
|
||||
{
|
||||
@@ -429,8 +418,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
case TrackType.CDMode2Form2:
|
||||
trkArray[i].mode = AlcoholTrackMode.Mode2F2;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(mode), mode, null);
|
||||
default: throw new ArgumentOutOfRangeException(nameof(mode), mode, null);
|
||||
}
|
||||
|
||||
switch(subMode)
|
||||
@@ -447,8 +435,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
case TrackSubchannelType.Q16:
|
||||
case TrackSubchannelType.Q16Interleaved:
|
||||
throw new FeatureUnsupportedImageException("Specified subchannel type is not supported.");
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(subMode), subMode, null);
|
||||
default: throw new ArgumentOutOfRangeException(nameof(subMode), subMode, null);
|
||||
}
|
||||
|
||||
tracks = new List<AlcoholTrack>(trkArray);
|
||||
@@ -472,8 +459,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if(trackLengths.ContainsKey(point))
|
||||
trackLengths.Remove(point);
|
||||
if(trackLengths.ContainsKey(point)) trackLengths.Remove(point);
|
||||
|
||||
trackLengths.Add(point, (uint)length);
|
||||
|
||||
@@ -481,18 +467,15 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
for(int i = 0; i < sess.Length; i++)
|
||||
{
|
||||
if(sess[i].firstTrack == point)
|
||||
sess[i].sessionStart = (int)startLba;
|
||||
if(sess[i].lastTrack == point)
|
||||
sess[i].sessionEnd = (int)(startLba + length);
|
||||
if(sess[i].firstTrack == point) sess[i].sessionStart = (int)startLba;
|
||||
if(sess[i].lastTrack == point) sess[i].sessionEnd = (int)(startLba + length);
|
||||
}
|
||||
|
||||
sessions = new List<AlcoholSession>(sess);
|
||||
|
||||
}
|
||||
|
||||
public void AddTrack(byte adrCtl, byte tno, byte point, byte min, byte sec, byte frame, byte zero, byte pmin,
|
||||
byte psec, byte pframe, byte session)
|
||||
byte psec, byte pframe, byte session)
|
||||
{
|
||||
AlcoholTrack trk = new AlcoholTrack
|
||||
{
|
||||
@@ -519,11 +502,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
AlcoholSession[] sess = sessions.ToArray();
|
||||
|
||||
for(int i = 0; i < sess.Length; i++)
|
||||
{
|
||||
if(sess[i].sessionSequence == session)
|
||||
sess[i].nonTrackBlocks++;
|
||||
}
|
||||
for(int i = 0; i < sess.Length; i++) { if(sess[i].sessionSequence == session) sess[i].nonTrackBlocks++; }
|
||||
|
||||
sessions = new List<AlcoholSession>(sess);
|
||||
}
|
||||
@@ -540,8 +519,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
this.pfi = new byte[2048];
|
||||
Array.Copy(pfi, 4, this.pfi, 0, 2048);
|
||||
}
|
||||
else
|
||||
this.pfi = pfi;
|
||||
else this.pfi = pfi;
|
||||
}
|
||||
|
||||
public void AddDMI(byte[] dmi)
|
||||
@@ -551,8 +529,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
this.dmi = new byte[2048];
|
||||
Array.Copy(dmi, 4, this.dmi, 0, 2048);
|
||||
}
|
||||
else
|
||||
this.dmi = dmi;
|
||||
else this.dmi = dmi;
|
||||
}
|
||||
|
||||
public void SetExtension(string extension)
|
||||
@@ -560,4 +537,4 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
this.extension = extension;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
internal class CompactDisc
|
||||
{
|
||||
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 Resume resume, ref DumpLog dumpLog, Alcohol120 alcohol, bool dumpLeadIn)
|
||||
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 Resume resume,
|
||||
ref DumpLog dumpLog, Alcohol120 alcohol, bool dumpLeadIn)
|
||||
{
|
||||
MHDDLog mhddLog;
|
||||
IBGLog ibgLog;
|
||||
@@ -76,10 +79,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
ulong errored = 0;
|
||||
DataFile dumpFile = null;
|
||||
bool aborted = false;
|
||||
System.Console.CancelKeyPress += (sender, e) =>
|
||||
{
|
||||
e.Cancel = aborted = true;
|
||||
};
|
||||
System.Console.CancelKeyPress += (sender, e) => { e.Cancel = aborted = true; };
|
||||
|
||||
// We discarded all discs that falsify a TOC before requesting a real TOC
|
||||
// No TOC, no CD (or an empty one)
|
||||
@@ -124,10 +124,13 @@ 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)
|
||||
{
|
||||
Decoders.SCSI.MMC.DiscInformation.StandardDiscInformation? discInfo = Decoders.SCSI.MMC.DiscInformation.Decode000b(cmdBuf);
|
||||
Decoders.SCSI.MMC.DiscInformation.StandardDiscInformation? discInfo =
|
||||
Decoders.SCSI.MMC.DiscInformation.Decode000b(cmdBuf);
|
||||
if(discInfo.HasValue)
|
||||
{
|
||||
// If it is a read-only CD, check CD type if available
|
||||
@@ -172,21 +175,20 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
foreach(FullTOC.TrackDataDescriptor track in toc.Value.TrackDescriptors)
|
||||
{
|
||||
if(track.TNO == 1 &&
|
||||
((TOC_CONTROL)(track.CONTROL & 0x0D) == TOC_CONTROL.DataTrack ||
|
||||
(TOC_CONTROL)(track.CONTROL & 0x0D) == TOC_CONTROL.DataTrackIncremental))
|
||||
if(track.TNO == 1 && ((TOC_CONTROL)(track.CONTROL & 0x0D) == TOC_CONTROL.DataTrack ||
|
||||
(TOC_CONTROL)(track.CONTROL & 0x0D) ==
|
||||
TOC_CONTROL.DataTrackIncremental))
|
||||
{
|
||||
allFirstSessionTracksAreAudio &= firstTrackLastSession != 1;
|
||||
}
|
||||
|
||||
if((TOC_CONTROL)(track.CONTROL & 0x0D) == TOC_CONTROL.DataTrack ||
|
||||
(TOC_CONTROL)(track.CONTROL & 0x0D) == TOC_CONTROL.DataTrackIncremental)
|
||||
(TOC_CONTROL)(track.CONTROL & 0x0D) == TOC_CONTROL.DataTrackIncremental)
|
||||
{
|
||||
hasDataTrack = true;
|
||||
allFirstSessionTracksAreAudio &= track.TNO >= firstTrackLastSession;
|
||||
}
|
||||
else
|
||||
hasAudioTrack = true;
|
||||
else hasAudioTrack = true;
|
||||
|
||||
hasVideoTrack |= track.ADR == 4;
|
||||
}
|
||||
@@ -194,12 +196,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(hasDataTrack && hasAudioTrack && allFirstSessionTracksAreAudio && sessions == 2)
|
||||
dskType = MediaType.CDPLUS;
|
||||
if(!hasDataTrack && hasAudioTrack && sessions == 1)
|
||||
dskType = MediaType.CDDA;
|
||||
if(hasDataTrack && !hasAudioTrack && sessions == 1)
|
||||
dskType = MediaType.CDROM;
|
||||
if(hasVideoTrack && !hasDataTrack && sessions == 1)
|
||||
dskType = MediaType.CDV;
|
||||
if(!hasDataTrack && hasAudioTrack && sessions == 1) dskType = MediaType.CDDA;
|
||||
if(hasDataTrack && !hasAudioTrack && sessions == 1) dskType = MediaType.CDROM;
|
||||
if(hasVideoTrack && !hasDataTrack && sessions == 1) dskType = MediaType.CDV;
|
||||
}
|
||||
|
||||
dumpLog.WriteLine("Reading PMA");
|
||||
@@ -244,10 +243,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
blockSize = 2448;
|
||||
subSize = 96;
|
||||
int sectorSize;
|
||||
if(separateSubchannel)
|
||||
sectorSize = (int)(blockSize - subSize);
|
||||
else
|
||||
sectorSize = (int)blockSize;
|
||||
if(separateSubchannel) sectorSize = (int)(blockSize - subSize);
|
||||
else sectorSize = (int)blockSize;
|
||||
|
||||
if(toc == null)
|
||||
{
|
||||
@@ -271,15 +268,17 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
sessionsForAlcohol[trk.SessionNumber - 1].EndTrack = trk.POINT;
|
||||
}
|
||||
}
|
||||
|
||||
alcohol.AddSessions(sessionsForAlcohol);
|
||||
|
||||
foreach(FullTOC.TrackDataDescriptor trk in toc.Value.TrackDescriptors)
|
||||
{
|
||||
alcohol.AddTrack((byte)((trk.ADR << 4) & trk.CONTROL), trk.TNO, trk.POINT, trk.Min, trk.Sec, trk.Frame,
|
||||
trk.Zero, trk.PMIN, trk.PSEC, trk.PFRAME, trk.SessionNumber);
|
||||
trk.Zero, trk.PMIN, trk.PSEC, trk.PFRAME, trk.SessionNumber);
|
||||
}
|
||||
|
||||
FullTOC.TrackDataDescriptor[] sortedTracks = toc.Value.TrackDescriptors.OrderBy(track => track.POINT).ToArray();
|
||||
FullTOC.TrackDataDescriptor[] sortedTracks =
|
||||
toc.Value.TrackDescriptors.OrderBy(track => track.POINT).ToArray();
|
||||
List<TrackType> trackList = new List<TrackType>();
|
||||
long lastSector = 0;
|
||||
string lastMSF = null;
|
||||
@@ -291,22 +290,18 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
TrackType track = new TrackType
|
||||
{
|
||||
Sequence = new TrackSequenceType
|
||||
{
|
||||
Session = trk.SessionNumber,
|
||||
TrackNumber = trk.POINT
|
||||
}
|
||||
Sequence = new TrackSequenceType {Session = trk.SessionNumber, TrackNumber = trk.POINT}
|
||||
};
|
||||
if((TOC_CONTROL)(trk.CONTROL & 0x0D) == TOC_CONTROL.DataTrack ||
|
||||
(TOC_CONTROL)(trk.CONTROL & 0x0D) == TOC_CONTROL.DataTrackIncremental)
|
||||
(TOC_CONTROL)(trk.CONTROL & 0x0D) == TOC_CONTROL.DataTrackIncremental)
|
||||
track.TrackType1 = TrackTypeTrackType.mode1;
|
||||
else
|
||||
track.TrackType1 = TrackTypeTrackType.audio;
|
||||
else track.TrackType1 = TrackTypeTrackType.audio;
|
||||
if(trk.PHOUR > 0)
|
||||
track.StartMSF = string.Format("{3:D2}:{0:D2}:{1:D2}:{2:D2}", trk.PMIN, trk.PSEC, trk.PFRAME, trk.PHOUR);
|
||||
else
|
||||
track.StartMSF = string.Format("{0:D2}:{1:D2}:{2:D2}", trk.PMIN, trk.PSEC, trk.PFRAME);
|
||||
track.StartSector = trk.PHOUR * 3600 * 75 + trk.PMIN * 60 * 75 + trk.PSEC * 75 + trk.PFRAME - 150;
|
||||
track.StartMSF = string.Format("{3:D2}:{0:D2}:{1:D2}:{2:D2}", trk.PMIN, trk.PSEC,
|
||||
trk.PFRAME, trk.PHOUR);
|
||||
else track.StartMSF = string.Format("{0:D2}:{1:D2}:{2:D2}", trk.PMIN, trk.PSEC, trk.PFRAME);
|
||||
track.StartSector = trk.PHOUR * 3600 * 75 + trk.PMIN * 60 * 75 + trk.PSEC * 75 + trk.PFRAME -
|
||||
150;
|
||||
trackList.Add(track);
|
||||
}
|
||||
else if(trk.POINT == 0xA2)
|
||||
@@ -346,17 +341,15 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
phour = trk.PHOUR;
|
||||
}
|
||||
|
||||
if(phour > 0)
|
||||
lastMSF = string.Format("{3:D2}:{0:D2}:{1:D2}:{2:D2}", pmin, psec, pframe, phour);
|
||||
else
|
||||
lastMSF = string.Format("{0:D2}:{1:D2}:{2:D2}", pmin, psec, pframe);
|
||||
if(phour > 0) lastMSF = string.Format("{3:D2}:{0:D2}:{1:D2}:{2:D2}", pmin, psec, pframe, phour);
|
||||
else lastMSF = string.Format("{0:D2}:{1:D2}:{2:D2}", pmin, psec, pframe);
|
||||
lastSector = phour * 3600 * 75 + pmin * 60 * 75 + psec * 75 + pframe - 150;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrackType[] tracks = trackList.ToArray();
|
||||
for(int t = 1; t < tracks.Length;t++)
|
||||
for(int t = 1; t < tracks.Length; t++)
|
||||
{
|
||||
tracks[t - 1].EndSector = tracks[t].StartSector - 1;
|
||||
int phour = 0, pmin = 0, psec = 0;
|
||||
@@ -380,9 +373,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(phour > 0)
|
||||
tracks[t - 1].EndMSF = string.Format("{3:D2}:{0:D2}:{1:D2}:{2:D2}", pmin, psec, pframe, phour);
|
||||
else
|
||||
tracks[t - 1].EndMSF = string.Format("{0:D2}:{1:D2}:{2:D2}", pmin, psec, pframe);
|
||||
else tracks[t - 1].EndMSF = string.Format("{0:D2}:{1:D2}:{2:D2}", pmin, psec, pframe);
|
||||
}
|
||||
|
||||
tracks[tracks.Length - 1].EndMSF = lastMSF;
|
||||
tracks[tracks.Length - 1].EndSector = lastSector;
|
||||
blocks = (ulong)(lastSector + 1);
|
||||
@@ -393,23 +386,21 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
return;
|
||||
}
|
||||
|
||||
if(dumpRaw)
|
||||
{
|
||||
throw new NotImplementedException("Raw CD dumping not yet implemented");
|
||||
}
|
||||
if(dumpRaw) { throw new NotImplementedException("Raw CD dumping not yet implemented"); }
|
||||
else
|
||||
{
|
||||
// TODO: Check subchannel capabilities
|
||||
readcd = !dev.ReadCd(out readBuffer, out senseBuf, 0, blockSize, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
|
||||
true, true, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, out duration);
|
||||
readcd = !dev.ReadCd(out readBuffer, out senseBuf, 0, blockSize, 1, MmcSectorTypes.AllTypes, false,
|
||||
false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
|
||||
MmcSubchannel.Raw, dev.Timeout, out duration);
|
||||
|
||||
if(readcd)
|
||||
DicConsole.WriteLine("Using MMC READ CD command.");
|
||||
if(readcd) DicConsole.WriteLine("Using MMC READ CD command.");
|
||||
}
|
||||
|
||||
DumpHardwareType currentTry = null;
|
||||
ExtentsULong extents = null;
|
||||
ResumeSupport.Process(true, true, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformID, ref resume, ref currentTry, ref extents);
|
||||
ResumeSupport.Process(true, true, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformID,
|
||||
ref resume, ref currentTry, ref extents);
|
||||
if(currentTry == null || extents == null)
|
||||
throw new Exception("Could not process resume file, not continuing...");
|
||||
|
||||
@@ -503,14 +494,13 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
if(readcd)
|
||||
{
|
||||
sense = dev.ReadCd(out readBuffer, out senseBuf, 0, blockSize, blocksToRead, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
|
||||
true, true, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, out duration);
|
||||
if(dev.Error || sense)
|
||||
blocksToRead /= 2;
|
||||
sense = dev.ReadCd(out readBuffer, out senseBuf, 0, blockSize, blocksToRead,
|
||||
MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
|
||||
true, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, out duration);
|
||||
if(dev.Error || sense) blocksToRead /= 2;
|
||||
}
|
||||
|
||||
if(!dev.Error || blocksToRead == 1)
|
||||
break;
|
||||
if(!dev.Error || blocksToRead == 1) break;
|
||||
}
|
||||
|
||||
if(dev.Error || sense)
|
||||
@@ -532,17 +522,14 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dumpFile = new DataFile(outputPrefix + ".bin");
|
||||
alcohol.SetExtension(".bin");
|
||||
DataFile subFile = null;
|
||||
if(separateSubchannel)
|
||||
subFile = new DataFile(outputPrefix + ".sub");
|
||||
if(separateSubchannel) subFile = new DataFile(outputPrefix + ".sub");
|
||||
mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
|
||||
ibgLog = new IBGLog(outputPrefix + ".ibg", 0x0008);
|
||||
|
||||
dumpFile.Seek(resume.NextBlock, (ulong)sectorSize);
|
||||
if(separateSubchannel)
|
||||
subFile.Seek(resume.NextBlock, subSize);
|
||||
if(separateSubchannel) subFile.Seek(resume.NextBlock, subSize);
|
||||
|
||||
if(resume.NextBlock > 0)
|
||||
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
|
||||
start = DateTime.UtcNow;
|
||||
for(int t = 0; t < tracks.Count(); t++)
|
||||
@@ -560,11 +547,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
tracks[t].Size = (tracks[t].EndSector - tracks[t].StartSector + 1) * sectorSize;
|
||||
tracks[t].SubChannel = new SubChannelType
|
||||
{
|
||||
Image = new ImageType
|
||||
{
|
||||
format = "rw_raw",
|
||||
offsetSpecified = true
|
||||
},
|
||||
Image = new ImageType {format = "rw_raw", offsetSpecified = true},
|
||||
Size = (tracks[t].EndSector - tracks[t].StartSector + 1) * subSize
|
||||
};
|
||||
if(separateSubchannel)
|
||||
@@ -578,8 +561,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
tracks[t].SubChannel.Image.Value = tracks[t].Image.Value;
|
||||
}
|
||||
|
||||
alcohol.SetTrackSizes((byte)(t + 1), sectorSize, tracks[t].StartSector, dumpFile.Position, (tracks[t].EndSector - tracks[t].StartSector + 1));
|
||||
|
||||
alcohol.SetTrackSizes((byte)(t + 1), sectorSize, tracks[t].StartSector, dumpFile.Position,
|
||||
(tracks[t].EndSector - tracks[t].StartSector + 1));
|
||||
|
||||
bool checkedDataFormat = false;
|
||||
|
||||
for(ulong i = resume.NextBlock; i <= (ulong)tracks[t].EndSector; i += blocksToRead)
|
||||
@@ -597,18 +581,18 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
blocksToRead = (uint)((ulong)tracks[t].EndSector + 1 - 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;
|
||||
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} at track {3} ({2:F3} MiB/sec.)", i, blocks, currentSpeed, t + 1);
|
||||
DicConsole.Write("\rReading sector {0} of {1} at track {3} ({2:F3} MiB/sec.)", i, blocks,
|
||||
currentSpeed, t + 1);
|
||||
|
||||
if(readcd)
|
||||
{
|
||||
sense = dev.ReadCd(out readBuffer, out senseBuf, (uint)i, blockSize, blocksToRead, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
|
||||
true, true, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, out cmdDuration);
|
||||
sense = dev.ReadCd(out readBuffer, out senseBuf, (uint)i, blockSize, blocksToRead,
|
||||
MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
|
||||
true, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, out cmdDuration);
|
||||
totalDuration += cmdDuration;
|
||||
}
|
||||
|
||||
@@ -625,14 +609,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
subFile.Write(readBuffer, (int)(sectorSize + b * blockSize), (int)subSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
dumpFile.Write(readBuffer);
|
||||
else dumpFile.Write(readBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Reset device after X errors
|
||||
if(stopOnError)
|
||||
return; // TODO: Return more cleanly
|
||||
if(stopOnError) return; // TODO: Return more cleanly
|
||||
|
||||
// Write empty data
|
||||
if(separateSubchannel)
|
||||
@@ -640,17 +622,15 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dumpFile.Write(new byte[sectorSize * blocksToRead]);
|
||||
subFile.Write(new byte[subSize * blocksToRead]);
|
||||
}
|
||||
else
|
||||
dumpFile.Write(new byte[blockSize * blocksToRead]);
|
||||
else dumpFile.Write(new byte[blockSize * blocksToRead]);
|
||||
|
||||
errored += blocksToRead;
|
||||
for(ulong b = i; b < i + blocksToRead; b++)
|
||||
resume.BadBlocks.Add(b);
|
||||
DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
if(cmdDuration < 500)
|
||||
mhddLog.Write(i, 65535);
|
||||
else
|
||||
mhddLog.Write(i, cmdDuration);
|
||||
for(ulong b = i; b < i + blocksToRead; b++) resume.BadBlocks.Add(b);
|
||||
|
||||
DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}",
|
||||
Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
if(cmdDuration < 500) mhddLog.Write(i, 65535);
|
||||
else mhddLog.Write(i, cmdDuration);
|
||||
|
||||
ibgLog.Write(i, 0);
|
||||
dumpLog.WriteLine("Error reading {0} sectors from sector {1}.", blocksToRead, i);
|
||||
@@ -660,7 +640,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
byte[] sync = new byte[12];
|
||||
Array.Copy(readBuffer, 0, sync, 0, 12);
|
||||
if(sync.SequenceEqual(new byte[] { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 }))
|
||||
if(sync.SequenceEqual(new byte[]
|
||||
{
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00
|
||||
}))
|
||||
{
|
||||
switch(readBuffer[15])
|
||||
{
|
||||
@@ -711,21 +694,25 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
case TrackTypeTrackType.mode0:
|
||||
trkType = ImagePlugins.TrackType.Data;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
alcohol.SetTrackTypes((byte)(t + 1), trkType,
|
||||
separateSubchannel ? TrackSubchannelType.None : TrackSubchannelType.RawInterleaved);
|
||||
separateSubchannel
|
||||
? TrackSubchannelType.None
|
||||
: TrackSubchannelType.RawInterleaved);
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
end = DateTime.UtcNow;
|
||||
mhddLog.Close();
|
||||
#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
|
||||
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 dump speed {0:F3} KiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
|
||||
|
||||
#region Compact Disc Error handling
|
||||
if(resume.BadBlocks.Count > 0 && !aborted)
|
||||
@@ -734,7 +721,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
bool forward = true;
|
||||
bool runningPersistent = false;
|
||||
|
||||
cdRepeatRetry:
|
||||
cdRepeatRetry:
|
||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||
foreach(ulong badSector in tmpArray)
|
||||
{
|
||||
@@ -747,12 +734,15 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
double cmdDuration = 0;
|
||||
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "");
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1,
|
||||
forward ? "forward" : "reverse",
|
||||
runningPersistent ? "recovering partial data, " : "");
|
||||
|
||||
if(readcd)
|
||||
{
|
||||
sense = dev.ReadCd(out readBuffer, out senseBuf, (uint)badSector, blockSize, blocksToRead, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
|
||||
true, true, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, out cmdDuration);
|
||||
sense = dev.ReadCd(out readBuffer, out senseBuf, (uint)badSector, blockSize, blocksToRead,
|
||||
MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
|
||||
true, MmcErrorField.None, MmcSubchannel.Raw, dev.Timeout, out cmdDuration);
|
||||
totalDuration += cmdDuration;
|
||||
}
|
||||
|
||||
@@ -764,14 +754,13 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
extents.Add(badSector);
|
||||
dumpLog.WriteLine("Correctly retried sector {0} in pass {1}.", badSector, pass);
|
||||
}
|
||||
|
||||
|
||||
if(separateSubchannel)
|
||||
{
|
||||
dumpFile.WriteAt(readBuffer, badSector, (uint)sectorSize, 0, sectorSize);
|
||||
subFile.WriteAt(readBuffer, badSector, subSize, sectorSize, (int)subSize);
|
||||
}
|
||||
else
|
||||
dumpFile.WriteAt(readBuffer, badSector, blockSize);
|
||||
else dumpFile.WriteAt(readBuffer, badSector, blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,47 +780,39 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(!runningPersistent && persistent)
|
||||
{
|
||||
sense = dev.ModeSense6(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current, 0x01, dev.Timeout, out duration);
|
||||
sense = dev.ModeSense6(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current, 0x01,
|
||||
dev.Timeout, out duration);
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ModeSense10(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current, 0x01, dev.Timeout, out duration);
|
||||
if(!sense)
|
||||
currentMode = Decoders.SCSI.Modes.DecodeMode10(readBuffer, dev.SCSIType);
|
||||
sense = dev.ModeSense10(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current,
|
||||
0x01, dev.Timeout, out duration);
|
||||
if(!sense) currentMode = Decoders.SCSI.Modes.DecodeMode10(readBuffer, dev.SCSIType);
|
||||
}
|
||||
else
|
||||
currentMode = Decoders.SCSI.Modes.DecodeMode6(readBuffer, dev.SCSIType);
|
||||
else currentMode = Decoders.SCSI.Modes.DecodeMode6(readBuffer, dev.SCSIType);
|
||||
|
||||
if(currentMode.HasValue)
|
||||
currentModePage = currentMode.Value.Pages[0];
|
||||
if(currentMode.HasValue) currentModePage = currentMode.Value.Pages[0];
|
||||
|
||||
Decoders.SCSI.Modes.ModePage_01_MMC pgMMC = new Decoders.SCSI.Modes.ModePage_01_MMC
|
||||
{
|
||||
PS = false,
|
||||
ReadRetryCount = 255,
|
||||
Parameter = 0x20
|
||||
};
|
||||
Decoders.SCSI.Modes.ModePage_01_MMC pgMMC =
|
||||
new Decoders.SCSI.Modes.ModePage_01_MMC {PS = false, ReadRetryCount = 255, Parameter = 0x20};
|
||||
Decoders.SCSI.Modes.DecodedMode md = new Decoders.SCSI.Modes.DecodedMode
|
||||
{
|
||||
Header = new Decoders.SCSI.Modes.ModeHeader(),
|
||||
Pages = new Decoders.SCSI.Modes.ModePage[]
|
||||
{
|
||||
new Decoders.SCSI.Modes.ModePage
|
||||
{
|
||||
Page = 0x01,
|
||||
Subpage = 0x00,
|
||||
PageResponse = Decoders.SCSI.Modes.EncodeModePage_01_MMC(pgMMC)
|
||||
}
|
||||
}
|
||||
{
|
||||
new Decoders.SCSI.Modes.ModePage
|
||||
{
|
||||
Page = 0x01,
|
||||
Subpage = 0x00,
|
||||
PageResponse = Decoders.SCSI.Modes.EncodeModePage_01_MMC(pgMMC)
|
||||
}
|
||||
}
|
||||
};
|
||||
md6 = Decoders.SCSI.Modes.EncodeMode6(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);
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration);
|
||||
}
|
||||
if(sense) { sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration); }
|
||||
|
||||
runningPersistent = true;
|
||||
if(!sense && !dev.Error)
|
||||
@@ -845,32 +826,26 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Decoders.SCSI.Modes.DecodedMode md = new Decoders.SCSI.Modes.DecodedMode
|
||||
{
|
||||
Header = new Decoders.SCSI.Modes.ModeHeader(),
|
||||
Pages = new Decoders.SCSI.Modes.ModePage[]
|
||||
{
|
||||
currentModePage.Value
|
||||
}
|
||||
Pages = new Decoders.SCSI.Modes.ModePage[] {currentModePage.Value}
|
||||
};
|
||||
md6 = Decoders.SCSI.Modes.EncodeMode6(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);
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration);
|
||||
}
|
||||
if(sense) { sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration); }
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
}
|
||||
#endregion Compact Disc Error handling
|
||||
|
||||
resume.BadBlocks.Sort();
|
||||
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
|
||||
|
||||
dataChk = new Checksum();
|
||||
dumpFile.Seek(0, SeekOrigin.Begin);
|
||||
if(separateSubchannel)
|
||||
subFile.Seek(0, SeekOrigin.Begin);
|
||||
if(separateSubchannel) subFile.Seek(0, SeekOrigin.Begin);
|
||||
blocksToRead = 500;
|
||||
|
||||
dumpLog.WriteLine("Checksum starts.");
|
||||
@@ -890,7 +865,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
if(((ulong)tracks[t].EndSector + 1 - i) < blocksToRead)
|
||||
blocksToRead = (uint)((ulong)tracks[t].EndSector + 1 - i);
|
||||
|
||||
DicConsole.Write("\rChecksumming sector {0} of {1} at track {3} ({2:F3} MiB/sec.)", i, blocks, currentSpeed, t + 1);
|
||||
DicConsole.Write("\rChecksumming sector {0} of {1} at track {3} ({2:F3} MiB/sec.)", i, blocks,
|
||||
currentSpeed, t + 1);
|
||||
|
||||
DateTime chkStart = DateTime.UtcNow;
|
||||
byte[] dataToCheck = new byte[blockSize * blocksToRead];
|
||||
@@ -913,6 +889,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dataChk.Update(dataToCheck);
|
||||
trkChk.Update(dataToCheck);
|
||||
}
|
||||
|
||||
DateTime chkEnd = DateTime.UtcNow;
|
||||
|
||||
double chkDuration = (chkEnd - chkStart).TotalMilliseconds;
|
||||
@@ -924,16 +901,16 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
tracks[t].Checksums = trkChk.End().ToArray();
|
||||
if(separateSubchannel)
|
||||
tracks[t].SubChannel.Checksums = subChk.End().ToArray();
|
||||
else
|
||||
tracks[t].SubChannel.Checksums = tracks[t].Checksums;
|
||||
if(separateSubchannel) tracks[t].SubChannel.Checksums = subChk.End().ToArray();
|
||||
else tracks[t].SubChannel.Checksums = tracks[t].Checksums;
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
dumpFile.Close();
|
||||
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));
|
||||
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
|
||||
|
||||
// TODO: Correct this
|
||||
sidecar.OpticalDisc[0].Checksums = dataChk.End().ToArray();
|
||||
@@ -944,7 +921,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Value = outputPrefix + ".bin"
|
||||
};
|
||||
sidecar.OpticalDisc[0].Sessions = toc.Value.LastCompleteSession;
|
||||
sidecar.OpticalDisc[0].Tracks = new[] { tracks.Count() };
|
||||
sidecar.OpticalDisc[0].Tracks = new[] {tracks.Count()};
|
||||
sidecar.OpticalDisc[0].Track = tracks;
|
||||
sidecar.OpticalDisc[0].Dimensions = Metadata.Dimensions.DimensionsFromMediaType(dskType);
|
||||
Metadata.MediaType.MediaTypeToString(dskType, out string xmlDskTyp, out string xmlDskSubTyp);
|
||||
@@ -955,10 +932,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
DicConsole.WriteLine("Writing metadata sidecar");
|
||||
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml",
|
||||
FileMode.Create);
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
|
||||
|
||||
System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
System.Xml.Serialization.XmlSerializer xmlSer =
|
||||
new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
xmlSer.Serialize(xmlFs, sidecar);
|
||||
xmlFs.Close();
|
||||
alcohol.Close();
|
||||
@@ -967,4 +944,4 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Statistics.AddMedia(dskType, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
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, ref DumpLog dumpLog, bool dumpLeadIn, Encoding encoding)
|
||||
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, bool dumpLeadIn, Encoding encoding)
|
||||
{
|
||||
byte[] cmdBuf = null;
|
||||
byte[] senseBuf = null;
|
||||
@@ -60,7 +63,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
// 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)
|
||||
{
|
||||
Decoders.SCSI.MMC.Features.SeparatedFeatures ftr = Decoders.SCSI.MMC.Features.Separate(cmdBuf);
|
||||
@@ -164,7 +168,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(compactDisc)
|
||||
{
|
||||
CompactDisc.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, separateSubchannel, ref resume, ref dumpLog, alcohol, dumpLeadIn);
|
||||
CompactDisc.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError,
|
||||
ref sidecar, ref dskType, separateSubchannel, ref resume, ref dumpLog, alcohol,
|
||||
dumpLeadIn);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -176,17 +182,19 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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)
|
||||
{
|
||||
Decoders.DVD.PFI.PhysicalFormatInformation? nintendoPfi = Decoders.DVD.PFI.Decode(cmdBuf);
|
||||
if(nintendoPfi != null)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -194,18 +202,16 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
#endregion Nintendo
|
||||
|
||||
#region All DVD and HD DVD types
|
||||
if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDPR ||
|
||||
dskType == MediaType.DVDPRDL || dskType == MediaType.DVDPRW ||
|
||||
dskType == MediaType.DVDPRWDL || dskType == MediaType.DVDR ||
|
||||
dskType == MediaType.DVDRAM || dskType == MediaType.DVDRDL ||
|
||||
dskType == MediaType.DVDROM || dskType == MediaType.DVDRW ||
|
||||
dskType == MediaType.DVDRWDL || dskType == MediaType.HDDVDR ||
|
||||
dskType == MediaType.HDDVDRAM || dskType == MediaType.HDDVDRDL ||
|
||||
dskType == MediaType.HDDVDROM || dskType == MediaType.HDDVDRW ||
|
||||
dskType == MediaType.HDDVDRWDL)
|
||||
if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDPR || dskType == MediaType.DVDPRDL ||
|
||||
dskType == MediaType.DVDPRW || dskType == MediaType.DVDPRWDL || dskType == MediaType.DVDR ||
|
||||
dskType == MediaType.DVDRAM || dskType == MediaType.DVDRDL || dskType == MediaType.DVDROM ||
|
||||
dskType == MediaType.DVDRW || dskType == MediaType.DVDRWDL || dskType == MediaType.HDDVDR ||
|
||||
dskType == MediaType.HDDVDRAM || dskType == MediaType.HDDVDRDL || dskType == MediaType.HDDVDROM ||
|
||||
dskType == MediaType.HDDVDRW || 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)
|
||||
{
|
||||
alcohol.AddPFI(cmdBuf);
|
||||
@@ -242,10 +248,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dskType = MediaType.DVDPRWDL;
|
||||
break;
|
||||
case Decoders.DVD.DiskCategory.DVDR:
|
||||
if(decPfi.PartVersion == 6)
|
||||
dskType = MediaType.DVDRDL;
|
||||
else
|
||||
dskType = MediaType.DVDR;
|
||||
if(decPfi.PartVersion == 6) dskType = MediaType.DVDRDL;
|
||||
else dskType = MediaType.DVDR;
|
||||
break;
|
||||
case Decoders.DVD.DiskCategory.DVDRAM:
|
||||
dskType = MediaType.DVDRAM;
|
||||
@@ -254,10 +258,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dskType = MediaType.DVDROM;
|
||||
break;
|
||||
case Decoders.DVD.DiskCategory.DVDRW:
|
||||
if(decPfi.PartVersion == 3)
|
||||
dskType = MediaType.DVDRWDL;
|
||||
else
|
||||
dskType = MediaType.DVDRW;
|
||||
if(decPfi.PartVersion == 3) dskType = MediaType.DVDRWDL;
|
||||
else dskType = MediaType.DVDRW;
|
||||
break;
|
||||
case Decoders.DVD.DiskCategory.HDDVDR:
|
||||
dskType = MediaType.HDDVDR;
|
||||
@@ -272,10 +274,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dskType = MediaType.HDDVDRW;
|
||||
break;
|
||||
case Decoders.DVD.DiskCategory.Nintendo:
|
||||
if(decPfi.DiscSize == Decoders.DVD.DVDSize.Eighty)
|
||||
dskType = MediaType.GOD;
|
||||
else
|
||||
dskType = MediaType.WOD;
|
||||
if(decPfi.DiscSize == Decoders.DVD.DVDSize.Eighty) dskType = MediaType.GOD;
|
||||
else dskType = MediaType.WOD;
|
||||
break;
|
||||
case Decoders.DVD.DiskCategory.UMD:
|
||||
dskType = MediaType.UMD;
|
||||
@@ -286,13 +286,14 @@ 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(Decoders.Xbox.DMI.IsXbox(cmdBuf) || Decoders.Xbox.DMI.IsXbox360(cmdBuf))
|
||||
{
|
||||
if(Decoders.Xbox.DMI.IsXbox(cmdBuf))
|
||||
dskType = MediaType.XGD;
|
||||
if(Decoders.Xbox.DMI.IsXbox(cmdBuf)) dskType = MediaType.XGD;
|
||||
else if(Decoders.Xbox.DMI.IsXbox360(cmdBuf))
|
||||
{
|
||||
dskType = MediaType.XGD2;
|
||||
@@ -307,15 +308,18 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
sense = dev.ScsiInquiry(out byte[] inqBuf, out senseBuf);
|
||||
|
||||
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)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Not continuing. If you want to continue reading cooked data when raw is not available use the force option.");
|
||||
DicConsole
|
||||
.ErrorWriteLine("Not continuing. If you want to continue reading cooked data when raw is not available use the force option.");
|
||||
// TODO: Exit more gracefully
|
||||
return;
|
||||
}
|
||||
@@ -324,7 +328,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
alcohol.AddDMI(cmdBuf);
|
||||
|
||||
|
||||
if(cmdBuf.Length == 2052)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -345,7 +349,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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(Decoders.DVD.CSS_CPRM.DecodeLeadInCopyright(cmdBuf).HasValue)
|
||||
@@ -360,7 +366,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
};
|
||||
DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].CMI.Image, tmpBuf);
|
||||
|
||||
Decoders.DVD.CSS_CPRM.LeadInCopyright cpy = Decoders.DVD.CSS_CPRM.DecodeLeadInCopyright(cmdBuf).Value;
|
||||
Decoders.DVD.CSS_CPRM.LeadInCopyright cpy =
|
||||
Decoders.DVD.CSS_CPRM.DecodeLeadInCopyright(cmdBuf).Value;
|
||||
if(cpy.CopyrightType != Decoders.DVD.CopyrightType.NoProtection)
|
||||
sidecar.OpticalDisc[0].CopyProtection = cpy.CopyrightType.ToString();
|
||||
}
|
||||
@@ -369,11 +376,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
#endregion DVD-ROM
|
||||
|
||||
#region DVD-ROM and HD DVD-ROM
|
||||
if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDROM ||
|
||||
dskType == MediaType.HDDVDROM)
|
||||
if(dskType == MediaType.DVDDownload || dskType == MediaType.DVDROM || 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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -394,7 +401,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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(Decoders.DVD.DDS.Decode(cmdBuf).HasValue)
|
||||
@@ -412,7 +420,9 @@ 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(Decoders.DVD.Spare.Decode(cmdBuf).HasValue)
|
||||
@@ -435,7 +445,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -455,7 +466,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -470,7 +483,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -487,11 +502,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
#endregion DVD-R, DVD-RW and HD DVD-R
|
||||
|
||||
#region All DVD+
|
||||
if(dskType == MediaType.DVDPR || dskType == MediaType.DVDPRDL ||
|
||||
dskType == MediaType.DVDPRW || dskType == MediaType.DVDPRWDL)
|
||||
if(dskType == MediaType.DVDPR || dskType == MediaType.DVDPRDL || 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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -506,7 +522,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -526,7 +543,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -544,10 +563,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
#region All Blu-ray
|
||||
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(Decoders.Bluray.DI.Decode(cmdBuf).HasValue)
|
||||
@@ -565,7 +585,8 @@ 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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -581,12 +602,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
#endregion All Blu-ray
|
||||
|
||||
|
||||
#region BD-ROM only
|
||||
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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -604,11 +625,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
#endregion BD-ROM only
|
||||
|
||||
#region Writable Blu-ray only
|
||||
if(dskType == MediaType.BDR || dskType == MediaType.BDRE ||
|
||||
dskType == MediaType.BDRXL || dskType == MediaType.BDREXL)
|
||||
if(dskType == MediaType.BDR || dskType == MediaType.BDRE || 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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -623,7 +645,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
tmpBuf = new byte[cmdBuf.Length - 4];
|
||||
@@ -641,11 +665,13 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(isXbox)
|
||||
{
|
||||
XGD.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, ref resume, ref dumpLog, encoding);
|
||||
XGD.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError,
|
||||
ref sidecar, ref dskType, ref resume, ref dumpLog, encoding);
|
||||
return;
|
||||
}
|
||||
|
||||
SBC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, true, ref resume, ref dumpLog, encoding, alcohol);
|
||||
SBC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar,
|
||||
ref dskType, true, ref resume, ref dumpLog, encoding, alcohol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,9 +39,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
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, ref DumpLog dumpLog, Encoding encoding)
|
||||
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, Encoding encoding)
|
||||
{
|
||||
throw new NotImplementedException("NVMe devices not yet supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40,45 +40,51 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
public static class ResumeSupport
|
||||
{
|
||||
public static void Process(bool isLba, bool removable, ulong blocks, string Manufacturer, string Model, string Serial, Interop.PlatformID platform, ref Resume resume, ref DumpHardwareType currentTry, ref ExtentsULong extents)
|
||||
public static void Process(bool isLba, bool removable, ulong blocks, string Manufacturer, string Model,
|
||||
string Serial, Interop.PlatformID platform, ref Resume resume,
|
||||
ref DumpHardwareType currentTry, ref ExtentsULong extents)
|
||||
{
|
||||
if(resume != null)
|
||||
{
|
||||
if(!isLba)
|
||||
throw new NotImplementedException("Resuming CHS devices is currently not supported.");
|
||||
if(!isLba) throw new NotImplementedException("Resuming CHS devices is currently not supported.");
|
||||
|
||||
if(resume.Removable != removable)
|
||||
throw new Exception(string.Format("Resume file specifies a {0} device but you're requesting to dump a {1} device, not continuing...",
|
||||
resume.Removable ? "removable" : "non removable",
|
||||
removable ? "removable" : "non removable"));
|
||||
throw new
|
||||
Exception(string.Format("Resume file specifies a {0} device but you're requesting to dump a {1} device, not continuing...",
|
||||
resume.Removable ? "removable" : "non removable",
|
||||
removable ? "removable" : "non removable"));
|
||||
|
||||
if(resume.LastBlock != blocks - 1)
|
||||
throw new Exception(string.Format("Resume file specifies a device with {0} blocks but you're requesting to dump one with {1} blocks, not continuing...",
|
||||
resume.LastBlock + 1, blocks));
|
||||
|
||||
throw new
|
||||
Exception(string.Format("Resume file specifies a device with {0} blocks but you're requesting to dump one with {1} blocks, not continuing...",
|
||||
resume.LastBlock + 1, blocks));
|
||||
|
||||
foreach(DumpHardwareType oldtry in resume.Tries)
|
||||
{
|
||||
if(oldtry.Manufacturer != Manufacturer && !removable)
|
||||
throw new Exception(string.Format("Resume file specifies a device manufactured by {0} but you're requesting to dump one by {1}, not continuing...",
|
||||
oldtry.Manufacturer, Manufacturer));
|
||||
throw new
|
||||
Exception(string.Format("Resume file specifies a device manufactured by {0} but you're requesting to dump one by {1}, not continuing...",
|
||||
oldtry.Manufacturer, Manufacturer));
|
||||
|
||||
if(oldtry.Model != Model && !removable)
|
||||
throw new Exception(string.Format("Resume file specifies a device model {0} but you're requesting to dump model {1}, not continuing...",
|
||||
oldtry.Model, Model));
|
||||
throw new
|
||||
Exception(string.Format("Resume file specifies a device model {0} but you're requesting to dump model {1}, not continuing...",
|
||||
oldtry.Model, Model));
|
||||
|
||||
if(oldtry.Serial != Serial && !removable)
|
||||
throw new Exception(string.Format("Resume file specifies a device with serial {0} but you're requesting to dump one with serial {1}, not continuing...",
|
||||
oldtry.Serial, Serial));
|
||||
throw new
|
||||
Exception(string.Format("Resume file specifies a device with serial {0} but you're requesting to dump one with serial {1}, not continuing...",
|
||||
oldtry.Serial, Serial));
|
||||
|
||||
if(oldtry.Software == null)
|
||||
throw new Exception("Found corrupt resume file, cannot continue...");
|
||||
if(oldtry.Software == null) throw new Exception("Found corrupt resume file, cannot continue...");
|
||||
|
||||
if(oldtry.Software.Name == "DiscImageChef" && oldtry.Software.OperatingSystem == platform.ToString() && oldtry.Software.Version == Version.GetVersion())
|
||||
if(oldtry.Software.Name == "DiscImageChef" &&
|
||||
oldtry.Software.OperatingSystem == platform.ToString() &&
|
||||
oldtry.Software.Version == Version.GetVersion())
|
||||
{
|
||||
if(removable && (oldtry.Manufacturer != Manufacturer || oldtry.Model != Model || oldtry.Serial != Serial))
|
||||
continue;
|
||||
|
||||
if(removable && (oldtry.Manufacturer != Manufacturer || oldtry.Model != Model ||
|
||||
oldtry.Serial != Serial)) continue;
|
||||
|
||||
currentTry = oldtry;
|
||||
extents = ExtentsConverter.FromMetadata(currentTry.Extents);
|
||||
break;
|
||||
@@ -120,4 +126,4 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
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, ref DumpLog dumpLog, Encoding encoding, Alcohol120 alcohol = null)
|
||||
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, Encoding encoding, Alcohol120 alcohol = null)
|
||||
{
|
||||
MHDDLog mhddLog;
|
||||
IBGLog ibgLog;
|
||||
@@ -80,10 +83,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
ulong errored = 0;
|
||||
DataFile dumpFile = null;
|
||||
bool aborted = false;
|
||||
System.Console.CancelKeyPress += (sender, e) =>
|
||||
{
|
||||
e.Cancel = aborted = true;
|
||||
};
|
||||
System.Console.CancelKeyPress += (sender, e) => { e.Cancel = aborted = true; };
|
||||
|
||||
dumpLog.WriteLine("Initializing reader.");
|
||||
Reader scsiReader = new Reader(dev, dev.Timeout, null, dumpRaw);
|
||||
@@ -99,8 +99,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
if(blocks != 0 && blockSize != 0)
|
||||
{
|
||||
blocks++;
|
||||
DicConsole.WriteLine("Media has {0} blocks of {1} bytes/each. (for a total of {2} bytes)",
|
||||
blocks, blockSize, blocks * (ulong)blockSize);
|
||||
DicConsole.WriteLine("Media has {0} blocks of {1} bytes/each. (for a total of {2} bytes)", blocks,
|
||||
blockSize, blocks * (ulong)blockSize);
|
||||
}
|
||||
// Check how many blocks to read, if error show and return
|
||||
if(scsiReader.GetBlocksToRead())
|
||||
@@ -109,6 +109,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine(scsiReader.ErrorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
blocksToRead = scsiReader.BlocksToRead;
|
||||
logicalBlockSize = blockSize;
|
||||
physicalBlockSize = scsiReader.PhysicalBlockSize;
|
||||
@@ -121,10 +122,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
if(dskType == MediaType.Unknown)
|
||||
dskType = MediaTypeFromSCSI.Get((byte)dev.SCSIType, dev.Manufacturer, dev.Model, scsiMediumType, scsiDensityCode, blocks, blockSize);
|
||||
dskType = MediaTypeFromSCSI.Get((byte)dev.SCSIType, dev.Manufacturer, dev.Model, scsiMediumType,
|
||||
scsiDensityCode, blocks, blockSize);
|
||||
|
||||
if(dskType == MediaType.Unknown && dev.IsUSB && containsFloppyPage)
|
||||
dskType = MediaType.FlashDrive;
|
||||
if(dskType == MediaType.Unknown && dev.IsUSB && containsFloppyPage) dskType = MediaType.FlashDrive;
|
||||
|
||||
DicConsole.WriteLine("Media identified as {0}", dskType);
|
||||
|
||||
@@ -224,16 +225,17 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
|
||||
if(evpds.Count > 0)
|
||||
sidecar.BlockMedia[0].SCSI.EVPD = evpds.ToArray();
|
||||
if(evpds.Count > 0) sidecar.BlockMedia[0].SCSI.EVPD = evpds.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
sense = dev.ModeSense10(out cmdBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration);
|
||||
sense = dev.ModeSense10(out cmdBuf, out senseBuf, false, true,
|
||||
ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration);
|
||||
}
|
||||
|
||||
Decoders.SCSI.Modes.DecodedMode? decMode = null;
|
||||
@@ -254,11 +256,12 @@ 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)
|
||||
sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration);
|
||||
if(sense || dev.Error)
|
||||
sense = dev.ModeSense(out cmdBuf, out senseBuf, 5, out duration);
|
||||
sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current,
|
||||
0x3F, 0x00, 5, out duration);
|
||||
if(sense || dev.Error) sense = dev.ModeSense(out cmdBuf, out senseBuf, 5, out duration);
|
||||
|
||||
if(!sense && !dev.Error)
|
||||
{
|
||||
@@ -278,7 +281,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
if(decMode.HasValue)
|
||||
{
|
||||
scsiMediumType = (byte)decMode.Value.Header.MediumType;
|
||||
if(decMode.Value.Header.BlockDescriptors != null && decMode.Value.Header.BlockDescriptors.Length >= 1)
|
||||
if(decMode.Value.Header.BlockDescriptors != null &&
|
||||
decMode.Value.Header.BlockDescriptors.Length >= 1)
|
||||
scsiDensityCode = (byte)decMode.Value.Header.BlockDescriptors[0].Density;
|
||||
|
||||
foreach(Decoders.SCSI.Modes.ModePage modePage in decMode.Value.Pages)
|
||||
@@ -300,12 +304,14 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
else
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Device is capable of reading raw data but I've been unable to guess correct sector size.");
|
||||
DicConsole
|
||||
.ErrorWriteLine("Device is capable of reading raw data but I've been unable to guess correct sector size.");
|
||||
}
|
||||
|
||||
if(!force)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Not continuing. If you want to continue reading cooked data when raw is not available use the force option.");
|
||||
DicConsole
|
||||
.ErrorWriteLine("Not continuing. If you want to continue reading cooked data when raw is not available use the force option.");
|
||||
// TODO: Exit more gracefully
|
||||
return;
|
||||
}
|
||||
@@ -315,23 +321,21 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if(longBlockSize == 37856) // Only a block will be read, but it contains 16 sectors and command expect sector number not block number
|
||||
if(longBlockSize == 37856
|
||||
) // Only a block will be read, but it contains 16 sectors and command expect sector number not block number
|
||||
blocksToRead = 16;
|
||||
else
|
||||
blocksToRead = 1;
|
||||
DicConsole.WriteLine("Reading {0} raw bytes ({1} cooked bytes) per sector.",
|
||||
longBlockSize, blockSize * blocksToRead);
|
||||
else blocksToRead = 1;
|
||||
DicConsole.WriteLine("Reading {0} raw bytes ({1} cooked bytes) per sector.", longBlockSize,
|
||||
blockSize * blocksToRead);
|
||||
physicalBlockSize = longBlockSize;
|
||||
blockSize = longBlockSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead);
|
||||
|
||||
string outputExtension = ".bin";
|
||||
if(opticalDisc && blockSize == 2048)
|
||||
outputExtension = ".iso";
|
||||
if(opticalDisc && blockSize == 2048) outputExtension = ".iso";
|
||||
mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
|
||||
ibgLog = new IBGLog(outputPrefix + ".ibg", currentProfile);
|
||||
dumpFile = new DataFile(outputPrefix + outputExtension);
|
||||
@@ -342,21 +346,22 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(alcohol != null && !dumpRaw)
|
||||
{
|
||||
alcohol.AddSessions(new [] { new Session() { StartTrack = 1, EndTrack = 1, SessionSequence = 1}});
|
||||
alcohol.AddSessions(new[] {new Session() {StartTrack = 1, EndTrack = 1, SessionSequence = 1}});
|
||||
alcohol.AddTrack(20, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1);
|
||||
alcohol.SetExtension(outputExtension);
|
||||
alcohol.SetTrackSizes(1, (int)blockSize, 0, 0, (long)blocks);
|
||||
alcohol.SetTrackTypes(1, TrackType.Data, TrackSubchannelType.None);
|
||||
}
|
||||
|
||||
|
||||
DumpHardwareType currentTry = null;
|
||||
ExtentsULong extents = null;
|
||||
ResumeSupport.Process(true, dev.IsRemovable, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformID, ref resume, ref currentTry, ref extents);
|
||||
ResumeSupport.Process(true, dev.IsRemovable, blocks, dev.Manufacturer, dev.Model, dev.Serial,
|
||||
dev.PlatformID, ref resume, ref currentTry, ref extents);
|
||||
if(currentTry == null || extents == null)
|
||||
throw new Exception("Could not process resume file, not continuing...");
|
||||
|
||||
dumpFile.Seek(resume.NextBlock, blockSize);
|
||||
if(resume.NextBlock > 0)
|
||||
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
|
||||
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
|
||||
{
|
||||
@@ -367,14 +372,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if((blocks - i) < blocksToRead)
|
||||
blocksToRead = (uint)(blocks - i);
|
||||
if((blocks - i) < blocksToRead) blocksToRead = (uint)(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;
|
||||
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);
|
||||
@@ -392,19 +394,16 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
else
|
||||
{
|
||||
// TODO: Reset device after X errors
|
||||
if(stopOnError)
|
||||
return; // TODO: Return more cleanly
|
||||
if(stopOnError) return; // TODO: Return more cleanly
|
||||
|
||||
// Write empty data
|
||||
dumpFile.Write(new byte[blockSize * blocksToRead]);
|
||||
|
||||
errored += blocksToRead;
|
||||
for(ulong b = i; b < i + blocksToRead; b++)
|
||||
resume.BadBlocks.Add(b);
|
||||
if(cmdDuration < 500)
|
||||
mhddLog.Write(i, 65535);
|
||||
else
|
||||
mhddLog.Write(i, cmdDuration);
|
||||
for(ulong b = i; b < i + blocksToRead; b++) resume.BadBlocks.Add(b);
|
||||
|
||||
if(cmdDuration < 500) mhddLog.Write(i, 65535);
|
||||
else mhddLog.Write(i, cmdDuration);
|
||||
|
||||
ibgLog.Write(i, 0);
|
||||
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i);
|
||||
@@ -415,14 +414,17 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
#pragma warning restore IDE0004 // Remove Unnecessary Cast
|
||||
resume.NextBlock = i + blocksToRead;
|
||||
}
|
||||
|
||||
end = DateTime.UtcNow;
|
||||
DicConsole.WriteLine();
|
||||
mhddLog.Close();
|
||||
#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
|
||||
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 dump speed {0:F3} KiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
|
||||
|
||||
#region Error handling
|
||||
if(resume.BadBlocks.Count > 0 && !aborted)
|
||||
@@ -431,7 +433,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
bool forward = true;
|
||||
bool runningPersistent = false;
|
||||
|
||||
repeatRetry:
|
||||
repeatRetry:
|
||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||
foreach(ulong badSector in tmpArray)
|
||||
{
|
||||
@@ -442,7 +444,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "");
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1,
|
||||
forward ? "forward" : "reverse",
|
||||
runningPersistent ? "recovering partial data, " : "");
|
||||
|
||||
sense = scsiReader.ReadBlock(out readBuffer, badSector, out double cmdDuration);
|
||||
totalDuration += cmdDuration;
|
||||
@@ -454,8 +458,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dumpFile.WriteAt(readBuffer, badSector, blockSize);
|
||||
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
|
||||
}
|
||||
else if(runningPersistent)
|
||||
dumpFile.WriteAt(readBuffer, badSector, blockSize);
|
||||
else if(runningPersistent) dumpFile.WriteAt(readBuffer, badSector, blockSize);
|
||||
}
|
||||
|
||||
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
|
||||
@@ -474,27 +477,27 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(!runningPersistent && persistent)
|
||||
{
|
||||
sense = dev.ModeSense6(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current, 0x01, dev.Timeout, out duration);
|
||||
sense = dev.ModeSense6(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current, 0x01,
|
||||
dev.Timeout, out duration);
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ModeSense10(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current, 0x01, dev.Timeout, out duration);
|
||||
if(!sense)
|
||||
currentMode = Decoders.SCSI.Modes.DecodeMode10(readBuffer, dev.SCSIType);
|
||||
sense = dev.ModeSense10(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current,
|
||||
0x01, dev.Timeout, out duration);
|
||||
if(!sense) currentMode = Decoders.SCSI.Modes.DecodeMode10(readBuffer, dev.SCSIType);
|
||||
}
|
||||
else
|
||||
currentMode = Decoders.SCSI.Modes.DecodeMode6(readBuffer, dev.SCSIType);
|
||||
else currentMode = Decoders.SCSI.Modes.DecodeMode6(readBuffer, dev.SCSIType);
|
||||
|
||||
if(currentMode.HasValue)
|
||||
currentModePage = currentMode.Value.Pages[0];
|
||||
if(currentMode.HasValue) currentModePage = currentMode.Value.Pages[0];
|
||||
|
||||
if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice)
|
||||
{
|
||||
Decoders.SCSI.Modes.ModePage_01_MMC pgMMC = new Decoders.SCSI.Modes.ModePage_01_MMC
|
||||
{
|
||||
PS = false,
|
||||
ReadRetryCount = 255,
|
||||
Parameter = 0x20
|
||||
};
|
||||
Decoders.SCSI.Modes.ModePage_01_MMC pgMMC =
|
||||
new Decoders.SCSI.Modes.ModePage_01_MMC
|
||||
{
|
||||
PS = false,
|
||||
ReadRetryCount = 255,
|
||||
Parameter = 0x20
|
||||
};
|
||||
Decoders.SCSI.Modes.DecodedMode md = new Decoders.SCSI.Modes.DecodedMode
|
||||
{
|
||||
Header = new Decoders.SCSI.Modes.ModeHeader(),
|
||||
@@ -545,10 +548,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
dumpLog.WriteLine("Sending MODE SELECT to drive.");
|
||||
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration);
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration);
|
||||
}
|
||||
if(sense) { sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration); }
|
||||
|
||||
runningPersistent = true;
|
||||
if(!sense && !dev.Error)
|
||||
@@ -562,25 +562,20 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Decoders.SCSI.Modes.DecodedMode md = new Decoders.SCSI.Modes.DecodedMode
|
||||
{
|
||||
Header = new Decoders.SCSI.Modes.ModeHeader(),
|
||||
Pages = new Decoders.SCSI.Modes.ModePage[]
|
||||
{
|
||||
currentModePage.Value
|
||||
}
|
||||
Pages = new Decoders.SCSI.Modes.ModePage[] {currentModePage.Value}
|
||||
};
|
||||
md6 = Decoders.SCSI.Modes.EncodeMode6(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);
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration);
|
||||
}
|
||||
if(sense) { sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration); }
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
}
|
||||
#endregion Error handling
|
||||
|
||||
resume.BadBlocks.Sort();
|
||||
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
|
||||
|
||||
@@ -597,8 +592,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if((blocks - i) < blocksToRead)
|
||||
blocksToRead = (uint)(blocks - i);
|
||||
if((blocks - i) < blocksToRead) blocksToRead = (uint)(blocks - i);
|
||||
|
||||
DicConsole.Write("\rChecksumming sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed);
|
||||
|
||||
@@ -615,11 +609,13 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (chkDuration / (double)1000);
|
||||
#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
dumpFile.Close();
|
||||
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));
|
||||
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
|
||||
|
||||
PluginBase plugins = new PluginBase();
|
||||
plugins.RegisterAllPlugins(encoding);
|
||||
@@ -636,15 +632,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
_imageFormat = ImageFormat.Detect(inputFilter);
|
||||
PartitionType[] xmlFileSysInfo = null;
|
||||
|
||||
try
|
||||
{
|
||||
if(!_imageFormat.OpenImage(inputFilter))
|
||||
_imageFormat = null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_imageFormat = null;
|
||||
}
|
||||
try { if(!_imageFormat.OpenImage(inputFilter)) _imageFormat = null; }
|
||||
catch { _imageFormat = null; }
|
||||
|
||||
if(_imageFormat != null)
|
||||
{
|
||||
@@ -669,7 +658,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
};
|
||||
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);
|
||||
i, partitions[i].Start, partitions[i].End, partitions[i].Type,
|
||||
partitions[i].Scheme);
|
||||
|
||||
foreach(Filesystem _plugin in plugins.PluginsList.Values)
|
||||
{
|
||||
@@ -682,12 +672,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Statistics.AddFilesystem(_plugin.XmlFSType.Type);
|
||||
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
|
||||
|
||||
if(_plugin.XmlFSType.Type == "Opera")
|
||||
dskType = MediaType.ThreeDO;
|
||||
if(_plugin.XmlFSType.Type == "Opera") dskType = MediaType.ThreeDO;
|
||||
if(_plugin.XmlFSType.Type == "PC Engine filesystem")
|
||||
dskType = MediaType.SuperCDROM2;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Wii filesystem")
|
||||
dskType = MediaType.WOD;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Wii filesystem") dskType = MediaType.WOD;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Gamecube filesystem")
|
||||
dskType = MediaType.GOD;
|
||||
}
|
||||
@@ -700,27 +688,18 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
|
||||
if(lstFs.Count > 0)
|
||||
xmlFileSysInfo[i].FileSystems = lstFs.ToArray();
|
||||
if(lstFs.Count > 0) xmlFileSysInfo[i].FileSystems = lstFs.ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dumpLog.WriteLine("Getting filesystem for whole device.");
|
||||
xmlFileSysInfo = new PartitionType[1];
|
||||
xmlFileSysInfo[0] = new PartitionType
|
||||
{
|
||||
EndSector = (int)(blocks - 1),
|
||||
StartSector = 0
|
||||
};
|
||||
xmlFileSysInfo[0] = new PartitionType {EndSector = (int)(blocks - 1), StartSector = 0};
|
||||
List<FileSystemType> lstFs = new List<FileSystemType>();
|
||||
|
||||
Partition wholePart = new Partition
|
||||
{
|
||||
Name = "Whole device",
|
||||
Length = blocks,
|
||||
Size = blocks * blockSize
|
||||
};
|
||||
Partition wholePart =
|
||||
new Partition {Name = "Whole device", Length = blocks, Size = blocks * blockSize};
|
||||
|
||||
foreach(Filesystem _plugin in plugins.PluginsList.Values)
|
||||
{
|
||||
@@ -733,14 +712,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Statistics.AddFilesystem(_plugin.XmlFSType.Type);
|
||||
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
|
||||
|
||||
if(_plugin.XmlFSType.Type == "Opera")
|
||||
dskType = MediaType.ThreeDO;
|
||||
if(_plugin.XmlFSType.Type == "PC Engine filesystem")
|
||||
dskType = MediaType.SuperCDROM2;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Wii filesystem")
|
||||
dskType = MediaType.WOD;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Gamecube filesystem")
|
||||
dskType = MediaType.GOD;
|
||||
if(_plugin.XmlFSType.Type == "Opera") dskType = MediaType.ThreeDO;
|
||||
if(_plugin.XmlFSType.Type == "PC Engine filesystem") dskType = MediaType.SuperCDROM2;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Wii filesystem") dskType = MediaType.WOD;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Gamecube filesystem") dskType = MediaType.GOD;
|
||||
}
|
||||
}
|
||||
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
|
||||
@@ -751,14 +726,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
|
||||
if(lstFs.Count > 0)
|
||||
xmlFileSysInfo[0].FileSystems = lstFs.ToArray();
|
||||
if(lstFs.Count > 0) xmlFileSysInfo[0].FileSystems = lstFs.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
if(alcohol != null && !dumpRaw)
|
||||
alcohol.SetMediaType(dskType);
|
||||
|
||||
if(alcohol != null && !dumpRaw) alcohol.SetMediaType(dskType);
|
||||
|
||||
if(opticalDisc)
|
||||
{
|
||||
sidecar.OpticalDisc[0].Checksums = dataChk.End().ToArray();
|
||||
@@ -771,30 +744,26 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
// TODO: Implement layers
|
||||
//sidecar.OpticalDisc[0].Layers = new LayersType();
|
||||
sidecar.OpticalDisc[0].Sessions = 1;
|
||||
sidecar.OpticalDisc[0].Tracks = new[] { 1 };
|
||||
sidecar.OpticalDisc[0].Tracks = new[] {1};
|
||||
sidecar.OpticalDisc[0].Track = new Schemas.TrackType[1];
|
||||
sidecar.OpticalDisc[0].Track[0] = new Schemas.TrackType
|
||||
{
|
||||
BytesPerSector = (int)blockSize,
|
||||
Checksums = sidecar.OpticalDisc[0].Checksums,
|
||||
EndSector = (long)(blocks - 1),
|
||||
Image = new ImageType
|
||||
{
|
||||
format = "BINARY",
|
||||
offset = 0,
|
||||
offsetSpecified = true,
|
||||
Value = sidecar.OpticalDisc[0].Image.Value
|
||||
},
|
||||
Sequence = new TrackSequenceType
|
||||
{
|
||||
Session = 1,
|
||||
TrackNumber = 1
|
||||
},
|
||||
Image =
|
||||
new ImageType
|
||||
{
|
||||
format = "BINARY",
|
||||
offset = 0,
|
||||
offsetSpecified = true,
|
||||
Value = sidecar.OpticalDisc[0].Image.Value
|
||||
},
|
||||
Sequence = new TrackSequenceType {Session = 1, TrackNumber = 1},
|
||||
Size = (long)(blocks * blockSize),
|
||||
StartSector = 0
|
||||
};
|
||||
if(xmlFileSysInfo != null)
|
||||
sidecar.OpticalDisc[0].Track[0].FileSystemInformation = xmlFileSysInfo;
|
||||
if(xmlFileSysInfo != null) sidecar.OpticalDisc[0].Track[0].FileSystemInformation = xmlFileSysInfo;
|
||||
switch(dskType)
|
||||
{
|
||||
case MediaType.DDCD:
|
||||
@@ -831,6 +800,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
sidecar.OpticalDisc[0].Track[0].TrackType1 = TrackTypeTrackType.bluray;
|
||||
break;
|
||||
}
|
||||
|
||||
sidecar.OpticalDisc[0].Dimensions = Metadata.Dimensions.DimensionsFromMediaType(dskType);
|
||||
Metadata.MediaType.MediaTypeToString(dskType, out string xmlDskTyp, out string xmlDskSubTyp);
|
||||
sidecar.OpticalDisc[0].DiscType = xmlDskTyp;
|
||||
@@ -851,14 +821,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
};
|
||||
if(!dev.IsRemovable || dev.IsUSB)
|
||||
{
|
||||
if(dev.Type == DeviceType.ATAPI)
|
||||
sidecar.BlockMedia[0].Interface = "ATAPI";
|
||||
else if(dev.IsUSB)
|
||||
sidecar.BlockMedia[0].Interface = "USB";
|
||||
else if(dev.IsFireWire)
|
||||
sidecar.BlockMedia[0].Interface = "FireWire";
|
||||
else
|
||||
sidecar.BlockMedia[0].Interface = "SCSI";
|
||||
if(dev.Type == DeviceType.ATAPI) sidecar.BlockMedia[0].Interface = "ATAPI";
|
||||
else if(dev.IsUSB) sidecar.BlockMedia[0].Interface = "USB";
|
||||
else if(dev.IsFireWire) sidecar.BlockMedia[0].Interface = "FireWire";
|
||||
else sidecar.BlockMedia[0].Interface = "SCSI";
|
||||
}
|
||||
sidecar.BlockMedia[0].LogicalBlocks = (long)blocks;
|
||||
sidecar.BlockMedia[0].PhysicalBlockSize = (int)physicalBlockSize;
|
||||
@@ -867,18 +833,18 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
sidecar.BlockMedia[0].Model = dev.Model;
|
||||
sidecar.BlockMedia[0].Serial = dev.Serial;
|
||||
sidecar.BlockMedia[0].Size = (long)(blocks * blockSize);
|
||||
if(xmlFileSysInfo != null)
|
||||
sidecar.BlockMedia[0].FileSystemInformation = xmlFileSysInfo;
|
||||
if(xmlFileSysInfo != null) sidecar.BlockMedia[0].FileSystemInformation = xmlFileSysInfo;
|
||||
|
||||
if(dev.IsRemovable)
|
||||
sidecar.BlockMedia[0].DumpHardwareArray = resume.Tries.ToArray();
|
||||
if(dev.IsRemovable) sidecar.BlockMedia[0].DumpHardwareArray = resume.Tries.ToArray();
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
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
|
||||
DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1048576) / (totalDuration / 1000));
|
||||
DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1048576) / (totalDuration / 1000));
|
||||
#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created
|
||||
DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed);
|
||||
DicConsole.WriteLine("Slowest speed burst: {0:F3} MiB/sec.", minSpeed);
|
||||
@@ -889,17 +855,16 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
DicConsole.WriteLine("Writing metadata sidecar");
|
||||
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml",
|
||||
FileMode.Create);
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
|
||||
|
||||
System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
System.Xml.Serialization.XmlSerializer xmlSer =
|
||||
new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
xmlSer.Serialize(xmlFs, sidecar);
|
||||
xmlFs.Close();
|
||||
if(alcohol != null && !dumpRaw)
|
||||
alcohol.Close();
|
||||
if(alcohol != null && !dumpRaw) alcohol.Close();
|
||||
}
|
||||
|
||||
Statistics.AddMedia(dskType, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
public class SCSI
|
||||
{
|
||||
// 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, ref DumpLog dumpLog, bool dumpLeadIn, Encoding encoding)
|
||||
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, bool dumpLeadIn, Encoding encoding)
|
||||
{
|
||||
byte[] senseBuf = null;
|
||||
bool sense = false;
|
||||
@@ -60,14 +62,14 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Decoders.SCSI.FixedSense? decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf);
|
||||
if(decSense.HasValue)
|
||||
{
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
|
||||
|
||||
// Just retry, for 5 times
|
||||
if(decSense.Value.ASC == 0x29)
|
||||
{
|
||||
resets++;
|
||||
if(resets < 5)
|
||||
goto deviceGotReset;
|
||||
if(resets < 5) goto deviceGotReset;
|
||||
}
|
||||
|
||||
if(decSense.Value.ASC == 0x3A)
|
||||
@@ -78,12 +80,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.WriteLine("\rWaiting for drive to become ready");
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out duration);
|
||||
if(!sense)
|
||||
break;
|
||||
if(!sense) break;
|
||||
|
||||
decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf);
|
||||
if(decSense.HasValue)
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
|
||||
leftRetries--;
|
||||
}
|
||||
|
||||
@@ -101,18 +103,19 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.WriteLine("\rWaiting for drive to become ready");
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out duration);
|
||||
if(!sense)
|
||||
break;
|
||||
if(!sense) break;
|
||||
|
||||
decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf);
|
||||
if(decSense.HasValue)
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
|
||||
leftRetries--;
|
||||
}
|
||||
|
||||
if(sense)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}",
|
||||
Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -137,24 +140,26 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.WriteLine("\rWaiting for drive to become ready");
|
||||
System.Threading.Thread.Sleep(2000);
|
||||
sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out duration);
|
||||
if(!sense)
|
||||
break;
|
||||
if(!sense) break;
|
||||
|
||||
decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf);
|
||||
if(decSense.HasValue)
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
|
||||
leftRetries--;
|
||||
}
|
||||
|
||||
if(sense)
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}",
|
||||
Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}",
|
||||
Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -170,8 +175,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.SequentialAccess)
|
||||
{
|
||||
if(dumpRaw)
|
||||
throw new ArgumentException("Tapes cannot be dumped raw.");
|
||||
if(dumpRaw) throw new ArgumentException("Tapes cannot be dumped raw.");
|
||||
|
||||
SSC.Dump(dev, outputPrefix, devicePath, ref sidecar, ref resume, ref dumpLog);
|
||||
return;
|
||||
@@ -179,11 +183,13 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice)
|
||||
{
|
||||
MMC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, separateSubchannel, ref resume, ref dumpLog, dumpLeadIn, encoding);
|
||||
MMC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError,
|
||||
ref sidecar, ref dskType, separateSubchannel, ref resume, ref dumpLog, dumpLeadIn, encoding);
|
||||
return;
|
||||
}
|
||||
|
||||
SBC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, false, ref resume, ref dumpLog, encoding);
|
||||
SBC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar,
|
||||
ref dskType, false, ref resume, ref dumpLog, encoding);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
internal static class SSC
|
||||
{
|
||||
internal static void Dump(Device dev, string outputPrefix, string devicePath, ref CICMMetadataType sidecar, ref Metadata.Resume resume, ref DumpLog dumpLog)
|
||||
internal static void Dump(Device dev, string outputPrefix, string devicePath, ref CICMMetadataType sidecar,
|
||||
ref Metadata.Resume resume, ref DumpLog dumpLog)
|
||||
{
|
||||
Decoders.SCSI.FixedSense? fxSense;
|
||||
bool aborted;
|
||||
@@ -69,14 +70,16 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(fxSense.HasValue && fxSense.Value.SenseKey != Decoders.SCSI.SenseKeys.NoSense)
|
||||
{
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}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("{0}", strSense);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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...");
|
||||
@@ -91,19 +94,22 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dev.RequestSense(out senseBuf, dev.Timeout, out duration);
|
||||
fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense);
|
||||
}
|
||||
while(fxSense.HasValue && fxSense.Value.ASC == 0x00 && (fxSense.Value.ASCQ == 0x1A || fxSense.Value.ASCQ != 0x04));
|
||||
while(fxSense.HasValue && fxSense.Value.ASC == 0x00 &&
|
||||
(fxSense.Value.ASCQ == 0x1A || fxSense.Value.ASCQ != 0x04));
|
||||
|
||||
dev.RequestSense(out senseBuf, dev.Timeout, out duration);
|
||||
fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense);
|
||||
|
||||
// And yet, did not rewind!
|
||||
if(fxSense.HasValue && ((fxSense.Value.ASC == 0x00 && fxSense.Value.ASCQ != 0x04) || fxSense.Value.ASC != 0x00))
|
||||
if(fxSense.HasValue && ((fxSense.Value.ASC == 0x00 && fxSense.Value.ASCQ != 0x04) ||
|
||||
fxSense.Value.ASC != 0x00))
|
||||
{
|
||||
DicConsole.WriteLine();
|
||||
DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey,
|
||||
fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -111,7 +117,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
// Check position
|
||||
sense = dev.ReadPosition(out byte[] cmdBuf, out senseBuf, SscPositionForms.Short, dev.Timeout, out duration);
|
||||
sense = dev.ReadPosition(out byte[] cmdBuf, out senseBuf, SscPositionForms.Short, dev.Timeout,
|
||||
out duration);
|
||||
|
||||
if(sense)
|
||||
{
|
||||
@@ -119,12 +126,15 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
// Anyway, <=SCSI-1 tapes do not support partitions
|
||||
fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense);
|
||||
|
||||
if(fxSense.HasValue && ((fxSense.Value.ASC == 0x20 && fxSense.Value.ASCQ != 0x00) || fxSense.Value.ASC != 0x20 && fxSense.Value.SenseKey != Decoders.SCSI.SenseKeys.IllegalRequest))
|
||||
if(fxSense.HasValue && ((fxSense.Value.ASC == 0x20 && fxSense.Value.ASCQ != 0x00) ||
|
||||
fxSense.Value.ASC != 0x20 && fxSense.Value.SenseKey !=
|
||||
Decoders.SCSI.SenseKeys.IllegalRequest))
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Could not get position. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpLog.WriteLine("Could not get position. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey,
|
||||
fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -143,7 +153,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,27 +167,32 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dev.RequestSense(out senseBuf, dev.Timeout, out duration);
|
||||
fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense);
|
||||
}
|
||||
while(fxSense.HasValue && fxSense.Value.ASC == 0x00 && (fxSense.Value.ASCQ == 0x1A || fxSense.Value.ASCQ == 0x19));
|
||||
while(fxSense.HasValue && fxSense.Value.ASC == 0x00 &&
|
||||
(fxSense.Value.ASCQ == 0x1A || fxSense.Value.ASCQ == 0x19));
|
||||
|
||||
// And yet, did not rewind!
|
||||
if(fxSense.HasValue && ((fxSense.Value.ASC == 0x00 && fxSense.Value.ASCQ != 0x04) || fxSense.Value.ASC != 0x00))
|
||||
if(fxSense.HasValue && ((fxSense.Value.ASC == 0x00 && fxSense.Value.ASCQ != 0x04) ||
|
||||
fxSense.Value.ASC != 0x00))
|
||||
{
|
||||
DicConsole.WriteLine();
|
||||
DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
|
||||
sense = dev.ReadPosition(out cmdBuf, out senseBuf, SscPositionForms.Short, dev.Timeout, out duration);
|
||||
sense = dev.ReadPosition(out cmdBuf, out senseBuf, SscPositionForms.Short, dev.Timeout,
|
||||
out duration);
|
||||
if(sense)
|
||||
{
|
||||
fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense);
|
||||
DicConsole.ErrorWriteLine("Drive could not rewind, please correct. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpLog.WriteLine("Drive could not rewind, please correct. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -193,18 +209,17 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
sidecar.BlockMedia = new BlockMediaType[1];
|
||||
sidecar.BlockMedia[0] = new BlockMediaType
|
||||
{
|
||||
SCSI = new SCSIType()
|
||||
};
|
||||
sidecar.BlockMedia[0] = new BlockMediaType {SCSI = new SCSIType()};
|
||||
byte scsiMediumTypeTape = 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)
|
||||
{
|
||||
sense = dev.ModeSense10(out cmdBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration);
|
||||
sense = dev.ModeSense10(out cmdBuf, out senseBuf, false, true, ScsiModeSensePageControl.Current, 0x3F,
|
||||
0x00, 5, out duration);
|
||||
}
|
||||
|
||||
Decoders.SCSI.Modes.DecodedMode? decMode = null;
|
||||
@@ -225,11 +240,12 @@ 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)
|
||||
sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out duration);
|
||||
if(sense || dev.Error)
|
||||
sense = dev.ModeSense(out cmdBuf, out senseBuf, 5, out duration);
|
||||
sense = dev.ModeSense6(out cmdBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F, 0x00, 5,
|
||||
out duration);
|
||||
if(sense || dev.Error) sense = dev.ModeSense(out cmdBuf, out senseBuf, 5, out duration);
|
||||
|
||||
if(!sense && !dev.Error)
|
||||
{
|
||||
@@ -255,11 +271,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
blockSize = decMode.Value.Header.BlockDescriptors[0].BlockLength;
|
||||
dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize);
|
||||
}
|
||||
else
|
||||
blockSize = 1;
|
||||
else blockSize = 1;
|
||||
|
||||
if(dskType == MediaType.Unknown)
|
||||
dskType = MediaTypeFromSCSI.Get((byte)dev.SCSIType, dev.Manufacturer, dev.Model, scsiMediumTypeTape, scsiDensityCodeTape, blocks, blockSize);
|
||||
dskType = MediaTypeFromSCSI.Get((byte)dev.SCSIType, dev.Manufacturer, dev.Model, scsiMediumTypeTape,
|
||||
scsiDensityCodeTape, blocks, blockSize);
|
||||
|
||||
DicConsole.WriteLine("Media identified as {0}", dskType);
|
||||
|
||||
@@ -280,7 +296,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
bool fixedLen = false;
|
||||
uint transferLen = blockSize;
|
||||
|
||||
sense = dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize, dev.Timeout, out duration);
|
||||
sense = dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize, dev.Timeout,
|
||||
out duration);
|
||||
if(sense)
|
||||
{
|
||||
fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense);
|
||||
@@ -298,21 +315,24 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Drive could not return back. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpLog.WriteLine("Drive could not return back. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fixedLen = true;
|
||||
transferLen = 1;
|
||||
sense = dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize, dev.Timeout, out duration);
|
||||
sense = dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize,
|
||||
dev.Timeout, out duration);
|
||||
if(sense)
|
||||
{
|
||||
DicConsole.WriteLine();
|
||||
DicConsole.ErrorWriteLine("Drive could not read. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpLog.WriteLine("Drive could not read. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -322,7 +342,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Drive could not read. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpLog.WriteLine("Drive could not read. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -345,7 +366,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Drive could not return back. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpLog.WriteLine("Drive could not return back. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey,
|
||||
fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -393,10 +415,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
partitionChk = new Checksum();
|
||||
|
||||
aborted = false;
|
||||
System.Console.CancelKeyPress += (sender, e) =>
|
||||
{
|
||||
e.Cancel = aborted = true;
|
||||
};
|
||||
System.Console.CancelKeyPress += (sender, e) => { e.Cancel = aborted = true; };
|
||||
|
||||
while(currentPartition < totalPartitions)
|
||||
{
|
||||
@@ -461,23 +480,24 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
#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;
|
||||
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 block {0} ({1:F3} MiB/sec.)", currentBlock, currentSpeed);
|
||||
|
||||
sense = dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize, dev.Timeout, out duration);
|
||||
sense = dev.Read6(out cmdBuf, out senseBuf, false, fixedLen, transferLen, blockSize, dev.Timeout,
|
||||
out duration);
|
||||
totalDuration += duration;
|
||||
|
||||
if(sense)
|
||||
{
|
||||
fxSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf, out strSense);
|
||||
if(fxSense.Value.ASC == 0x00 && fxSense.Value.ASCQ == 0x00 && fxSense.Value.ILI && fxSense.Value.InformationValid)
|
||||
if(fxSense.Value.ASC == 0x00 && fxSense.Value.ASCQ == 0x00 && fxSense.Value.ILI &&
|
||||
fxSense.Value.InformationValid)
|
||||
{
|
||||
blockSize = (uint)((int)blockSize - BitConverter.ToInt32(BitConverter.GetBytes(fxSense.Value.Information), 0));
|
||||
blockSize = (uint)((int)blockSize -
|
||||
BitConverter.ToInt32(BitConverter.GetBytes(fxSense.Value.Information), 0));
|
||||
currentTapeFile.BlockSize = blockSize;
|
||||
|
||||
DicConsole.WriteLine();
|
||||
@@ -495,7 +515,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("{0}", strSense);
|
||||
dumpFile.Close();
|
||||
dumpLog.WriteLine("Drive could not go back one block. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
|
||||
fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -514,7 +535,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
|
||||
// For sure this is an end-of-tape/partition
|
||||
if(fxSense.Value.ASC == 0x00 && (fxSense.Value.ASCQ == 0x02 || fxSense.Value.ASCQ == 0x05 || fxSense.Value.EOM))
|
||||
if(fxSense.Value.ASC == 0x00 &&
|
||||
(fxSense.Value.ASCQ == 0x02 || fxSense.Value.ASCQ == 0x05 || fxSense.Value.EOM))
|
||||
{
|
||||
// TODO: Detect end of partition
|
||||
endOfMedia = true;
|
||||
@@ -529,7 +551,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
continue;
|
||||
}
|
||||
|
||||
if((fxSense.Value.SenseKey == Decoders.SCSI.SenseKeys.NoSense || fxSense.Value.SenseKey == Decoders.SCSI.SenseKeys.RecoveredError) &&
|
||||
if((fxSense.Value.SenseKey == Decoders.SCSI.SenseKeys.NoSense ||
|
||||
fxSense.Value.SenseKey == Decoders.SCSI.SenseKeys.RecoveredError) &&
|
||||
(fxSense.Value.ASCQ == 0x02 || fxSense.Value.ASCQ == 0x05 || fxSense.Value.EOM))
|
||||
{
|
||||
// TODO: Detect end of partition
|
||||
@@ -538,7 +561,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
continue;
|
||||
}
|
||||
|
||||
if((fxSense.Value.SenseKey == Decoders.SCSI.SenseKeys.NoSense || fxSense.Value.SenseKey == Decoders.SCSI.SenseKeys.RecoveredError) &&
|
||||
if((fxSense.Value.SenseKey == Decoders.SCSI.SenseKeys.NoSense ||
|
||||
fxSense.Value.SenseKey == Decoders.SCSI.SenseKeys.RecoveredError) &&
|
||||
(fxSense.Value.ASCQ == 0x01 || fxSense.Value.Filemark))
|
||||
{
|
||||
currentTapeFile.Checksums = fileChk.End().ToArray();
|
||||
@@ -574,7 +598,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Drive could not read block. Sense follows...");
|
||||
DicConsole.ErrorWriteLine("{0} {1}", fxSense.Value.SenseKey, strSense);
|
||||
dumpLog.WriteLine("Drive could not read block. Sense follows...");
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey, fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h", fxSense.Value.SenseKey,
|
||||
fxSense.Value.ASC, fxSense.Value.ASCQ);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -602,14 +627,19 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.WriteLine();
|
||||
end = DateTime.UtcNow;
|
||||
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));
|
||||
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
|
||||
DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1048576) / (totalDuration / 1000));
|
||||
DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1048576) / (totalDuration / 1000));
|
||||
#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created
|
||||
DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed);
|
||||
DicConsole.WriteLine("Slowest speed burst: {0:F3} MiB/sec.", minSpeed);
|
||||
@@ -628,15 +658,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
sidecar.BlockMedia[0].LogicalBlocks = (long)blocks;
|
||||
sidecar.BlockMedia[0].Size = (long)(currentSize);
|
||||
sidecar.BlockMedia[0].DumpHardwareArray = new DumpHardwareType[1];
|
||||
sidecar.BlockMedia[0].DumpHardwareArray[0] = new DumpHardwareType
|
||||
{
|
||||
Extents = new ExtentType[1]
|
||||
};
|
||||
sidecar.BlockMedia[0].DumpHardwareArray[0].Extents[0] = new ExtentType
|
||||
{
|
||||
Start = 0,
|
||||
End = blocks - 1
|
||||
};
|
||||
sidecar.BlockMedia[0].DumpHardwareArray[0] = new DumpHardwareType {Extents = new ExtentType[1]};
|
||||
sidecar.BlockMedia[0].DumpHardwareArray[0].Extents[0] = new ExtentType {Start = 0, End = blocks - 1};
|
||||
sidecar.BlockMedia[0].DumpHardwareArray[0].Manufacturer = dev.Manufacturer;
|
||||
sidecar.BlockMedia[0].DumpHardwareArray[0].Model = dev.Model;
|
||||
sidecar.BlockMedia[0].DumpHardwareArray[0].Revision = dev.Revision;
|
||||
@@ -648,10 +671,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
DicConsole.WriteLine("Writing metadata sidecar");
|
||||
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml",
|
||||
FileMode.Create);
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
|
||||
|
||||
System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
System.Xml.Serialization.XmlSerializer xmlSer =
|
||||
new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
xmlSer.Serialize(xmlFs, sidecar);
|
||||
xmlFs.Close();
|
||||
}
|
||||
@@ -661,4 +684,4 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
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, ref DumpLog dumpLog, Encoding encoding)
|
||||
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, Encoding encoding)
|
||||
{
|
||||
bool aborted;
|
||||
MHDDLog mhddLog;
|
||||
@@ -59,8 +61,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Raw dumping is not supported in MultiMediaCard or SecureDigital devices.");
|
||||
|
||||
if(force)
|
||||
DicConsole.ErrorWriteLine("Continuing...");
|
||||
if(force) DicConsole.ErrorWriteLine("Continuing...");
|
||||
else
|
||||
{
|
||||
DicConsole.ErrorWriteLine("Aborting...");
|
||||
@@ -73,10 +74,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
uint timeout = 5;
|
||||
double duration;
|
||||
|
||||
CICMMetadataType sidecar = new CICMMetadataType()
|
||||
{
|
||||
BlockMedia = new BlockMediaType[] { new BlockMediaType() }
|
||||
};
|
||||
CICMMetadataType sidecar =
|
||||
new CICMMetadataType() {BlockMedia = new BlockMediaType[] {new BlockMediaType()}};
|
||||
|
||||
uint blocksToRead = 128;
|
||||
uint blockSize = 512;
|
||||
@@ -103,15 +102,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
blocksToRead = ecsdDecoded.OptimalReadSize;
|
||||
blocks = ecsdDecoded.SectorCount;
|
||||
blockSize = (uint)(ecsdDecoded.SectorSize == 1 ? 4096 : 512);
|
||||
if(ecsdDecoded.NativeSectorSize == 0)
|
||||
physicalBlockSize = 512;
|
||||
else if(ecsdDecoded.NativeSectorSize == 1)
|
||||
physicalBlockSize = 4096;
|
||||
if(ecsdDecoded.NativeSectorSize == 0) physicalBlockSize = 512;
|
||||
else if(ecsdDecoded.NativeSectorSize == 1) physicalBlockSize = 4096;
|
||||
// Supposing it's high-capacity MMC if it has Extended CSD...
|
||||
byteAddressed = false;
|
||||
}
|
||||
else
|
||||
ecsd = null;
|
||||
else ecsd = null;
|
||||
|
||||
dumpLog.WriteLine("Reading CSD");
|
||||
sense = dev.ReadCSD(out csd, out response, timeout, out duration);
|
||||
@@ -124,13 +120,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
csd = null;
|
||||
else csd = null;
|
||||
|
||||
dumpLog.WriteLine("Reading OCR");
|
||||
sense = dev.ReadOCR(out ocr, out response, timeout, out duration);
|
||||
if(sense)
|
||||
ocr = null;
|
||||
if(sense) ocr = null;
|
||||
|
||||
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
|
||||
}
|
||||
@@ -143,31 +137,29 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
if(!sense)
|
||||
{
|
||||
csdDecoded = Decoders.SecureDigital.Decoders.DecodeCSD(csd);
|
||||
blocks = (ulong)(csdDecoded.Structure == 0 ? (csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2) : (csdDecoded.Size + 1) * 1024);
|
||||
blocks = (ulong)(csdDecoded.Structure == 0
|
||||
? (csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2)
|
||||
: (csdDecoded.Size + 1) * 1024);
|
||||
blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength);
|
||||
// Structure >=1 for SDHC/SDXC, so that's block addressed
|
||||
byteAddressed = csdDecoded.Structure == 0;
|
||||
}
|
||||
else
|
||||
csd = null;
|
||||
else csd = null;
|
||||
|
||||
dumpLog.WriteLine("Reading OCR");
|
||||
sense = dev.ReadSDOCR(out ocr, out response, timeout, out duration);
|
||||
if(sense)
|
||||
ocr = null;
|
||||
if(sense) ocr = null;
|
||||
|
||||
dumpLog.WriteLine("Reading SCR");
|
||||
sense = dev.ReadSCR(out scr, out response, timeout, out duration);
|
||||
if(sense)
|
||||
scr = null;
|
||||
if(sense) scr = null;
|
||||
|
||||
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
|
||||
}
|
||||
|
||||
dumpLog.WriteLine("Reading CID");
|
||||
sense = dev.ReadCID(out cid, out response, timeout, out duration);
|
||||
if(sense)
|
||||
cid = null;
|
||||
if(sense) cid = null;
|
||||
|
||||
DumpType cidDump = null;
|
||||
DumpType csdDump = null;
|
||||
@@ -182,7 +174,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Checksums = Checksum.GetChecksums(cid).ToArray()
|
||||
};
|
||||
DataFile.WriteTo("MMC/SecureDigital Dump", cidDump.Image, cid);
|
||||
};
|
||||
}
|
||||
;
|
||||
if(csd != null)
|
||||
{
|
||||
csdDump = new DumpType
|
||||
@@ -192,7 +185,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Checksums = Checksum.GetChecksums(csd).ToArray()
|
||||
};
|
||||
DataFile.WriteTo("MMC/SecureDigital Dump", csdDump.Image, csd);
|
||||
};
|
||||
}
|
||||
;
|
||||
if(ecsd != null)
|
||||
{
|
||||
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType
|
||||
@@ -201,8 +195,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Size = ecsd.Length,
|
||||
Checksums = Checksum.GetChecksums(ecsd).ToArray()
|
||||
};
|
||||
DataFile.WriteTo("MMC/SecureDigital Dump", sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD.Image, ecsd);
|
||||
};
|
||||
DataFile.WriteTo("MMC/SecureDigital Dump", sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD.Image,
|
||||
ecsd);
|
||||
}
|
||||
;
|
||||
if(ocr != null)
|
||||
{
|
||||
ocrDump = new DumpType
|
||||
@@ -212,7 +208,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Checksums = Checksum.GetChecksums(ocr).ToArray()
|
||||
};
|
||||
DataFile.WriteTo("MMC/SecureDigital Dump", ocrDump.Image, ocr);
|
||||
};
|
||||
}
|
||||
;
|
||||
if(scr != null)
|
||||
{
|
||||
sidecar.BlockMedia[0].SecureDigital.SCR = new DumpType
|
||||
@@ -222,7 +219,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Checksums = Checksum.GetChecksums(scr).ToArray()
|
||||
};
|
||||
DataFile.WriteTo("MMC/SecureDigital Dump", sidecar.BlockMedia[0].SecureDigital.SCR.Image, scr);
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
if(dev.Type == DeviceType.MMC)
|
||||
{
|
||||
@@ -247,10 +245,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Checksum dataChk;
|
||||
|
||||
aborted = false;
|
||||
System.Console.CancelKeyPress += (sender, e) =>
|
||||
{
|
||||
e.Cancel = aborted = true;
|
||||
};
|
||||
System.Console.CancelKeyPress += (sender, e) => { e.Cancel = aborted = true; };
|
||||
|
||||
DataFile dumpFile;
|
||||
|
||||
@@ -260,6 +255,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Unable to get device size.");
|
||||
return;
|
||||
}
|
||||
|
||||
dumpLog.WriteLine("Device reports {0} blocks.", blocks);
|
||||
|
||||
byte[] cmdBuf;
|
||||
@@ -267,13 +263,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
while(true)
|
||||
{
|
||||
error = dev.Read(out cmdBuf, out response, 0, blockSize, blocksToRead, byteAddressed, timeout, out duration);
|
||||
error = dev.Read(out cmdBuf, out response, 0, blockSize, blocksToRead, byteAddressed, timeout,
|
||||
out duration);
|
||||
|
||||
if(error)
|
||||
blocksToRead /= 2;
|
||||
if(error) blocksToRead /= 2;
|
||||
|
||||
if(!error || blocksToRead == 1)
|
||||
break;
|
||||
if(!error || blocksToRead == 1) break;
|
||||
}
|
||||
|
||||
if(error)
|
||||
@@ -288,7 +283,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
DumpHardwareType currentTry = 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)
|
||||
throw new Exception("Could not process resume file, not continuing...");
|
||||
|
||||
@@ -298,8 +294,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
ibgLog = new IBGLog(outputPrefix + ".ibg", currentProfile);
|
||||
dumpFile = new DataFile(outputPrefix + ".bin");
|
||||
dumpFile.Seek(resume.NextBlock, blockSize);
|
||||
if(resume.NextBlock > 0)
|
||||
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
|
||||
start = DateTime.UtcNow;
|
||||
for(ulong i = resume.NextBlock; i < blocks; i += blocksToRead)
|
||||
@@ -311,19 +306,17 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if((blocks - i) < blocksToRead)
|
||||
blocksToRead = (byte)(blocks - i);
|
||||
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;
|
||||
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);
|
||||
error = dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, byteAddressed, timeout,
|
||||
out duration);
|
||||
|
||||
if(!error)
|
||||
{
|
||||
@@ -334,12 +327,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
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);
|
||||
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]);
|
||||
@@ -352,24 +343,26 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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);
|
||||
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));
|
||||
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:
|
||||
repeatRetryLba:
|
||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||
foreach(ulong badSector in tmpArray)
|
||||
{
|
||||
@@ -380,9 +373,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "");
|
||||
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;
|
||||
|
||||
@@ -393,8 +389,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dumpFile.WriteAt(cmdBuf, badSector, blockSize);
|
||||
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
|
||||
}
|
||||
else if(runningPersistent)
|
||||
dumpFile.WriteAt(cmdBuf, badSector, blockSize);
|
||||
else if(runningPersistent) dumpFile.WriteAt(cmdBuf, badSector, blockSize);
|
||||
}
|
||||
|
||||
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
|
||||
@@ -425,8 +420,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if((blocks - i) < blocksToRead)
|
||||
blocksToRead = (byte)(blocks - i);
|
||||
if((blocks - i) < blocksToRead) blocksToRead = (byte)(blocks - i);
|
||||
|
||||
DicConsole.Write("\rChecksumming sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed);
|
||||
|
||||
@@ -441,11 +435,13 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (chkDuration / (double)1000);
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
dumpFile.Close();
|
||||
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));
|
||||
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
|
||||
|
||||
PluginBase plugins = new PluginBase();
|
||||
plugins.RegisterAllPlugins(encoding);
|
||||
@@ -463,15 +459,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
_imageFormat = ImageFormat.Detect(inputFilter);
|
||||
PartitionType[] xmlFileSysInfo = null;
|
||||
|
||||
try
|
||||
{
|
||||
if(!_imageFormat.OpenImage(inputFilter))
|
||||
_imageFormat = null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_imageFormat = null;
|
||||
}
|
||||
try { if(!_imageFormat.OpenImage(inputFilter)) _imageFormat = null; }
|
||||
catch { _imageFormat = null; }
|
||||
|
||||
if(_imageFormat != null)
|
||||
{
|
||||
@@ -496,7 +485,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
};
|
||||
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);
|
||||
i, partitions[i].Start, partitions[i].End, partitions[i].Type,
|
||||
partitions[i].Scheme);
|
||||
|
||||
foreach(Filesystem _plugin in plugins.PluginsList.Values)
|
||||
{
|
||||
@@ -518,8 +508,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
|
||||
if(lstFs.Count > 0)
|
||||
xmlFileSysInfo[i].FileSystems = lstFs.ToArray();
|
||||
if(lstFs.Count > 0) xmlFileSysInfo[i].FileSystems = lstFs.ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -527,19 +516,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dumpLog.WriteLine("Getting filesystem for whole device.");
|
||||
|
||||
xmlFileSysInfo = new PartitionType[1];
|
||||
xmlFileSysInfo[0] = new PartitionType
|
||||
{
|
||||
EndSector = (int)(blocks - 1),
|
||||
StartSector = 0
|
||||
};
|
||||
xmlFileSysInfo[0] = new PartitionType {EndSector = (int)(blocks - 1), StartSector = 0};
|
||||
List<FileSystemType> lstFs = new List<FileSystemType>();
|
||||
|
||||
Partition wholePart = new Partition
|
||||
{
|
||||
Name = "Whole device",
|
||||
Length = blocks,
|
||||
Size = blocks * blockSize
|
||||
};
|
||||
Partition wholePart =
|
||||
new Partition {Name = "Whole device", Length = blocks, Size = blocks * blockSize};
|
||||
|
||||
foreach(Filesystem _plugin in plugins.PluginsList.Values)
|
||||
{
|
||||
@@ -561,8 +542,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
|
||||
if(lstFs.Count > 0)
|
||||
xmlFileSysInfo[0].FileSystems = lstFs.ToArray();
|
||||
if(lstFs.Count > 0) xmlFileSysInfo[0].FileSystems = lstFs.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,10 +566,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
format = "Raw disk image (sector by sector copy)",
|
||||
Value = outputPrefix + ".bin"
|
||||
};
|
||||
if(dev.Type == DeviceType.MMC)
|
||||
sidecar.BlockMedia[0].Interface = "MultiMediaCard";
|
||||
else if(dev.Type == DeviceType.SecureDigital)
|
||||
sidecar.BlockMedia[0].Interface = "SecureDigital";
|
||||
if(dev.Type == DeviceType.MMC) sidecar.BlockMedia[0].Interface = "MultiMediaCard";
|
||||
else if(dev.Type == DeviceType.SecureDigital) sidecar.BlockMedia[0].Interface = "SecureDigital";
|
||||
sidecar.BlockMedia[0].LogicalBlocks = (long)blocks;
|
||||
sidecar.BlockMedia[0].PhysicalBlockSize = physicalBlockSize > 0 ? physicalBlockSize : (int)blockSize;
|
||||
sidecar.BlockMedia[0].LogicalBlockSize = (int)blockSize;
|
||||
@@ -597,36 +575,34 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
sidecar.BlockMedia[0].Model = dev.Model;
|
||||
sidecar.BlockMedia[0].Serial = dev.Serial;
|
||||
sidecar.BlockMedia[0].Size = (long)(blocks * blockSize);
|
||||
if(xmlFileSysInfo != null)
|
||||
sidecar.BlockMedia[0].FileSystemInformation = xmlFileSysInfo;
|
||||
if(xmlFileSysInfo != null) sidecar.BlockMedia[0].FileSystemInformation = xmlFileSysInfo;
|
||||
|
||||
DicConsole.WriteLine();
|
||||
|
||||
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("Avegare speed: {0:F3} MiB/sec.", (((double)blockSize * (double)(blocks + 1)) / 1048576) / (totalDuration / 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("Avegare speed: {0:F3} MiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1048576) / (totalDuration / 1000));
|
||||
DicConsole.WriteLine("Fastest speed burst: {0:F3} MiB/sec.", maxSpeed);
|
||||
DicConsole.WriteLine("Slowest speed burst: {0:F3} MiB/sec.", minSpeed);
|
||||
DicConsole.WriteLine("{0} sectors could not be read.", resume.BadBlocks.Count);
|
||||
if(resume.BadBlocks.Count > 0)
|
||||
resume.BadBlocks.Sort();
|
||||
if(resume.BadBlocks.Count > 0) resume.BadBlocks.Sort();
|
||||
DicConsole.WriteLine();
|
||||
|
||||
if(!aborted)
|
||||
{
|
||||
DicConsole.WriteLine("Writing metadata sidecar");
|
||||
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml",
|
||||
FileMode.Create);
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
|
||||
|
||||
System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
System.Xml.Serialization.XmlSerializer xmlSer =
|
||||
new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
xmlSer.Serialize(xmlFs, sidecar);
|
||||
xmlFs.Close();
|
||||
}
|
||||
|
||||
if(dev.Type == DeviceType.MMC)
|
||||
Statistics.AddMedia(MediaType.MMC, true);
|
||||
else if(dev.Type == DeviceType.SecureDigital)
|
||||
Statistics.AddMedia(MediaType.SecureDigital, true);
|
||||
if(dev.Type == DeviceType.MMC) Statistics.AddMedia(MediaType.MMC, true);
|
||||
else if(dev.Type == DeviceType.SecureDigital) Statistics.AddMedia(MediaType.SecureDigital, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
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, ref DumpLog dumpLog, Encoding encoding)
|
||||
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,
|
||||
Encoding encoding)
|
||||
{
|
||||
MHDDLog mhddLog;
|
||||
IBGLog ibgLog;
|
||||
@@ -68,10 +71,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Checksum dataChk;
|
||||
DataFile dumpFile = null;
|
||||
bool aborted = false;
|
||||
System.Console.CancelKeyPress += (sender, e) =>
|
||||
{
|
||||
e.Cancel = aborted = true;
|
||||
};
|
||||
System.Console.CancelKeyPress += (sender, e) => { e.Cancel = aborted = true; };
|
||||
|
||||
dumpLog.WriteLine("Reading Xbox Security Sector.");
|
||||
sense = dev.KreonExtractSS(out byte[] ssBuf, out byte[] senseBuf, dev.Timeout, out double duration);
|
||||
@@ -96,19 +96,19 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
sidecar.OpticalDisc[0].Xbox = new XboxType()
|
||||
{
|
||||
SecuritySectors = new XboxSecuritySectorsType[]
|
||||
{
|
||||
new XboxSecuritySectorsType()
|
||||
{
|
||||
RequestNumber = 0,
|
||||
RequestVersion = 1,
|
||||
SecuritySectors = new DumpType()
|
||||
{
|
||||
Image = outputPrefix + ".ss.bin",
|
||||
Size = tmpBuf.Length,
|
||||
Checksums = Checksum.GetChecksums(tmpBuf).ToArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
new XboxSecuritySectorsType()
|
||||
{
|
||||
RequestNumber = 0,
|
||||
RequestVersion = 1,
|
||||
SecuritySectors = new DumpType()
|
||||
{
|
||||
Image = outputPrefix + ".ss.bin",
|
||||
Size = tmpBuf.Length,
|
||||
Checksums = Checksum.GetChecksums(tmpBuf).ToArray()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
DataFile.WriteTo("SCSI Dump", outputPrefix + ".ss.bin", ssBuf);
|
||||
|
||||
@@ -124,6 +124,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Cannot lock drive, not continuing.");
|
||||
return;
|
||||
}
|
||||
|
||||
dumpLog.WriteLine("Getting video partition size.");
|
||||
sense = dev.ReadCapacity(out byte[] readBuffer, out senseBuf, dev.Timeout, out duration);
|
||||
if(sense)
|
||||
@@ -132,15 +133,18 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Cannot get disc capacity.");
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
dumpLog.WriteLine("Cannot get PFI.");
|
||||
DicConsole.ErrorWriteLine("Cannot get PFI.");
|
||||
return;
|
||||
}
|
||||
|
||||
tmpBuf = new byte[readBuffer.Length - 4];
|
||||
Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4);
|
||||
sidecar.OpticalDisc[0].PFI = new DumpType
|
||||
@@ -151,16 +155,19 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
};
|
||||
DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].PFI.Image, tmpBuf, "Locked PFI", true);
|
||||
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;
|
||||
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)
|
||||
{
|
||||
dumpLog.WriteLine("Cannot get DMI.");
|
||||
DicConsole.ErrorWriteLine("Cannot get DMI.");
|
||||
return;
|
||||
}
|
||||
|
||||
tmpBuf = new byte[readBuffer.Length - 4];
|
||||
Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4);
|
||||
sidecar.OpticalDisc[0].DMI = new DumpType
|
||||
@@ -181,6 +188,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing.");
|
||||
return;
|
||||
}
|
||||
|
||||
dumpLog.WriteLine("Getting game partition size.");
|
||||
sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out duration);
|
||||
if(sense)
|
||||
@@ -189,7 +197,9 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Cannot get disc capacity.");
|
||||
return;
|
||||
}
|
||||
gameSize = (ulong)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + (readBuffer[3])) + 1;
|
||||
|
||||
gameSize = (ulong)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + (readBuffer[3])) +
|
||||
1;
|
||||
DicConsole.DebugWriteLine("Dump-media command", "Game partition total size: {0} sectors", gameSize);
|
||||
|
||||
// Get middle zone size
|
||||
@@ -202,6 +212,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing.");
|
||||
return;
|
||||
}
|
||||
|
||||
dumpLog.WriteLine("Getting disc size.");
|
||||
sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out duration);
|
||||
if(sense)
|
||||
@@ -210,18 +221,22 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Cannot get disc capacity.");
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
dumpLog.WriteLine("Cannot get PFI.");
|
||||
DicConsole.ErrorWriteLine("Cannot get PFI.");
|
||||
return;
|
||||
}
|
||||
|
||||
DicConsole.DebugWriteLine("Dump-media command", "Unlocked total size: {0} sectors", totalSize);
|
||||
blocks = totalSize + 1;
|
||||
middleZone = totalSize - (Decoders.DVD.PFI.Decode(readBuffer).Value.Layer0EndPSN - Decoders.DVD.PFI.Decode(readBuffer).Value.DataAreaStartPSN + 1) - gameSize + 1;
|
||||
middleZone = totalSize - (Decoders.DVD.PFI.Decode(readBuffer).Value.Layer0EndPSN -
|
||||
Decoders.DVD.PFI.Decode(readBuffer).Value.DataAreaStartPSN + 1) - gameSize + 1;
|
||||
|
||||
tmpBuf = new byte[readBuffer.Length - 4];
|
||||
Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4);
|
||||
@@ -234,13 +249,15 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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)
|
||||
{
|
||||
dumpLog.WriteLine("Cannot get DMI.");
|
||||
DicConsole.ErrorWriteLine("Cannot get DMI.");
|
||||
return;
|
||||
}
|
||||
|
||||
tmpBuf = new byte[readBuffer.Length - 4];
|
||||
Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4);
|
||||
sidecar.OpticalDisc[0].Xbox.DMI = new DumpType
|
||||
@@ -251,7 +268,6 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
};
|
||||
DataFile.WriteTo("SCSI Dump", sidecar.OpticalDisc[0].Xbox.DMI.Image, tmpBuf, "Unlocked DMI", true);
|
||||
|
||||
|
||||
totalSize = l0Video + l1Video + middleZone * 2 + gameSize;
|
||||
layerBreak = l0Video + middleZone + gameSize / 2;
|
||||
|
||||
@@ -270,7 +286,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
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)
|
||||
{
|
||||
dumpLog.WriteLine("Cannot read medium, aborting scan...");
|
||||
@@ -285,13 +302,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
if(read12)
|
||||
{
|
||||
sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, 0, blockSize, 0, blocksToRead, false, dev.Timeout, out duration);
|
||||
if(sense || dev.Error)
|
||||
blocksToRead /= 2;
|
||||
sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, 0, blockSize, 0,
|
||||
blocksToRead, false, dev.Timeout, out duration);
|
||||
if(sense || dev.Error) blocksToRead /= 2;
|
||||
}
|
||||
|
||||
if(!dev.Error || blocksToRead == 1)
|
||||
break;
|
||||
if(!dev.Error || blocksToRead == 1) break;
|
||||
}
|
||||
|
||||
if(dev.Error)
|
||||
@@ -316,13 +332,14 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
uint saveBlocksToRead = blocksToRead;
|
||||
DumpHardwareType currentTry = null;
|
||||
ExtentsULong extents = null;
|
||||
ResumeSupport.Process(true, true, totalSize, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformID, ref resume, ref currentTry, ref extents);
|
||||
ResumeSupport.Process(true, true, totalSize, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformID,
|
||||
ref resume, ref currentTry, ref extents);
|
||||
if(currentTry == null || extents == null)
|
||||
throw new Exception("Could not process resume file, not continuing...");
|
||||
|
||||
ulong currentSector = resume.NextBlock;
|
||||
dumpFile.Seek(resume.NextBlock, blockSize);
|
||||
if(resume.NextBlock > 0)
|
||||
dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
|
||||
|
||||
dumpLog.WriteLine("Reading game partition.");
|
||||
for(int e = 0; e <= 16; e++)
|
||||
@@ -335,8 +352,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if(currentSector >= blocks)
|
||||
break;
|
||||
if(currentSector >= blocks) break;
|
||||
|
||||
ulong extentStart, extentEnd;
|
||||
// Extents
|
||||
@@ -345,11 +361,13 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
if(xboxSS.Value.Extents[e].StartPSN <= xboxSS.Value.Layer0EndPSN)
|
||||
extentStart = xboxSS.Value.Extents[e].StartPSN - 0x30000;
|
||||
else
|
||||
extentStart = (xboxSS.Value.Layer0EndPSN + 1) * 2 - ((xboxSS.Value.Extents[e].StartPSN ^ 0xFFFFFF) + 1) - 0x30000;
|
||||
extentStart = (xboxSS.Value.Layer0EndPSN + 1) * 2 -
|
||||
((xboxSS.Value.Extents[e].StartPSN ^ 0xFFFFFF) + 1) - 0x30000;
|
||||
if(xboxSS.Value.Extents[e].EndPSN <= xboxSS.Value.Layer0EndPSN)
|
||||
extentEnd = xboxSS.Value.Extents[e].EndPSN - 0x30000;
|
||||
else
|
||||
extentEnd = (xboxSS.Value.Layer0EndPSN + 1) * 2 - ((xboxSS.Value.Extents[e].EndPSN ^ 0xFFFFFF) + 1) - 0x30000;
|
||||
extentEnd = (xboxSS.Value.Layer0EndPSN + 1) * 2 -
|
||||
((xboxSS.Value.Extents[e].EndPSN ^ 0xFFFFFF) + 1) - 0x30000;
|
||||
}
|
||||
// After last extent
|
||||
else
|
||||
@@ -358,8 +376,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
extentEnd = blocks;
|
||||
}
|
||||
|
||||
if(currentSector > extentEnd)
|
||||
continue;
|
||||
if(currentSector > extentEnd) continue;
|
||||
|
||||
for(ulong i = currentSector; i < extentStart; i += blocksToRead)
|
||||
{
|
||||
@@ -372,19 +389,17 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if((extentStart - i) < blocksToRead)
|
||||
blocksToRead = (uint)(extentStart - i);
|
||||
if((extentStart - i) < blocksToRead) blocksToRead = (uint)(extentStart - 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;
|
||||
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, totalSize, currentSpeed);
|
||||
|
||||
sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)i, blockSize, 0, blocksToRead, false, dev.Timeout, out cmdDuration);
|
||||
sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)i, blockSize,
|
||||
0, blocksToRead, false, dev.Timeout, out cmdDuration);
|
||||
totalDuration += cmdDuration;
|
||||
|
||||
if(!sense && !dev.Error)
|
||||
@@ -397,27 +412,26 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
else
|
||||
{
|
||||
// TODO: Reset device after X errors
|
||||
if(stopOnError)
|
||||
return; // TODO: Return more cleanly
|
||||
if(stopOnError) return; // TODO: Return more cleanly
|
||||
|
||||
// Write empty data
|
||||
dumpFile.Write(new byte[blockSize * blocksToRead]);
|
||||
|
||||
errored += blocksToRead;
|
||||
for(ulong b = i; b < i + blocksToRead; b++)
|
||||
resume.BadBlocks.Add(b);
|
||||
DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
if(cmdDuration < 500)
|
||||
mhddLog.Write(i, 65535);
|
||||
else
|
||||
mhddLog.Write(i, cmdDuration);
|
||||
for(ulong b = i; b < i + blocksToRead; b++) resume.BadBlocks.Add(b);
|
||||
|
||||
DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}",
|
||||
Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
if(cmdDuration < 500) mhddLog.Write(i, 65535);
|
||||
else mhddLog.Write(i, cmdDuration);
|
||||
|
||||
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);
|
||||
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
|
||||
@@ -438,8 +452,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if((extentEnd - i) < blocksToRead)
|
||||
blocksToRead = (uint)(extentEnd - i) + 1;
|
||||
if((extentEnd - i) < blocksToRead) blocksToRead = (uint)(extentEnd - i) + 1;
|
||||
|
||||
mhddLog.Write(i, cmdDuration);
|
||||
ibgLog.Write(i, currentSpeed * 1024);
|
||||
@@ -450,8 +463,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
resume.NextBlock = currentSector;
|
||||
}
|
||||
|
||||
if(!aborted)
|
||||
currentSector = extentEnd + 1;
|
||||
if(!aborted) currentSector = extentEnd + 1;
|
||||
}
|
||||
|
||||
// Middle Zone D
|
||||
@@ -465,10 +477,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if(((middleZone - 1) - middle) < blocksToRead)
|
||||
blocksToRead = (uint)((middleZone - 1) - middle);
|
||||
if(((middleZone - 1) - middle) < blocksToRead) blocksToRead = (uint)((middleZone - 1) - middle);
|
||||
|
||||
DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", middle + currentSector, totalSize, currentSpeed);
|
||||
DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", middle + currentSector, totalSize,
|
||||
currentSpeed);
|
||||
|
||||
mhddLog.Write(middle + currentSector, cmdDuration);
|
||||
ibgLog.Write(middle + currentSector, currentSpeed * 1024);
|
||||
@@ -489,6 +501,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Cannot lock drive, not continuing.");
|
||||
return;
|
||||
}
|
||||
|
||||
sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out duration);
|
||||
if(sense)
|
||||
{
|
||||
@@ -507,19 +520,18 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if(((l0Video + l1Video) - l1) < blocksToRead)
|
||||
blocksToRead = (uint)((l0Video + l1Video) - l1);
|
||||
if(((l0Video + l1Video) - l1) < blocksToRead) blocksToRead = (uint)((l0Video + l1Video) - l1);
|
||||
|
||||
#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;
|
||||
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.)", currentSector, totalSize, currentSpeed);
|
||||
DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", currentSector, totalSize,
|
||||
currentSpeed);
|
||||
|
||||
sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)l1, blockSize, 0, blocksToRead, false, dev.Timeout, out cmdDuration);
|
||||
sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)l1, blockSize, 0,
|
||||
blocksToRead, false, dev.Timeout, out cmdDuration);
|
||||
totalDuration += cmdDuration;
|
||||
|
||||
if(!sense && !dev.Error)
|
||||
@@ -532,8 +544,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
else
|
||||
{
|
||||
// TODO: Reset device after X errors
|
||||
if(stopOnError)
|
||||
return; // TODO: Return more cleanly
|
||||
if(stopOnError) return; // TODO: Return more cleanly
|
||||
|
||||
// Write empty data
|
||||
dumpFile.Write(new byte[blockSize * blocksToRead]);
|
||||
@@ -541,17 +552,17 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
// TODO: Handle errors in video partition
|
||||
//errored += blocksToRead;
|
||||
//resume.BadBlocks.Add(l1);
|
||||
DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
if(cmdDuration < 500)
|
||||
mhddLog.Write(l1, 65535);
|
||||
else
|
||||
mhddLog.Write(l1, cmdDuration);
|
||||
DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}",
|
||||
Decoders.SCSI.Sense.PrettifySense(senseBuf));
|
||||
if(cmdDuration < 500) mhddLog.Write(l1, 65535);
|
||||
else mhddLog.Write(l1, cmdDuration);
|
||||
|
||||
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);
|
||||
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
|
||||
@@ -569,6 +580,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing.");
|
||||
return;
|
||||
}
|
||||
|
||||
sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out duration);
|
||||
if(sense)
|
||||
{
|
||||
@@ -580,21 +592,19 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
DicConsole.WriteLine();
|
||||
mhddLog.Close();
|
||||
#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
|
||||
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 dump speed {0:F3} KiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1024) / (totalDuration / 1000));
|
||||
|
||||
#region Error handling
|
||||
if(resume.BadBlocks.Count > 0 && !aborted)
|
||||
{
|
||||
List<ulong> tmpList = new List<ulong>();
|
||||
|
||||
foreach(ulong ur in resume.BadBlocks)
|
||||
{
|
||||
for(ulong i = ur; i < ur + blocksToRead; i++)
|
||||
tmpList.Add(i);
|
||||
}
|
||||
foreach(ulong ur in resume.BadBlocks) { for(ulong i = ur; i < ur + blocksToRead; i++) tmpList.Add(i); }
|
||||
|
||||
tmpList.Sort();
|
||||
|
||||
@@ -604,7 +614,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
resume.BadBlocks = tmpList;
|
||||
|
||||
repeatRetry:
|
||||
repeatRetry:
|
||||
ulong[] tmpArray = resume.BadBlocks.ToArray();
|
||||
foreach(ulong badSector in tmpArray)
|
||||
{
|
||||
@@ -617,9 +627,12 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
cmdDuration = 0;
|
||||
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "");
|
||||
DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1,
|
||||
forward ? "forward" : "reverse",
|
||||
runningPersistent ? "recovering partial data, " : "");
|
||||
|
||||
sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)badSector, blockSize, 0, 1, false, dev.Timeout, out cmdDuration);
|
||||
sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)badSector,
|
||||
blockSize, 0, 1, false, dev.Timeout, out cmdDuration);
|
||||
totalDuration += cmdDuration;
|
||||
|
||||
if(!sense && !dev.Error)
|
||||
@@ -629,8 +642,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
dumpFile.WriteAt(readBuffer, badSector, blockSize);
|
||||
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
|
||||
}
|
||||
else if(runningPersistent)
|
||||
dumpFile.WriteAt(readBuffer, badSector, blockSize);
|
||||
else if(runningPersistent) dumpFile.WriteAt(readBuffer, badSector, blockSize);
|
||||
}
|
||||
|
||||
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
|
||||
@@ -649,27 +661,27 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
if(!runningPersistent && persistent)
|
||||
{
|
||||
sense = dev.ModeSense6(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current, 0x01, dev.Timeout, out duration);
|
||||
sense = dev.ModeSense6(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current, 0x01,
|
||||
dev.Timeout, out duration);
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ModeSense10(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current, 0x01, dev.Timeout, out duration);
|
||||
if(!sense)
|
||||
currentMode = Decoders.SCSI.Modes.DecodeMode10(readBuffer, dev.SCSIType);
|
||||
sense = dev.ModeSense10(out readBuffer, out senseBuf, false, ScsiModeSensePageControl.Current,
|
||||
0x01, dev.Timeout, out duration);
|
||||
if(!sense) currentMode = Decoders.SCSI.Modes.DecodeMode10(readBuffer, dev.SCSIType);
|
||||
}
|
||||
else
|
||||
currentMode = Decoders.SCSI.Modes.DecodeMode6(readBuffer, dev.SCSIType);
|
||||
else currentMode = Decoders.SCSI.Modes.DecodeMode6(readBuffer, dev.SCSIType);
|
||||
|
||||
if(currentMode.HasValue)
|
||||
currentModePage = currentMode.Value.Pages[0];
|
||||
if(currentMode.HasValue) currentModePage = currentMode.Value.Pages[0];
|
||||
|
||||
if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice)
|
||||
{
|
||||
Decoders.SCSI.Modes.ModePage_01_MMC pgMMC = new Decoders.SCSI.Modes.ModePage_01_MMC
|
||||
{
|
||||
PS = false,
|
||||
ReadRetryCount = 255,
|
||||
Parameter = 0x20
|
||||
};
|
||||
Decoders.SCSI.Modes.ModePage_01_MMC pgMMC =
|
||||
new Decoders.SCSI.Modes.ModePage_01_MMC
|
||||
{
|
||||
PS = false,
|
||||
ReadRetryCount = 255,
|
||||
Parameter = 0x20
|
||||
};
|
||||
Decoders.SCSI.Modes.DecodedMode md = new Decoders.SCSI.Modes.DecodedMode
|
||||
{
|
||||
Header = new Decoders.SCSI.Modes.ModeHeader(),
|
||||
@@ -677,10 +689,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
new Decoders.SCSI.Modes.ModePage
|
||||
{
|
||||
Page = 0x01,
|
||||
Subpage = 0x00,
|
||||
PageResponse = Decoders.SCSI.Modes.EncodeModePage_01_MMC(pgMMC)
|
||||
}
|
||||
Page = 0x01,
|
||||
Subpage = 0x00,
|
||||
PageResponse = Decoders.SCSI.Modes.EncodeModePage_01_MMC(pgMMC)
|
||||
}
|
||||
}
|
||||
};
|
||||
md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType);
|
||||
@@ -707,11 +719,11 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Pages = new Decoders.SCSI.Modes.ModePage[]
|
||||
{
|
||||
new Decoders.SCSI.Modes.ModePage
|
||||
{
|
||||
Page = 0x01,
|
||||
Subpage = 0x00,
|
||||
PageResponse = Decoders.SCSI.Modes.EncodeModePage_01(pg)
|
||||
}
|
||||
{
|
||||
Page = 0x01,
|
||||
Subpage = 0x00,
|
||||
PageResponse = Decoders.SCSI.Modes.EncodeModePage_01(pg)
|
||||
}
|
||||
}
|
||||
};
|
||||
md6 = Decoders.SCSI.Modes.EncodeMode6(md, dev.SCSIType);
|
||||
@@ -720,10 +732,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
|
||||
dumpLog.WriteLine("Sending MODE SELECT to drive.");
|
||||
sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out duration);
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration);
|
||||
}
|
||||
if(sense) { sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration); }
|
||||
|
||||
runningPersistent = true;
|
||||
if(!sense && !dev.Error)
|
||||
@@ -737,25 +746,20 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Decoders.SCSI.Modes.DecodedMode md = new Decoders.SCSI.Modes.DecodedMode
|
||||
{
|
||||
Header = new Decoders.SCSI.Modes.ModeHeader(),
|
||||
Pages = new Decoders.SCSI.Modes.ModePage[]
|
||||
{
|
||||
currentModePage.Value
|
||||
}
|
||||
Pages = new Decoders.SCSI.Modes.ModePage[] {currentModePage.Value}
|
||||
};
|
||||
md6 = Decoders.SCSI.Modes.EncodeMode6(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);
|
||||
if(sense)
|
||||
{
|
||||
sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration);
|
||||
}
|
||||
if(sense) { sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out duration); }
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
}
|
||||
#endregion Error handling
|
||||
|
||||
resume.BadBlocks.Sort();
|
||||
currentTry.Extents = Metadata.ExtentsConverter.ToMetadata(extents);
|
||||
|
||||
@@ -774,8 +778,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
break;
|
||||
}
|
||||
|
||||
if((blocks - i) < blocksToRead)
|
||||
blocksToRead = (uint)(blocks - i);
|
||||
if((blocks - i) < blocksToRead) blocksToRead = (uint)(blocks - i);
|
||||
|
||||
DicConsole.Write("\rChecksumming sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed);
|
||||
|
||||
@@ -792,11 +795,13 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (chkDuration / (double)1000);
|
||||
#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created
|
||||
}
|
||||
|
||||
DicConsole.WriteLine();
|
||||
dumpFile.Close();
|
||||
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));
|
||||
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
|
||||
(((double)blockSize * (double)(blocks + 1)) / 1024) / (totalChkDuration / 1000));
|
||||
|
||||
PluginBase plugins = new PluginBase();
|
||||
plugins.RegisterAllPlugins(encoding);
|
||||
@@ -813,15 +818,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
_imageFormat = ImageFormat.Detect(inputFilter);
|
||||
PartitionType[] xmlFileSysInfo = null;
|
||||
|
||||
try
|
||||
{
|
||||
if(!_imageFormat.OpenImage(inputFilter))
|
||||
_imageFormat = null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
_imageFormat = null;
|
||||
}
|
||||
try { if(!_imageFormat.OpenImage(inputFilter)) _imageFormat = null; }
|
||||
catch { _imageFormat = null; }
|
||||
|
||||
if(_imageFormat != null)
|
||||
{
|
||||
@@ -846,7 +844,8 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
};
|
||||
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);
|
||||
i, partitions[i].Start, partitions[i].End, partitions[i].Type,
|
||||
partitions[i].Scheme);
|
||||
|
||||
foreach(Filesystem _plugin in plugins.PluginsList.Values)
|
||||
{
|
||||
@@ -859,12 +858,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Statistics.AddFilesystem(_plugin.XmlFSType.Type);
|
||||
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
|
||||
|
||||
if(_plugin.XmlFSType.Type == "Opera")
|
||||
dskType = MediaType.ThreeDO;
|
||||
if(_plugin.XmlFSType.Type == "Opera") dskType = MediaType.ThreeDO;
|
||||
if(_plugin.XmlFSType.Type == "PC Engine filesystem")
|
||||
dskType = MediaType.SuperCDROM2;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Wii filesystem")
|
||||
dskType = MediaType.WOD;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Wii filesystem") dskType = MediaType.WOD;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Gamecube filesystem")
|
||||
dskType = MediaType.GOD;
|
||||
}
|
||||
@@ -877,27 +874,18 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
|
||||
if(lstFs.Count > 0)
|
||||
xmlFileSysInfo[i].FileSystems = lstFs.ToArray();
|
||||
if(lstFs.Count > 0) xmlFileSysInfo[i].FileSystems = lstFs.ToArray();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dumpLog.WriteLine("Getting filesystem for whole device.");
|
||||
xmlFileSysInfo = new PartitionType[1];
|
||||
xmlFileSysInfo[0] = new PartitionType
|
||||
{
|
||||
EndSector = (int)(blocks - 1),
|
||||
StartSector = 0
|
||||
};
|
||||
xmlFileSysInfo[0] = new PartitionType {EndSector = (int)(blocks - 1), StartSector = 0};
|
||||
List<FileSystemType> lstFs = new List<FileSystemType>();
|
||||
|
||||
Partition wholePart = new Partition
|
||||
{
|
||||
Name = "Whole device",
|
||||
Length = blocks,
|
||||
Size = blocks * blockSize
|
||||
};
|
||||
Partition wholePart =
|
||||
new Partition {Name = "Whole device", Length = blocks, Size = blocks * blockSize};
|
||||
|
||||
foreach(Filesystem _plugin in plugins.PluginsList.Values)
|
||||
{
|
||||
@@ -910,14 +898,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Statistics.AddFilesystem(_plugin.XmlFSType.Type);
|
||||
dumpLog.WriteLine("Filesystem {0} found.", _plugin.XmlFSType.Type);
|
||||
|
||||
if(_plugin.XmlFSType.Type == "Opera")
|
||||
dskType = MediaType.ThreeDO;
|
||||
if(_plugin.XmlFSType.Type == "PC Engine filesystem")
|
||||
dskType = MediaType.SuperCDROM2;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Wii filesystem")
|
||||
dskType = MediaType.WOD;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Gamecube filesystem")
|
||||
dskType = MediaType.GOD;
|
||||
if(_plugin.XmlFSType.Type == "Opera") dskType = MediaType.ThreeDO;
|
||||
if(_plugin.XmlFSType.Type == "PC Engine filesystem") dskType = MediaType.SuperCDROM2;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Wii filesystem") dskType = MediaType.WOD;
|
||||
if(_plugin.XmlFSType.Type == "Nintendo Gamecube filesystem") dskType = MediaType.GOD;
|
||||
}
|
||||
}
|
||||
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
|
||||
@@ -928,8 +912,7 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
}
|
||||
}
|
||||
|
||||
if(lstFs.Count > 0)
|
||||
xmlFileSysInfo[0].FileSystems = lstFs.ToArray();
|
||||
if(lstFs.Count > 0) xmlFileSysInfo[0].FileSystems = lstFs.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -946,35 +929,28 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
typeSpecified = true,
|
||||
Sectors = new SectorsType[1]
|
||||
};
|
||||
sidecar.OpticalDisc[0].Layers.Sectors[0] = new SectorsType
|
||||
{
|
||||
Value = (long)layerBreak
|
||||
};
|
||||
sidecar.OpticalDisc[0].Layers.Sectors[0] = new SectorsType {Value = (long)layerBreak};
|
||||
sidecar.OpticalDisc[0].Sessions = 1;
|
||||
sidecar.OpticalDisc[0].Tracks = new[] { 1 };
|
||||
sidecar.OpticalDisc[0].Tracks = new[] {1};
|
||||
sidecar.OpticalDisc[0].Track = new Schemas.TrackType[1];
|
||||
sidecar.OpticalDisc[0].Track[0] = new Schemas.TrackType
|
||||
{
|
||||
BytesPerSector = (int)blockSize,
|
||||
Checksums = sidecar.OpticalDisc[0].Checksums,
|
||||
EndSector = (long)(blocks - 1),
|
||||
Image = new ImageType()
|
||||
{
|
||||
format = "BINARY",
|
||||
offset = 0,
|
||||
offsetSpecified = true,
|
||||
Value = sidecar.OpticalDisc[0].Image.Value
|
||||
},
|
||||
Sequence = new TrackSequenceType()
|
||||
{
|
||||
Session = 1,
|
||||
TrackNumber = 1
|
||||
},
|
||||
Image =
|
||||
new ImageType()
|
||||
{
|
||||
format = "BINARY",
|
||||
offset = 0,
|
||||
offsetSpecified = true,
|
||||
Value = sidecar.OpticalDisc[0].Image.Value
|
||||
},
|
||||
Sequence = new TrackSequenceType() {Session = 1, TrackNumber = 1},
|
||||
Size = (long)(totalSize * blockSize),
|
||||
StartSector = 0
|
||||
};
|
||||
if(xmlFileSysInfo != null)
|
||||
sidecar.OpticalDisc[0].Track[0].FileSystemInformation = xmlFileSysInfo;
|
||||
if(xmlFileSysInfo != null) sidecar.OpticalDisc[0].Track[0].FileSystemInformation = xmlFileSysInfo;
|
||||
sidecar.OpticalDisc[0].Track[0].TrackType1 = TrackTypeTrackType.dvd;
|
||||
sidecar.OpticalDisc[0].Dimensions = Metadata.Dimensions.DimensionsFromMediaType(dskType);
|
||||
Metadata.MediaType.MediaTypeToString(dskType, out string xmlDskTyp, out string xmlDskSubTyp);
|
||||
@@ -985,10 +961,10 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
{
|
||||
DicConsole.WriteLine("Writing metadata sidecar");
|
||||
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml",
|
||||
FileMode.Create);
|
||||
FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create);
|
||||
|
||||
System.Xml.Serialization.XmlSerializer xmlSer = new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
System.Xml.Serialization.XmlSerializer xmlSer =
|
||||
new System.Xml.Serialization.XmlSerializer(typeof(CICMMetadataType));
|
||||
xmlSer.Serialize(xmlFs, sidecar);
|
||||
xmlFs.Close();
|
||||
}
|
||||
@@ -996,4 +972,4 @@ namespace DiscImageChef.Core.Devices.Dumping
|
||||
Statistics.AddMedia(dskType, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user