Add support for dumping media in any of the writable image formats.

CompactDisc dumping disabled until further notice.
This commit is contained in:
2018-01-19 01:21:01 +00:00
parent de52db7da0
commit 29ac7931cb
14 changed files with 1746 additions and 2339 deletions

View File

@@ -33,20 +33,19 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using DiscImageChef.CommonTypes;
using DiscImageChef.Console;
using DiscImageChef.Core.Logging;
using DiscImageChef.Decoders.MMC;
using DiscImageChef.Devices;
using DiscImageChef.DiscImages;
using DiscImageChef.Filesystems;
using DiscImageChef.Filters;
using DiscImageChef.Metadata;
using Extents;
using Schemas;
using MediaType = DiscImageChef.Metadata.MediaType;
using MediaType = DiscImageChef.CommonTypes.MediaType;
namespace DiscImageChef.Core.Devices.Dumping
{
@@ -61,6 +60,7 @@ namespace DiscImageChef.Core.Devices.Dumping
/// <param name="dev">Device</param>
/// <param name="devicePath">Path to the device</param>
/// <param name="outputPrefix">Prefix for output data files</param>
/// <param name="outputPlugin">Plugin for output file</param>
/// <param name="retryPasses">How many times to retry</param>
/// <param name="force">Force to continue dump whenever possible</param>
/// <param name="dumpRaw">Dump long or scrambled sectors</param>
@@ -69,10 +69,16 @@ namespace DiscImageChef.Core.Devices.Dumping
/// <param name="resume">Information for dump resuming</param>
/// <param name="dumpLog">Dump logger</param>
/// <param name="encoding">Encoding to use when analyzing dump</param>
/// <param name="outputPath">Path to output file</param>
/// <param name="formatOptions">Formats to pass to output file plugin</param>
/// <exception cref="ArgumentException">If you asked to dump long sectors from a SCSI Streaming device</exception>
public static void Dump(Device dev, string devicePath, string outputPrefix, ushort retryPasses, bool force,
bool dumpRaw, bool persistent, bool stopOnError, ref Resume resume, ref DumpLog dumpLog,
Encoding encoding)
public static void Dump(Device dev, string devicePath, IWritableImage outputPlugin, ushort retryPasses,
bool force, bool dumpRaw, bool persistent, bool stopOnError,
ref Resume resume,
ref
DumpLog dumpLog, Encoding encoding, string outputPrefix, string outputPath,
Dictionary<string, string>
formatOptions)
{
bool aborted;
@@ -88,22 +94,22 @@ namespace DiscImageChef.Core.Devices.Dumping
}
}
bool sense;
bool sense;
const ushort SD_PROFILE = 0x0001;
const uint TIMEOUT = 5;
double duration;
const uint TIMEOUT = 5;
double duration;
CICMMetadataType sidecar = new CICMMetadataType {BlockMedia = new[] {new BlockMediaType()}};
uint blocksToRead = 128;
uint blockSize = 512;
ulong blocks = 0;
byte[] csd = null;
byte[] ocr = null;
byte[] ecsd = null;
byte[] scr = null;
int physicalBlockSize = 0;
bool byteAddressed = true;
uint blocksToRead = 128;
uint blockSize = 512;
ulong blocks = 0;
byte[] csd = null;
byte[] ocr = null;
byte[] ecsd = null;
byte[] scr = null;
int physicalBlockSize = 0;
bool byteAddressed = true;
Dictionary<MediaTagType, byte[]> mediaTags = new Dictionary<MediaTagType, byte[]>();
switch(dev.Type)
{
@@ -114,13 +120,15 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!sense)
{
ExtendedCSD ecsdDecoded = Decoders.MMC.Decoders.DecodeExtendedCSD(ecsd);
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;
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;
// Supposing it's high-capacity MMC if it has Extended CSD...
byteAddressed = false;
mediaTags.Add(MediaTagType.MMC_ExtendedCSD, null);
}
else ecsd = null;
@@ -131,17 +139,20 @@ namespace DiscImageChef.Core.Devices.Dumping
if(blocks == 0)
{
CSD csdDecoded = Decoders.MMC.Decoders.DecodeCSD(csd);
blocks = (ulong)((csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2));
blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength);
blocks =
(ulong)((csdDecoded.Size + 1) * Math.Pow(2, csdDecoded.SizeMultiplier + 2));
blockSize = (uint)Math.Pow(2, csdDecoded.ReadBlockLength);
}
mediaTags.Add(MediaTagType.MMC_CSD, null);
}
else csd = null;
dumpLog.WriteLine("Reading OCR");
sense = dev.ReadOcr(out ocr, out _, TIMEOUT, out duration);
sense = dev.ReadOcr(out ocr, out _, TIMEOUT, out duration);
if(sense) ocr = null;
else mediaTags.Add(MediaTagType.MMC_OCR, null);
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
break;
}
case DeviceType.SecureDigital:
@@ -151,115 +162,45 @@ namespace DiscImageChef.Core.Devices.Dumping
if(!sense)
{
Decoders.SecureDigital.CSD 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;
mediaTags.Add(MediaTagType.SD_CSD, null);
}
else csd = null;
dumpLog.WriteLine("Reading OCR");
sense = dev.ReadSdocr(out ocr, out _, TIMEOUT, out duration);
sense = dev.ReadSdocr(out ocr, out _, TIMEOUT, out duration);
if(sense) ocr = null;
else mediaTags.Add(MediaTagType.SD_OCR, null);
dumpLog.WriteLine("Reading SCR");
sense = dev.ReadScr(out scr, out _, TIMEOUT, out duration);
sense = dev.ReadScr(out scr, out _, TIMEOUT, out duration);
if(sense) scr = null;
else mediaTags.Add(MediaTagType.SD_SCR, null);
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
break;
}
}
dumpLog.WriteLine("Reading CID");
sense = dev.ReadCid(out byte[] cid, out _, TIMEOUT, out duration);
sense = dev.ReadCid(out byte[] cid, out _, TIMEOUT, out duration);
if(sense) cid = null;
DumpType cidDump = null;
DumpType csdDump = null;
DumpType ocrDump = null;
if(cid != null)
{
cidDump = new DumpType
{
Image = outputPrefix + ".cid.bin",
Size = cid.Length,
Checksums = Checksum.GetChecksums(cid).ToArray()
};
DataFile.WriteTo("MMC/SecureDigital Dump", cidDump.Image, cid);
}
if(csd != null)
{
csdDump = new DumpType
{
Image = outputPrefix + ".csd.bin",
Size = csd.Length,
Checksums = Checksum.GetChecksums(csd).ToArray()
};
DataFile.WriteTo("MMC/SecureDigital Dump", csdDump.Image, csd);
}
if(ecsd != null)
{
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType
{
Image = outputPrefix + ".ecsd.bin",
Size = ecsd.Length,
Checksums = Checksum.GetChecksums(ecsd).ToArray()
};
DataFile.WriteTo("MMC/SecureDigital Dump", sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD.Image,
ecsd);
}
if(ocr != null)
{
ocrDump = new DumpType
{
Image = outputPrefix + ".ocr.bin",
Size = ocr.Length,
Checksums = Checksum.GetChecksums(ocr).ToArray()
};
DataFile.WriteTo("MMC/SecureDigital Dump", ocrDump.Image, ocr);
}
if(scr != null)
{
sidecar.BlockMedia[0].SecureDigital.SCR = new DumpType
{
Image = outputPrefix + ".scr.bin",
Size = scr.Length,
Checksums = Checksum.GetChecksums(scr).ToArray()
};
DataFile.WriteTo("MMC/SecureDigital Dump", sidecar.BlockMedia[0].SecureDigital.SCR.Image, scr);
}
switch(dev.Type)
{
case DeviceType.MMC:
sidecar.BlockMedia[0].MultiMediaCard.CID = cidDump;
sidecar.BlockMedia[0].MultiMediaCard.CSD = csdDump;
sidecar.BlockMedia[0].MultiMediaCard.OCR = ocrDump;
break;
case DeviceType.SecureDigital:
sidecar.BlockMedia[0].SecureDigital.CID = cidDump;
sidecar.BlockMedia[0].SecureDigital.CSD = csdDump;
sidecar.BlockMedia[0].SecureDigital.OCR = ocrDump;
break;
}
else mediaTags.Add(dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID : MediaTagType.MMC_CID, null);
DateTime start;
DateTime end;
double totalDuration = 0;
double totalChkDuration = 0;
double currentSpeed = 0;
double maxSpeed = double.MinValue;
double minSpeed = double.MaxValue;
double totalDuration = 0;
double totalChkDuration = 0;
double currentSpeed = 0;
double maxSpeed = double.MinValue;
double minSpeed = double.MaxValue;
aborted = false;
aborted = false;
System.Console.CancelKeyPress += (sender, e) => e.Cancel = aborted = true;
if(blocks == 0)
@@ -272,7 +213,7 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpLog.WriteLine("Device reports {0} blocks.", blocks);
byte[] cmdBuf;
bool error;
bool error;
while(true)
{
@@ -293,18 +234,50 @@ namespace DiscImageChef.Core.Devices.Dumping
dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
DumpHardwareType currentTry = null;
ExtentsULong extents = null;
ExtentsULong extents = null;
ResumeSupport.Process(true, false, blocks, dev.Manufacturer, dev.Model, dev.Serial, dev.PlatformId,
ref resume, ref currentTry, ref extents);
if(currentTry == null || extents == null)
throw new InvalidOperationException("Could not process resume file, not continuing...");
bool ret = true;
foreach(MediaTagType tag in mediaTags.Keys)
{
if(outputPlugin.SupportedMediaTags.Contains(tag)) continue;
ret = false;
dumpLog.WriteLine($"Output format does not support {tag}.");
DicConsole.ErrorWriteLine($"Output format does not support {tag}.");
}
if(!ret)
{
dumpLog.WriteLine("Several media tags not supported, {0}continuing...", force ? "" : "not ");
DicConsole.ErrorWriteLine("Several media tags not supported, {0}continuing...", force ? "" : "not ");
if(!force) return;
}
DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead);
MhddLog mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead);
IbgLog ibgLog = new IbgLog(outputPrefix + ".ibg", SD_PROFILE);
DataFile dumpFile = new DataFile(outputPrefix + ".bin");
dumpFile.Seek(resume.NextBlock, blockSize);
IbgLog ibgLog = new IbgLog(outputPrefix + ".ibg", SD_PROFILE);
ret = outputPlugin.Create(outputPath,
dev.Type == DeviceType.SecureDigital
? MediaType.SecureDigital
: MediaType.MMC,
formatOptions, blocks, blockSize);
// Cannot create image
if(!ret)
{
dumpLog.WriteLine("Error creating output image, not continuing.");
dumpLog.WriteLine(outputPlugin.ErrorMessage);
DicConsole.ErrorWriteLine("Error creating output image, not continuing.");
DicConsole.ErrorWriteLine(outputPlugin.ErrorMessage);
return;
}
if(resume.NextBlock > 0) dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock);
start = DateTime.UtcNow;
@@ -319,10 +292,10 @@ namespace DiscImageChef.Core.Devices.Dumping
if(blocks - i < blocksToRead) blocksToRead = (byte)(blocks - i);
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
#pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
if(currentSpeed > maxSpeed && currentSpeed != 0) maxSpeed = currentSpeed;
if(currentSpeed < minSpeed && currentSpeed != 0) minSpeed = currentSpeed;
#pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator
#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);
@@ -333,7 +306,7 @@ namespace DiscImageChef.Core.Devices.Dumping
{
mhddLog.Write(i, duration);
ibgLog.Write(i, currentSpeed * 1024);
dumpFile.Write(cmdBuf);
outputPlugin.WriteSectors(cmdBuf, i, blocksToRead);
extents.Add(i, blocksToRead, true);
}
else
@@ -343,29 +316,32 @@ namespace DiscImageChef.Core.Devices.Dumping
mhddLog.Write(i, duration < 500 ? 65535 : duration);
ibgLog.Write(i, 0);
dumpFile.Write(new byte[blockSize * blocksToRead]);
outputPlugin.WriteSectors(new byte[blockSize * blocksToRead], i, blocksToRead);
dumpLog.WriteLine("Error reading {0} blocks from block {1}.", blocksToRead, i);
}
double newSpeed = (double)blockSize * blocksToRead / 1048576 / (duration / 1000);
double newSpeed =
(double)blockSize * blocksToRead / 1048576 / (duration / 1000);
if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed;
resume.NextBlock = i + blocksToRead;
resume.NextBlock = i + blocksToRead;
}
end = DateTime.Now;
DicConsole.WriteLine();
mhddLog.Close();
ibgLog.Close(dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000), devicePath);
dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);
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));
#region Error handling
if(resume.BadBlocks.Count > 0 && !aborted)
{
int pass = 0;
bool forward = true;
int pass = 0;
bool forward = true;
bool runningPersistent = false;
repeatRetryLba:
@@ -392,10 +368,11 @@ namespace DiscImageChef.Core.Devices.Dumping
{
resume.BadBlocks.Remove(badSector);
extents.Add(badSector);
dumpFile.WriteAt(cmdBuf, badSector, blockSize);
outputPlugin.WriteSector(cmdBuf, badSector);
dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
}
else if(runningPersistent) dumpFile.WriteAt(cmdBuf, badSector, blockSize);
else if(runningPersistent)
outputPlugin.WriteSector(cmdBuf, badSector);
}
if(pass < retryPasses && !aborted && resume.BadBlocks.Count > 0)
@@ -413,179 +390,190 @@ namespace DiscImageChef.Core.Devices.Dumping
currentTry.Extents = ExtentsConverter.ToMetadata(extents);
Checksum dataChk = new Checksum();
dumpFile.Seek(0, SeekOrigin.Begin);
blocksToRead = 500;
dumpLog.WriteLine("Closing output file.");
DicConsole.WriteLine("Closing output file.");
outputPlugin.Close();
dumpLog.WriteLine("Checksum starts.");
for(ulong i = 0; i < blocks; i += blocksToRead)
if(aborted)
{
if(aborted)
{
dumpLog.WriteLine("Aborted!");
break;
}
if(blocks - i < blocksToRead) blocksToRead = (byte)(blocks - i);
DicConsole.Write("\rChecksumming sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed);
DateTime chkStart = DateTime.UtcNow;
byte[] dataToCheck = new byte[blockSize * blocksToRead];
dumpFile.Read(dataToCheck, 0, (int)(blockSize * blocksToRead));
dataChk.Update(dataToCheck);
DateTime chkEnd = DateTime.UtcNow;
double chkDuration = (chkEnd - chkStart).TotalMilliseconds;
totalChkDuration += chkDuration;
double newSpeed = (double)blockSize * blocksToRead / 1048576 / (chkDuration / 1000);
if(!double.IsInfinity(newSpeed)) currentSpeed = newSpeed;
}
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));
PluginBase plugins = new PluginBase();
FiltersList filtersList = new FiltersList();
IFilter inputFilter = filtersList.GetFilter(outputPrefix + ".bin");
if(inputFilter == null)
{
DicConsole.ErrorWriteLine("Cannot open file just created, this should not happen.");
dumpLog.WriteLine("Aborted!");
return;
}
IMediaImage imageFormat = ImageFormat.Detect(inputFilter);
PartitionType[] xmlFileSysInfo = null;
dumpLog.WriteLine("Creating sidecar.");
FiltersList filters = new FiltersList();
IFilter filter = filters.GetFilter(outputPath);
IMediaImage inputPlugin = ImageFormat.Detect(filter);
if(!inputPlugin.Open(filter)) throw new ArgumentException("Could not open created image.");
try { if(!imageFormat.Open(inputFilter)) imageFormat = null; }
catch { imageFormat = null; }
DateTime chkStart = DateTime.UtcNow;
CICMMetadataType sidecar = Sidecar.Create(inputPlugin, outputPath, filter.Id, encoding);
if(imageFormat != null)
switch(dev.Type)
{
dumpLog.WriteLine("Getting partitions.");
List<Partition> partitions = Partitions.GetAll(imageFormat);
Partitions.AddSchemesToStats(partitions);
dumpLog.WriteLine("Found {0} partitions.", partitions.Count);
case DeviceType.MMC:
sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType();
break;
case DeviceType.SecureDigital:
sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType();
break;
}
if(partitions.Count > 0)
DumpType cidDump = null;
DumpType csdDump = null;
DumpType ocrDump = null;
if(cid != null)
{
cidDump = new DumpType
{
xmlFileSysInfo = new PartitionType[partitions.Count];
for(int i = 0; i < partitions.Count; i++)
{
xmlFileSysInfo[i] = new PartitionType
{
Description = partitions[i].Description,
EndSector = (int)(partitions[i].Start + partitions[i].Length - 1),
Name = partitions[i].Name,
Sequence = (int)partitions[i].Sequence,
StartSector = (int)partitions[i].Start,
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);
Image = outputPath,
Size = cid.Length,
Checksums = Checksum.GetChecksums(cid).ToArray()
};
foreach(IFilesystem plugin in plugins.PluginsList.Values)
try
{
if(!plugin.Identify(imageFormat, partitions[i])) continue;
ret =
outputPlugin.WriteMediaTag(cid,
dev.Type == DeviceType.SecureDigital
? MediaTagType.SD_CID
: MediaTagType.MMC_CID);
plugin.GetInformation(imageFormat, partitions[i], out _, encoding);
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
dumpLog.WriteLine("Filesystem {0} found.", plugin.XmlFsType.Type);
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
{
//DicConsole.DebugWriteLine("Dump-media command", "Plugin {0} crashed", _plugin.Name);
}
if(lstFs.Count > 0) xmlFileSysInfo[i].FileSystems = lstFs.ToArray();
}
}
else
// Cannot write CID to image
if(!ret && !force)
{
dumpLog.WriteLine("Getting filesystem for whole device.");
xmlFileSysInfo = new PartitionType[1];
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};
foreach(IFilesystem plugin in plugins.PluginsList.Values)
try
{
if(!plugin.Identify(imageFormat, wholePart)) continue;
plugin.GetInformation(imageFormat, wholePart, out _, encoding);
lstFs.Add(plugin.XmlFsType);
Statistics.AddFilesystem(plugin.XmlFsType.Type);
dumpLog.WriteLine("Filesystem {0} found.", plugin.XmlFsType.Type);
}
#pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body
catch
#pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body
{
//DicConsole.DebugWriteLine("Create-sidecar command", "Plugin {0} crashed", _plugin.Name);
}
if(lstFs.Count > 0) xmlFileSysInfo[0].FileSystems = lstFs.ToArray();
dumpLog.WriteLine("Cannot write CID to output image.");
throw new ArgumentException(outputPlugin.ErrorMessage);
}
}
sidecar.BlockMedia[0].Checksums = dataChk.End().ToArray();
if(csd != null)
{
csdDump = new DumpType
{
Image = outputPath,
Size = csd.Length,
Checksums = Checksum.GetChecksums(csd).ToArray()
};
ret =
outputPlugin.WriteMediaTag(csd,
dev.Type == DeviceType.SecureDigital
? MediaTagType.SD_CSD
: MediaTagType.MMC_CSD);
// Cannot write CSD to image
if(!ret && !force)
{
dumpLog.WriteLine("Cannot write CSD to output image.");
throw new ArgumentException(outputPlugin.ErrorMessage);
}
}
if(ecsd != null)
{
sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType
{
Image = outputPath,
Size = ecsd.Length,
Checksums = Checksum.GetChecksums(ecsd).ToArray()
};
ret = outputPlugin.WriteMediaTag(ecsd, MediaTagType.MMC_ExtendedCSD);
// Cannot write Extended CSD to image
if(!ret && !force)
{
dumpLog.WriteLine("Cannot write Extended CSD to output image.");
throw new ArgumentException(outputPlugin.ErrorMessage);
}
}
if(ocr != null)
{
ocrDump = new DumpType
{
Image = outputPath,
Size = ocr.Length,
Checksums = Checksum.GetChecksums(ocr).ToArray()
};
ret =
outputPlugin.WriteMediaTag(ocr,
dev.Type == DeviceType.SecureDigital
? MediaTagType.SD_OCR
: MediaTagType.MMC_OCR);
// Cannot write OCR to image
if(!ret && !force)
{
dumpLog.WriteLine("Cannot write OCR to output image.");
throw new ArgumentException(outputPlugin.ErrorMessage);
}
}
if(scr != null)
{
sidecar.BlockMedia[0].SecureDigital.SCR = new DumpType
{
Image = outputPath,
Size = scr.Length,
Checksums = Checksum.GetChecksums(scr).ToArray()
};
ret = outputPlugin.WriteMediaTag(scr, MediaTagType.SD_SCR);
// Cannot write SCR to image
if(!ret && !force)
{
dumpLog.WriteLine("Cannot write SCR to output image.");
throw new ArgumentException(outputPlugin.ErrorMessage);
}
}
switch(dev.Type)
{
case DeviceType.MMC:
sidecar.BlockMedia[0].MultiMediaCard.CID = cidDump;
sidecar.BlockMedia[0].MultiMediaCard.CSD = csdDump;
sidecar.BlockMedia[0].MultiMediaCard.OCR = ocrDump;
break;
case DeviceType.SecureDigital:
sidecar.BlockMedia[0].SecureDigital.CID = cidDump;
sidecar.BlockMedia[0].SecureDigital.CSD = csdDump;
sidecar.BlockMedia[0].SecureDigital.OCR = ocrDump;
break;
}
end = DateTime.UtcNow;
totalChkDuration = (end - chkStart).TotalMilliseconds;
dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds);
dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
(double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000));
string xmlDskTyp = null, xmlDskSubTyp = null;
switch(dev.Type)
{
case DeviceType.MMC:
MediaType.MediaTypeToString(CommonTypes.MediaType.MMC, out xmlDskTyp, out xmlDskSubTyp);
sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(CommonTypes.MediaType.MMC);
Metadata.MediaType.MediaTypeToString(MediaType.MMC, out xmlDskTyp, out xmlDskSubTyp);
sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(MediaType.MMC);
break;
case DeviceType.SecureDigital:
MediaType.MediaTypeToString(CommonTypes.MediaType.SecureDigital, out xmlDskTyp, out xmlDskSubTyp);
sidecar.BlockMedia[0].Dimensions =
Dimensions.DimensionsFromMediaType(CommonTypes.MediaType.SecureDigital);
Metadata.MediaType.MediaTypeToString(MediaType.SecureDigital, out xmlDskTyp, out xmlDskSubTyp);
sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(MediaType.SecureDigital);
break;
}
sidecar.BlockMedia[0].DiskType = xmlDskTyp;
sidecar.BlockMedia[0].DiskType = xmlDskTyp;
sidecar.BlockMedia[0].DiskSubType = xmlDskSubTyp;
// TODO: Implement device firmware revision
sidecar.BlockMedia[0].Image = new ImageType
{
format = "Raw disk image (sector by sector copy)",
Value = outputPrefix + ".bin"
};
switch(dev.Type)
{
case DeviceType.MMC:
sidecar.BlockMedia[0].Interface = "MultiMediaCard";
break;
case DeviceType.SecureDigital:
sidecar.BlockMedia[0].Interface = "SecureDigital";
break;
}
sidecar.BlockMedia[0].LogicalBlocks = (long)blocks;
sidecar.BlockMedia[0].LogicalBlocks = (long)blocks;
sidecar.BlockMedia[0].PhysicalBlockSize = physicalBlockSize > 0 ? physicalBlockSize : (int)blockSize;
sidecar.BlockMedia[0].LogicalBlockSize = (int)blockSize;
sidecar.BlockMedia[0].Manufacturer = dev.Manufacturer;
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;
sidecar.BlockMedia[0].LogicalBlockSize = (int)blockSize;
sidecar.BlockMedia[0].Manufacturer = dev.Manufacturer;
sidecar.BlockMedia[0].Model = dev.Model;
sidecar.BlockMedia[0].Serial = dev.Serial;
sidecar.BlockMedia[0].Size = (long)(blocks * blockSize);
DicConsole.WriteLine();
@@ -595,7 +583,7 @@ namespace DiscImageChef.Core.Devices.Dumping
(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);
DicConsole.WriteLine("{0} sectors could not be read.", resume.BadBlocks.Count);
if(resume.BadBlocks.Count > 0) resume.BadBlocks.Sort();
DicConsole.WriteLine();
@@ -613,10 +601,10 @@ namespace DiscImageChef.Core.Devices.Dumping
switch(dev.Type)
{
case DeviceType.MMC:
Statistics.AddMedia(CommonTypes.MediaType.MMC, true);
Statistics.AddMedia(MediaType.MMC, true);
break;
case DeviceType.SecureDigital:
Statistics.AddMedia(CommonTypes.MediaType.SecureDigital, true);
Statistics.AddMedia(MediaType.SecureDigital, true);
break;
}
}