REFACTOR: Reformat code.

This commit is contained in:
2017-12-19 20:33:03 +00:00
parent 77edc7c91c
commit e6f6ace80b
704 changed files with 82627 additions and 83641 deletions

View File

@@ -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.");
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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.");
}
}
}
}

View File

@@ -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
}
}
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}
}