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 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;
IBGLog ibgLog;
@@ -60,7 +60,8 @@ namespace DiscImageChef.Core.Devices.Dumping
double duration;
ulong blocks = 0;
// TODO: Check subchannel support
uint blockSize = 2448;
uint blockSize = 0;
uint subSize = 0;
byte[] tmpBuf;
Decoders.CD.FullTOC.CDFullTOC? toc = null;
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)
{
@@ -452,20 +460,39 @@ namespace DiscImageChef.Core.Devices.Dumping
DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead);
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);
ibgLog = new IBGLog(outputPrefix + ".ibg", 0x0008);
start = DateTime.UtcNow;
for(int t = 0; t < tracks.Count(); t++)
{
tracks[t].BytesPerSector = (int)blockSize;
//tracks[0].Checksums = sidecar.OpticalDisc[0].Checksums;
tracks[t].BytesPerSector = (int)sectorSize;
tracks[t].Image = new ImageType();
tracks[t].Image.format = "BINARY";
tracks[t].Image.offset = dumpFile.Position;
tracks[t].Image.offsetSpecified = true;
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;
for(ulong i = (ulong)tracks[t].StartSector; i <= (ulong)tracks[t].EndSector; i += blocksToRead)
@@ -498,6 +525,15 @@ namespace DiscImageChef.Core.Devices.Dumping
{
mhddLog.Write(i, cmdDuration);
ibgLog.Write(i, currentSpeed * 1024);
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
@@ -507,6 +543,12 @@ namespace DiscImageChef.Core.Devices.Dumping
return; // TODO: Return more cleanly
// Write empty data
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
@@ -595,13 +637,19 @@ namespace DiscImageChef.Core.Devices.Dumping
totalDuration += cmdDuration;
}
if(!sense && !dev.Error)
if((!sense && !dev.Error) || runningPersistent)
{
if(!sense && !dev.Error)
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)
@@ -683,11 +731,14 @@ namespace DiscImageChef.Core.Devices.Dumping
dataChk = new Checksum();
dumpFile.Seek(0, SeekOrigin.Begin);
if(separateSubchannel)
subFile.Seek(0, SeekOrigin.Begin);
blocksToRead = 500;
for(int t = 0; t < tracks.Count(); t++)
{
Checksum trkChk = new Checksum();
Checksum subChk = new Checksum();
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;
byte[] dataToCheck = new byte[blockSize * blocksToRead];
dumpFile.Read(dataToCheck, 0, (int)(blockSize * blocksToRead));
if(separateSubchannel)
{
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;
double chkDuration = (chkEnd - chkStart).TotalMilliseconds;
@@ -715,6 +782,10 @@ 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;
}
DicConsole.WriteLine();
dumpFile.Close();

View File

@@ -45,7 +45,7 @@ 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)
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[] senseBuf = null;
@@ -163,7 +163,7 @@ namespace DiscImageChef.Core.Devices.Dumping
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;
}

View File

@@ -47,7 +47,7 @@ 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)
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;
bool sense = false;
@@ -145,7 +145,7 @@ 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);
MMC.Dump(dev, devicePath, outputPrefix, retryPasses, force, dumpRaw, persistent, stopOnError, ref sidecar, ref dskType, separateSubchannel);
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/ExtractFiles.cs:
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", "--retry-passes={0}", options.RetryPasses);
DicConsole.DebugWriteLine("Dump-Media command", "--persistent={0}", options.Persistent);
DicConsole.DebugWriteLine("Dump-Media command", "--separate-subchannel={0}", options.SeparateSubchannel);
if(!File.Exists(options.DevicePath))
{
@@ -100,7 +101,7 @@ namespace DiscImageChef.Commands
break;
case DeviceType.ATAPI:
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;
default:
throw new NotSupportedException("Unknown device type.");

View File

@@ -299,6 +299,9 @@ namespace DiscImageChef
HelpText = "Try to recover partial or incorrect data.")]
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.")]