Added support for dumping subchannel in a separate file.

This commit is contained in:
2017-06-07 23:25:06 +01:00
parent a5d6154b55
commit 8e4e4cd27a
6 changed files with 99 additions and 20 deletions

View File

@@ -50,7 +50,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
internal class CompactDisc 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) 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)
{ {
MHDDLog mhddLog; MHDDLog mhddLog;
IBGLog ibgLog; IBGLog ibgLog;
@@ -60,7 +60,8 @@ namespace DiscImageChef.Core.Devices.Dumping
double duration; double duration;
ulong blocks = 0; ulong blocks = 0;
// TODO: Check subchannel support // TODO: Check subchannel support
uint blockSize = 2448; uint blockSize = 0;
uint subSize = 0;
byte[] tmpBuf; byte[] tmpBuf;
Decoders.CD.FullTOC.CDFullTOC? toc = null; Decoders.CD.FullTOC.CDFullTOC? toc = null;
DateTime start; DateTime start;
@@ -234,7 +235,14 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
} }
blockSize = blockSize; // TODO: Support variable subchannel kinds
blockSize = 2448;
subSize = 96;
int sectorSize;
if(separateSubchannel)
sectorSize = (int)(blockSize - subSize);
else
sectorSize = (int)blockSize;
if(toc == null) if(toc == null)
{ {
@@ -452,20 +460,39 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead);
dumpFile = new DataFile(outputPrefix + ".bin"); dumpFile = new DataFile(outputPrefix + ".bin");
DataFile subFile = null;
if(separateSubchannel)
subFile = new DataFile(outputPrefix + ".sub");
mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead); mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
ibgLog = new IBGLog(outputPrefix + ".ibg", 0x0008); ibgLog = new IBGLog(outputPrefix + ".ibg", 0x0008);
start = DateTime.UtcNow; start = DateTime.UtcNow;
for(int t = 0; t < tracks.Count(); t++) for(int t = 0; t < tracks.Count(); t++)
{ {
tracks[t].BytesPerSector = (int)blockSize; tracks[t].BytesPerSector = (int)sectorSize;
//tracks[0].Checksums = sidecar.OpticalDisc[0].Checksums;
tracks[t].Image = new ImageType(); tracks[t].Image = new ImageType();
tracks[t].Image.format = "BINARY"; tracks[t].Image.format = "BINARY";
tracks[t].Image.offset = dumpFile.Position; tracks[t].Image.offset = dumpFile.Position;
tracks[t].Image.offsetSpecified = true; tracks[t].Image.offsetSpecified = true;
tracks[t].Image.Value = outputPrefix + ".bin"; tracks[t].Image.Value = outputPrefix + ".bin";
tracks[t].Size = (long)((tracks[t].EndSector - tracks[t].StartSector + 1) * blockSize); tracks[t].Size = (long)((tracks[t].EndSector - tracks[t].StartSector + 1) * sectorSize);
tracks[t].SubChannel = new SubChannelType();
tracks[t].SubChannel.Image = new ImageType();
tracks[t].SubChannel.Image.format = "rw_raw";
tracks[t].SubChannel.Image.offsetSpecified = true;
tracks[t].SubChannel.Size = (long)((tracks[t].EndSector - tracks[t].StartSector + 1) * subSize);
if(separateSubchannel)
{
tracks[t].SubChannel.Image.offset = subFile.Position;
tracks[t].SubChannel.Image.Value = outputPrefix + ".sub";
}
else
{
tracks[t].SubChannel.Image.offset = tracks[t].Image.offset;
tracks[t].SubChannel.Image.Value = tracks[t].Image.Value;
}
bool checkedDataFormat = false; bool checkedDataFormat = false;
for(ulong i = (ulong)tracks[t].StartSector; i <= (ulong)tracks[t].EndSector; i += blocksToRead) for(ulong i = (ulong)tracks[t].StartSector; i <= (ulong)tracks[t].EndSector; i += blocksToRead)
@@ -498,7 +525,16 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
mhddLog.Write(i, cmdDuration); mhddLog.Write(i, cmdDuration);
ibgLog.Write(i, currentSpeed * 1024); ibgLog.Write(i, currentSpeed * 1024);
dumpFile.Write(readBuffer); if(separateSubchannel)
{
for(int b = 0; b < blocksToRead; b++)
{
dumpFile.Write(readBuffer, (int)(0 + b * blockSize), sectorSize);
subFile.Write(readBuffer, (int)(sectorSize + b * blockSize), (int)subSize);
}
}
else
dumpFile.Write(readBuffer);
} }
else else
{ {
@@ -507,7 +543,13 @@ namespace DiscImageChef.Core.Devices.Dumping
return; // TODO: Return more cleanly return; // TODO: Return more cleanly
// Write empty data // Write empty data
dumpFile.Write(new byte[blockSize * blocksToRead]); if(separateSubchannel)
{
dumpFile.Write(new byte[sectorSize * blocksToRead]);
subFile.Write(new byte[subSize * blocksToRead]);
}
else
dumpFile.Write(new byte[blockSize * blocksToRead]);
// TODO: Record error on mapfile // TODO: Record error on mapfile
@@ -595,13 +637,19 @@ namespace DiscImageChef.Core.Devices.Dumping
totalDuration += cmdDuration; totalDuration += cmdDuration;
} }
if(!sense && !dev.Error) if((!sense && !dev.Error) || runningPersistent)
{ {
unreadableSectors.Remove(badSector); if(!sense && !dev.Error)
dumpFile.WriteAt(readBuffer, badSector, blockSize); unreadableSectors.Remove(badSector);
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 if(runningPersistent)
dumpFile.WriteAt(readBuffer, badSector, blockSize);
} }
if(pass < retryPasses && !aborted && unreadableSectors.Count > 0) if(pass < retryPasses && !aborted && unreadableSectors.Count > 0)
@@ -683,11 +731,14 @@ namespace DiscImageChef.Core.Devices.Dumping
dataChk = new Checksum(); dataChk = new Checksum();
dumpFile.Seek(0, SeekOrigin.Begin); dumpFile.Seek(0, SeekOrigin.Begin);
if(separateSubchannel)
subFile.Seek(0, SeekOrigin.Begin);
blocksToRead = 500; blocksToRead = 500;
for(int t = 0; t < tracks.Count(); t++) for(int t = 0; t < tracks.Count(); t++)
{ {
Checksum trkChk = new Checksum(); Checksum trkChk = new Checksum();
Checksum subChk = new Checksum();
for(ulong i = (ulong)tracks[t].StartSector; i <= (ulong)tracks[t].EndSector; i += blocksToRead) for(ulong i = (ulong)tracks[t].StartSector; i <= (ulong)tracks[t].EndSector; i += blocksToRead)
{ {
@@ -702,8 +753,24 @@ namespace DiscImageChef.Core.Devices.Dumping
DateTime chkStart = DateTime.UtcNow; DateTime chkStart = DateTime.UtcNow;
byte[] dataToCheck = new byte[blockSize * blocksToRead]; byte[] dataToCheck = new byte[blockSize * blocksToRead];
dumpFile.Read(dataToCheck, 0, (int)(blockSize * blocksToRead)); dumpFile.Read(dataToCheck, 0, (int)(blockSize * blocksToRead));
dataChk.Update(dataToCheck); if(separateSubchannel)
trkChk.Update(dataToCheck); {
byte[] data = new byte[sectorSize];
byte[] sub = new byte[subSize];
for(int b = 0; b < blocksToRead; b++)
{
Array.Copy(dataToCheck, 0, data, 0, sectorSize);
Array.Copy(dataToCheck, sectorSize, sub, 0, subSize);
dataChk.Update(data);
trkChk.Update(data);
subChk.Update(sub);
}
}
else
{
dataChk.Update(dataToCheck);
trkChk.Update(dataToCheck);
}
DateTime chkEnd = DateTime.UtcNow; DateTime chkEnd = DateTime.UtcNow;
double chkDuration = (chkEnd - chkStart).TotalMilliseconds; double chkDuration = (chkEnd - chkStart).TotalMilliseconds;
@@ -715,6 +782,10 @@ namespace DiscImageChef.Core.Devices.Dumping
} }
tracks[t].Checksums = trkChk.End().ToArray(); tracks[t].Checksums = trkChk.End().ToArray();
if(separateSubchannel)
tracks[t].SubChannel.Checksums = subChk.End().ToArray();
else
tracks[t].SubChannel.Checksums = tracks[t].Checksums;
} }
DicConsole.WriteLine(); DicConsole.WriteLine();
dumpFile.Close(); dumpFile.Close();

View File

@@ -45,7 +45,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{ {
internal static class MMC internal static class MMC
{ {
internal static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, ref CICMMetadataType sidecar, ref MediaType dskType) 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)
{ {
byte[] cmdBuf = null; byte[] cmdBuf = null;
byte[] senseBuf = null; byte[] senseBuf = null;
@@ -163,7 +163,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(compactDisc) if(compactDisc)
{ {
CompactDisc.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType); CompactDisc.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, separateSubchannel);
return; return;
} }

View File

@@ -47,7 +47,7 @@ namespace DiscImageChef.Core.Devices.Dumping
public class SCSI public class SCSI
{ {
// TODO: Get cartridge serial number from Certance vendor EVPD // TODO: Get cartridge serial number from Certance vendor EVPD
public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError) public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, bool separateSubchannel)
{ {
byte[] senseBuf = null; byte[] senseBuf = null;
bool sense = false; bool sense = false;
@@ -145,7 +145,7 @@ namespace DiscImageChef.Core.Devices.Dumping
if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice) if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice)
{ {
MMC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType); MMC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, separateSubchannel);
DicConsole.WriteLine("Writing metadata sidecar"); DicConsole.WriteLine("Writing metadata sidecar");

View File

@@ -1,3 +1,7 @@
* Options.cs:
* Commands/DumpMedia.cs:
Added support for dumping subchannel in a separate file.
* Commands/Ls.cs: * Commands/Ls.cs:
* Commands/ExtractFiles.cs: * Commands/ExtractFiles.cs:
Add support for encodings. Add support for encodings.

View File

@@ -63,6 +63,7 @@ namespace DiscImageChef.Commands
DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", options.Force); DicConsole.DebugWriteLine("Dump-Media command", "--force={0}", options.Force);
DicConsole.DebugWriteLine("Dump-Media command", "--retry-passes={0}", options.RetryPasses); DicConsole.DebugWriteLine("Dump-Media command", "--retry-passes={0}", options.RetryPasses);
DicConsole.DebugWriteLine("Dump-Media command", "--persistent={0}", options.Persistent); DicConsole.DebugWriteLine("Dump-Media command", "--persistent={0}", options.Persistent);
DicConsole.DebugWriteLine("Dump-Media command", "--separate-subchannel={0}", options.SeparateSubchannel);
if(!File.Exists(options.DevicePath)) if(!File.Exists(options.DevicePath))
{ {
@@ -100,7 +101,7 @@ namespace DiscImageChef.Commands
break; break;
case DeviceType.ATAPI: case DeviceType.ATAPI:
case DeviceType.SCSI: case DeviceType.SCSI:
SCSI.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError); SCSI.Dump(dev, options.DevicePath, options.OutputPrefix, options.RetryPasses, options.Force, options.Raw, options.Persistent, options.StopOnError, options.SeparateSubchannel);
break; break;
default: default:
throw new NotSupportedException("Unknown device type."); throw new NotSupportedException("Unknown device type.");

View File

@@ -299,6 +299,9 @@ namespace DiscImageChef
HelpText = "Try to recover partial or incorrect data.")] HelpText = "Try to recover partial or incorrect data.")]
public bool Persistent { get; set; } public bool Persistent { get; set; }
[Option("separate-subchannel", Default = false,
HelpText = "Save subchannel in a separate file. Only applicable to CD/DDCD/GD.")]
public bool SeparateSubchannel { get; set; }
} }
[Verb("device-report", HelpText = "Tests the device capabilities and creates an XML report of them.")] [Verb("device-report", HelpText = "Tests the device capabilities and creates an XML report of them.")]