public void Test() { foreach(PartitionTest test in Tests) { string testFile = test.TestFile; Environment.CurrentDirectory = DataFolder; bool exists = File.Exists(testFile); Assert.True(exists, $"{testFile} not found"); // ReSharper disable once ConditionIsAlwaysTrueOrFalse // It arrives here... if(!exists) continue; var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(testFile); Assert.IsNotNull(inputFilter, $"Filter: {testFile}"); IMediaImage image = ImageFormat.Detect(inputFilter); Assert.IsNotNull(image, $"Image format: {testFile}"); Assert.AreEqual(true, image.Open(inputFilter), $"Cannot open image for {testFile}"); List<Partition> partitions = Core.Partitions.GetAll(image); partitions.Should().BeEquivalentTo(test.Partitions, $"Partitions: {testFile}"); } }
public void Test() { Environment.CurrentDirectory = DataFolder; bool exists = File.Exists(TestFile); Assert.True(exists, "Test file not found"); var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(TestFile); Assert.IsNotNull(inputFilter, "Filter for test file is not detected"); IMediaImage image = ImageFormat.Detect(inputFilter); Assert.IsNotNull(image, "Image format for test file is not detected"); Assert.AreEqual(true, image.Open(inputFilter), "Cannot open image for test file"); var opticalInput = image as IOpticalMediaImage; Assert.IsNotNull(opticalInput, "Image format for test file is not for an optical disc"); var ctx = new Crc32Context(); Checksum trackChecksum = null; ulong previousTrackEnd = 0; List <Track> inputTracks = opticalInput.Tracks; foreach (Track currentTrack in inputTracks) { ulong sectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector + 1; ulong doneSectors = 0; while (doneSectors < sectors) { byte[] sector; if (sectors - doneSectors >= SECTORS_TO_READ) { sector = opticalInput.ReadSectors(doneSectors, SECTORS_TO_READ, currentTrack.TrackSequence); doneSectors += SECTORS_TO_READ; } else { sector = opticalInput.ReadSectors(doneSectors, (uint)(sectors - doneSectors), currentTrack.TrackSequence); doneSectors += sectors - doneSectors; } ctx.Update(sector); } previousTrackEnd = currentTrack.TrackEndSector; } }
internal static void GetImageInfo(ImageInfoOptions options) { DicConsole.DebugWriteLine("Analyze command", "--debug={0}", options.Debug); DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", options.Verbose); DicConsole.DebugWriteLine("Analyze command", "--input={0}", options.InputFile); FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(options.InputFile); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return; } try { IMediaImage imageFormat = ImageFormat.Detect(inputFilter); if (imageFormat == null) { DicConsole.WriteLine("Image format not identified."); return; } DicConsole.WriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); DicConsole.WriteLine(); try { if (!imageFormat.Open(inputFilter)) { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); return; } Core.ImageInfo.PrintImageInfo(imageFormat); Core.Statistics.AddMediaFormat(imageFormat.Format); Core.Statistics.AddMedia(imageFormat.Info.MediaType, false); Core.Statistics.AddFilter(inputFilter.Name); } catch (Exception ex) { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.DebugWriteLine("Image-info command", "Stack trace: {0}", ex.StackTrace); } } catch (Exception ex) { DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); DicConsole.DebugWriteLine("Image-info command", ex.StackTrace); } Core.Statistics.AddCommand("image-info"); }
internal static void DoPrintHex(PrintHexOptions options) { DicConsole.DebugWriteLine("PrintHex command", "--debug={0}", options.Debug); DicConsole.DebugWriteLine("PrintHex command", "--verbose={0}", options.Verbose); DicConsole.DebugWriteLine("PrintHex command", "--input={0}", options.InputFile); DicConsole.DebugWriteLine("PrintHex command", "--start={0}", options.StartSector); DicConsole.DebugWriteLine("PrintHex command", "--length={0}", options.Length); DicConsole.DebugWriteLine("PrintHex command", "--long-sectors={0}", options.LongSectors); DicConsole.DebugWriteLine("PrintHex command", "--WidthBytes={0}", options.WidthBytes); FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(options.InputFile); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return; } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying"); return; } inputFormat.Open(inputFilter); for (ulong i = 0; i < options.Length; i++) { DicConsole.WriteLine("Sector {0}", options.StartSector + i); if (inputFormat.Info.ReadableSectorTags == null) { DicConsole .WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data."); options.LongSectors = false; } else { if (inputFormat.Info.ReadableSectorTags.Count == 0) { DicConsole .WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data."); options.LongSectors = false; } } byte[] sector = options.LongSectors ? inputFormat.ReadSectorLong(options.StartSector + i) : inputFormat.ReadSector(options.StartSector + i); DiscImageChef.PrintHex.PrintHexArray(sector, options.WidthBytes); } Core.Statistics.AddCommand("print-hex"); }
public void Test() { Environment.CurrentDirectory = DataFolder; bool exists = File.Exists(TestFile); Assert.True(exists, "Test file not found"); var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(TestFile); Assert.IsNotNull(inputFilter, "Filter for test file is not detected"); IMediaImage image = ImageFormat.Detect(inputFilter); Assert.IsNotNull(image, "Image format for test file is not detected"); Assert.AreEqual(true, image.Open(inputFilter), "Cannot open image for test file"); ulong doneSectors = 0; var ctx = new Crc32Context(); while (doneSectors < image.Info.Sectors) { byte[] sector; if (image.Info.Sectors - doneSectors >= SECTORS_TO_READ) { sector = image.ReadSectors(doneSectors, SECTORS_TO_READ); doneSectors += SECTORS_TO_READ; } else { sector = image.ReadSectors(doneSectors, (uint)(image.Info.Sectors - doneSectors)); doneSectors += image.Info.Sectors - doneSectors; } ctx.Update(sector); } }
public static int Invoke(bool debug, bool verbose, bool adler32, bool crc16, bool crc32, bool crc64, bool fletcher16, bool fletcher32, bool md5, bool sha1, bool sha256, bool sha384, bool sha512, bool spamSum, string imagePath, bool separatedTracks, bool wholeDisc) { MainClass.PrintCopyright(); if (debug) { AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("checksum"); AaruConsole.DebugWriteLine("Checksum command", "--adler32={0}", adler32); AaruConsole.DebugWriteLine("Checksum command", "--crc16={0}", crc16); AaruConsole.DebugWriteLine("Checksum command", "--crc32={0}", crc32); AaruConsole.DebugWriteLine("Checksum command", "--crc64={0}", crc64); AaruConsole.DebugWriteLine("Checksum command", "--debug={0}", debug); AaruConsole.DebugWriteLine("Checksum command", "--fletcher16={0}", fletcher16); AaruConsole.DebugWriteLine("Checksum command", "--fletcher32={0}", fletcher32); AaruConsole.DebugWriteLine("Checksum command", "--input={0}", imagePath); AaruConsole.DebugWriteLine("Checksum command", "--md5={0}", md5); AaruConsole.DebugWriteLine("Checksum command", "--separated-tracks={0}", separatedTracks); AaruConsole.DebugWriteLine("Checksum command", "--sha1={0}", sha1); AaruConsole.DebugWriteLine("Checksum command", "--sha256={0}", sha256); AaruConsole.DebugWriteLine("Checksum command", "--sha384={0}", sha384); AaruConsole.DebugWriteLine("Checksum command", "--sha512={0}", sha512); AaruConsole.DebugWriteLine("Checksum command", "--spamsum={0}", spamSum); AaruConsole.DebugWriteLine("Checksum command", "--verbose={0}", verbose); AaruConsole.DebugWriteLine("Checksum command", "--whole-disc={0}", wholeDisc); var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(imagePath); if (inputFilter == null) { AaruConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { AaruConsole.ErrorWriteLine("Unable to recognize image format, not checksumming"); return((int)ErrorNumber.UnrecognizedFormat); } inputFormat.Open(inputFilter); Statistics.AddMediaFormat(inputFormat.Format); Statistics.AddMedia(inputFormat.Info.MediaType, false); Statistics.AddFilter(inputFilter.Name); var enabledChecksums = new EnableChecksum(); if (adler32) { enabledChecksums |= EnableChecksum.Adler32; } if (crc16) { enabledChecksums |= EnableChecksum.Crc16; } if (crc32) { enabledChecksums |= EnableChecksum.Crc32; } if (crc64) { enabledChecksums |= EnableChecksum.Crc64; } if (md5) { enabledChecksums |= EnableChecksum.Md5; } if (sha1) { enabledChecksums |= EnableChecksum.Sha1; } if (sha256) { enabledChecksums |= EnableChecksum.Sha256; } if (sha384) { enabledChecksums |= EnableChecksum.Sha384; } if (sha512) { enabledChecksums |= EnableChecksum.Sha512; } if (spamSum) { enabledChecksums |= EnableChecksum.SpamSum; } if (fletcher16) { enabledChecksums |= EnableChecksum.Fletcher16; } if (fletcher32) { enabledChecksums |= EnableChecksum.Fletcher32; } Checksum mediaChecksum = null; switch (inputFormat) { case IOpticalMediaImage opticalInput when opticalInput.Tracks != null: try { Checksum trackChecksum = null; if (wholeDisc) { mediaChecksum = new Checksum(enabledChecksums); } ulong previousTrackEnd = 0; List <Track> inputTracks = opticalInput.Tracks; foreach (Track currentTrack in inputTracks) { /* * if(currentTrack.TrackStartSector - previousTrackEnd != 0 && wholeDisc) * for(ulong i = previousTrackEnd + 1; i < currentTrack.TrackStartSector; i++) * { * AaruConsole.Write("\rHashing track-less sector {0}", i); * * byte[] hiddenSector = inputFormat.ReadSector(i); * * mediaChecksum?.Update(hiddenSector); * } */ AaruConsole.DebugWriteLine("Checksum command", "Track {0} starts at sector {1} and ends at sector {2}", currentTrack.TrackSequence, currentTrack.TrackStartSector, currentTrack.TrackEndSector); if (separatedTracks) { trackChecksum = new Checksum(enabledChecksums); } ulong sectors = (currentTrack.TrackEndSector - currentTrack.TrackStartSector) + 1; ulong doneSectors = 0; AaruConsole.WriteLine("Track {0} has {1} sectors", currentTrack.TrackSequence, sectors); while (doneSectors < sectors) { byte[] sector; if (sectors - doneSectors >= SECTORS_TO_READ) { sector = opticalInput.ReadSectors(doneSectors, SECTORS_TO_READ, currentTrack.TrackSequence); AaruConsole.Write("\rHashing sectors {0} to {2} of track {1}", doneSectors, currentTrack.TrackSequence, doneSectors + SECTORS_TO_READ); doneSectors += SECTORS_TO_READ; } else { sector = opticalInput.ReadSectors(doneSectors, (uint)(sectors - doneSectors), currentTrack.TrackSequence); AaruConsole.Write("\rHashing sectors {0} to {2} of track {1}", doneSectors, currentTrack.TrackSequence, doneSectors + (sectors - doneSectors)); doneSectors += sectors - doneSectors; } if (wholeDisc) { mediaChecksum?.Update(sector); } if (separatedTracks) { trackChecksum?.Update(sector); } } AaruConsole.WriteLine(); if (separatedTracks) { if (trackChecksum != null) { foreach (ChecksumType chk in trackChecksum.End()) { AaruConsole.WriteLine("Track {0}'s {1}: {2}", currentTrack.TrackSequence, chk.type, chk.Value); } } } previousTrackEnd = currentTrack.TrackEndSector; } /* * if(opticalInput.Info.Sectors - previousTrackEnd != 0 && wholeDisc) * for(ulong i = previousTrackEnd + 1; i < opticalInput.Info.Sectors; i++) * { * AaruConsole.Write("\rHashing track-less sector {0}", i); * * byte[] hiddenSector = inputFormat.ReadSector(i); * mediaChecksum?.Update(hiddenSector); * } */ if (wholeDisc) { if (mediaChecksum != null) { foreach (ChecksumType chk in mediaChecksum.End()) { AaruConsole.WriteLine("Disk's {0}: {1}", chk.type, chk.Value); } } } } catch (Exception ex) { if (debug) { AaruConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message); } else { AaruConsole.WriteLine("Unable to get separate tracks, not checksumming them"); } } break; case ITapeImage tapeImage when tapeImage.IsTape && tapeImage.Files?.Count > 0: { Checksum trackChecksum = null; if (wholeDisc) { mediaChecksum = new Checksum(enabledChecksums); } ulong previousTrackEnd = 0; foreach (TapeFile currentFile in tapeImage.Files) { if (currentFile.FirstBlock - previousTrackEnd != 0 && wholeDisc) { for (ulong i = previousTrackEnd + 1; i < currentFile.FirstBlock; i++) { AaruConsole.Write("\rHashing file-less block {0}", i); byte[] hiddenSector = inputFormat.ReadSector(i); mediaChecksum?.Update(hiddenSector); } } AaruConsole.DebugWriteLine("Checksum command", "Track {0} starts at sector {1} and ends at block {2}", currentFile.File, currentFile.FirstBlock, currentFile.LastBlock); if (separatedTracks) { trackChecksum = new Checksum(enabledChecksums); } ulong sectors = (currentFile.LastBlock - currentFile.FirstBlock) + 1; ulong doneSectors = 0; AaruConsole.WriteLine("File {0} has {1} sectors", currentFile.File, sectors); while (doneSectors < sectors) { byte[] sector; if (sectors - doneSectors >= SECTORS_TO_READ) { sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock, SECTORS_TO_READ); AaruConsole.Write("\rHashing blocks {0} to {2} of file {1}", doneSectors, currentFile.File, doneSectors + SECTORS_TO_READ); doneSectors += SECTORS_TO_READ; } else { sector = tapeImage.ReadSectors(doneSectors + currentFile.FirstBlock, (uint)(sectors - doneSectors)); AaruConsole.Write("\rHashing blocks {0} to {2} of file {1}", doneSectors, currentFile.File, doneSectors + (sectors - doneSectors)); doneSectors += sectors - doneSectors; } if (wholeDisc) { mediaChecksum?.Update(sector); } if (separatedTracks) { trackChecksum?.Update(sector); } } AaruConsole.WriteLine(); if (separatedTracks) { if (trackChecksum != null) { foreach (ChecksumType chk in trackChecksum.End()) { AaruConsole.WriteLine("File {0}'s {1}: {2}", currentFile.File, chk.type, chk.Value); } } } previousTrackEnd = currentFile.LastBlock; } if (tapeImage.Info.Sectors - previousTrackEnd != 0 && wholeDisc) { for (ulong i = previousTrackEnd + 1; i < tapeImage.Info.Sectors; i++) { AaruConsole.Write("\rHashing file-less sector {0}", i); byte[] hiddenSector = inputFormat.ReadSector(i); mediaChecksum?.Update(hiddenSector); } } if (wholeDisc) { if (mediaChecksum != null) { foreach (ChecksumType chk in mediaChecksum.End()) { AaruConsole.WriteLine("Tape's {0}: {1}", chk.type, chk.Value); } } } break; } default: { mediaChecksum = new Checksum(enabledChecksums); ulong sectors = inputFormat.Info.Sectors; AaruConsole.WriteLine("Sectors {0}", sectors); ulong doneSectors = 0; while (doneSectors < sectors) { byte[] sector; if (sectors - doneSectors >= SECTORS_TO_READ) { sector = inputFormat.ReadSectors(doneSectors, SECTORS_TO_READ); AaruConsole.Write("\rHashing sectors {0} to {1}", doneSectors, doneSectors + SECTORS_TO_READ); doneSectors += SECTORS_TO_READ; } else { sector = inputFormat.ReadSectors(doneSectors, (uint)(sectors - doneSectors)); AaruConsole.Write("\rHashing sectors {0} to {1}", doneSectors, doneSectors + (sectors - doneSectors)); doneSectors += sectors - doneSectors; } mediaChecksum.Update(sector); } AaruConsole.WriteLine(); foreach (ChecksumType chk in mediaChecksum.End()) { AaruConsole.WriteLine("Disk's {0}: {1}", chk.type, chk.Value); } break; } } return((int)ErrorNumber.NoError); }
public void Test() { Environment.CurrentDirectory = DataFolder; var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(TestFile); Dictionary <string, string> options = ParsedOptions; options["debug"] = Debug.ToString(); Assert.IsNotNull(inputFilter, "Cannot open specified file."); Encoding encodingClass = null; if (Encoding != null) { encodingClass = Claunia.Encoding.Encoding.GetEncoding(Encoding); } PluginBase plugins = GetPluginBase.Instance; IMediaImage imageFormat = ImageFormat.Detect(inputFilter); Assert.NotNull(imageFormat, "Image format not identified, not proceeding with analysis."); Assert.True(imageFormat.Open(inputFilter), "Unable to open image format"); List <Partition> partitions = Core.Partitions.GetAll(imageFormat); if (partitions.Count == 0) { Assert.IsFalse(ExpectPartitions, "No partitions found"); partitions.Add(new Partition { Description = "Whole device", Length = imageFormat.Info.Sectors, Offset = 0, Size = imageFormat.Info.SectorSize * imageFormat.Info.Sectors, Sequence = 1, Start = 0 }); } bool filesystemFound = false; Assert.AreEqual(ExpectedData.Partitions.Length, partitions.Count, $"Excepted {ExpectedData.Partitions.Length} partitions but found {partitions.Count}"); for (int i = 0; i < partitions.Count; i++) { Core.Filesystems.Identify(imageFormat, out List <string> idPlugins, partitions[i]); if (idPlugins.Count == 0) { Assert.IsNull(ExpectedData.Partitions[i], $"Expected no filesystems identified in partition {i} but found {idPlugins.Count}"); continue; } if (ExpectedData.Partitions[i].Volumes is null) { continue; } Assert.AreEqual(ExpectedData.Partitions[i].Volumes.Length, idPlugins.Count, $"Expected {ExpectedData.Partitions[i].Volumes.Length} filesystems identified in partition {i} but found {idPlugins.Count}"); for (int j = 0; j < idPlugins.Count; j++) { string pluginName = idPlugins[j]; if (!plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out IReadOnlyFilesystem plugin)) { continue; } Assert.IsNotNull(plugin, "Could not instantiate filesystem plugin"); var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] {}); Assert.IsNotNull(fs, $"Could not instantiate filesystem {pluginName}"); filesystemFound = true; Errno error = fs.Mount(imageFormat, partitions[i], encodingClass, options, Namespace); Assert.AreEqual(Errno.NoError, error, $"Could not mount {pluginName} in partition {i}."); Assert.AreEqual(ExpectedData.Partitions[i].Volumes[j].VolumeName, fs.XmlFsType.VolumeName, $"Excepted volume name \"{ExpectedData.Partitions[i].Volumes[j].VolumeName}\" for filesystem {j} in partition {i} but found \"{fs.XmlFsType.VolumeName}\""); VolumeData volumeData = ExpectedData.Partitions[i].Volumes[j]; ExtractFilesInDir("/", fs, Xattrs, volumeData); volumeData.Directories.Should().BeEmpty("Expected directories not found:", volumeData.Directories); volumeData.Files.Should().BeEmpty("Expected files not found:", volumeData.Files.Keys); } } Assert.IsTrue(filesystemFound, "No filesystems found."); }
/// <summary>Dumps a MultiMediaCard or SecureDigital flash card</summary> void SecureDigital() { if (_dumpRaw) { if (_force) { ErrorMessage?. Invoke("Raw dumping is not supported in MultiMediaCard or SecureDigital devices. Continuing..."); } else { StoppingErrorMessage?. Invoke("Raw dumping is not supported in MultiMediaCard or SecureDigital devices. Aborting..."); return; } } bool sense; const ushort sdProfile = 0x0001; const uint timeout = 5; double duration; uint blocksToRead = 1; uint blockSize = 512; ulong blocks = 0; byte[] csd = null; byte[] ocr = null; byte[] ecsd = null; byte[] scr = null; uint physicalBlockSize = 0; bool byteAddressed = true; uint[] response; Dictionary <MediaTagType, byte[]> mediaTags = new Dictionary <MediaTagType, byte[]>(); switch (_dev.Type) { case DeviceType.MMC: { UpdateStatus?.Invoke("Reading Extended CSD"); _dumpLog.WriteLine("Reading Extended CSD"); sense = _dev.ReadExtendedCsd(out ecsd, out response, timeout, out duration); 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; } // Supposing it's high-capacity MMC if it has Extended CSD... byteAddressed = false; mediaTags.Add(MediaTagType.MMC_ExtendedCSD, null); } else { _errorLog?.WriteLine("Read eCSD", _dev.Error, _dev.LastError, response); ecsd = null; } UpdateStatus?.Invoke("Reading CSD"); _dumpLog.WriteLine("Reading CSD"); sense = _dev.ReadCsd(out csd, out response, timeout, out duration); if (!sense) { 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); } mediaTags.Add(MediaTagType.MMC_CSD, null); } else { _errorLog?.WriteLine("Read CSD", _dev.Error, _dev.LastError, response); csd = null; } UpdateStatus?.Invoke("Reading OCR"); _dumpLog.WriteLine("Reading OCR"); sense = _dev.ReadOcr(out ocr, out response, timeout, out duration); if (sense) { _errorLog?.WriteLine("Read OCR", _dev.Error, _dev.LastError, response); ocr = null; } else { mediaTags.Add(MediaTagType.MMC_OCR, null); } break; } case DeviceType.SecureDigital: { UpdateStatus?.Invoke("Reading CSD"); _dumpLog.WriteLine("Reading CSD"); sense = _dev.ReadCsd(out csd, out response, timeout, out duration); 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); 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 { _errorLog?.WriteLine("Read CSD", _dev.Error, _dev.LastError, response); csd = null; } UpdateStatus?.Invoke("Reading OCR"); _dumpLog.WriteLine("Reading OCR"); sense = _dev.ReadSdocr(out ocr, out response, timeout, out duration); if (sense) { _errorLog?.WriteLine("Read OCR", _dev.Error, _dev.LastError, response); ocr = null; } else { mediaTags.Add(MediaTagType.SD_OCR, null); } UpdateStatus?.Invoke("Reading SCR"); _dumpLog.WriteLine("Reading SCR"); sense = _dev.ReadScr(out scr, out response, timeout, out duration); if (sense) { _errorLog?.WriteLine("Read SCR", _dev.Error, _dev.LastError, response); scr = null; } else { mediaTags.Add(MediaTagType.SD_SCR, null); } break; } } UpdateStatus?.Invoke("Reading CID"); _dumpLog.WriteLine("Reading CID"); sense = _dev.ReadCid(out byte[] cid, out response, timeout, out duration); if (sense) { _errorLog?.WriteLine("Read CID", _dev.Error, _dev.LastError, response); cid = null; } else { mediaTags.Add(_dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID : MediaTagType.MMC_CID, null); } DateTime start; DateTime end; double totalDuration = 0; double currentSpeed = 0; double maxSpeed = double.MinValue; double minSpeed = double.MaxValue; if (blocks == 0) { _dumpLog.WriteLine("Unable to get device size."); StoppingErrorMessage?.Invoke("Unable to get device size."); return; } UpdateStatus?.Invoke($"Device reports {blocks} blocks."); _dumpLog.WriteLine("Device reports {0} blocks.", blocks); byte[] cmdBuf; bool error; while (true) { error = _dev.Read(out cmdBuf, out _, 0, blockSize, blocksToRead, byteAddressed, timeout, out duration); if (error) { blocksToRead /= 2; } if (!error || blocksToRead == 1) { break; } } if (error) { _dumpLog.WriteLine("ERROR: Cannot get blocks to read, device error {0}.", _dev.LastError); StoppingErrorMessage?.Invoke($"Device error {_dev.LastError} trying to guess ideal transfer length."); return; } UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time."); _dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead); if (_skip < blocksToRead) { _skip = blocksToRead; } 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, _dev.FirmwareRevision, _private); if (currentTry == null || extents == null) { StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); return; } bool ret = true; foreach (MediaTagType tag in mediaTags.Keys.Where(tag => !_outputPlugin.SupportedMediaTags.Contains(tag))) { ret = false; _dumpLog.WriteLine($"Output format does not support {tag}."); ErrorMessage?.Invoke($"Output format does not support {tag}."); } if (!ret) { if (_force) { _dumpLog.WriteLine("Several media tags not supported, continuing..."); ErrorMessage?.Invoke("Several media tags not supported, continuing..."); } else { _dumpLog.WriteLine("Several media tags not supported, not continuing..."); StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing..."); return; } } var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private); var ibgLog = new IbgLog(_outputPrefix + ".ibg", sdProfile); 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); StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + _outputPlugin.ErrorMessage); return; } if (_resume.NextBlock > 0) { UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}."); _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); } start = DateTime.UtcNow; double imageWriteDuration = 0; bool newTrim = false; DateTime timeSpeedStart = DateTime.UtcNow; ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for (ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); break; } if (blocks - i < blocksToRead) { blocksToRead = (byte)(blocks - i); } if (currentSpeed > maxSpeed && currentSpeed > 0) { maxSpeed = currentSpeed; } if (currentSpeed < minSpeed && currentSpeed > 0) { minSpeed = currentSpeed; } UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, (long)blocks); error = _dev.Read(out cmdBuf, out response, (uint)i, blockSize, blocksToRead, byteAddressed, timeout, out duration); if (!error) { mhddLog.Write(i, duration); ibgLog.Write(i, currentSpeed * 1024); DateTime writeStart = DateTime.Now; _outputPlugin.WriteSectors(cmdBuf, i, blocksToRead); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; extents.Add(i, blocksToRead, true); } else { _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, byteAddressed, response); if (i + _skip > blocks) { _skip = (uint)(blocks - i); } for (ulong b = i; b < i + _skip; b++) { _resume.BadBlocks.Add(b); } mhddLog.Write(i, duration < 500 ? 65535 : duration); ibgLog.Write(i, 0); DateTime writeStart = DateTime.Now; _outputPlugin.WriteSectors(new byte[blockSize * _skip], i, _skip); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); i += _skip - blocksToRead; newTrim = true; } sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; if (elapsed < 1) { continue; } currentSpeed = (sectorSpeedStart * blockSize) / (1048576 * elapsed); sectorSpeedStart = 0; timeSpeedStart = DateTime.UtcNow; } end = DateTime.Now; EndProgress?.Invoke(); mhddLog.Close(); ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000), _devicePath); UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); UpdateStatus?. Invoke($"Average dump speed {((double)blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000):F3} KiB/sec."); UpdateStatus?. Invoke($"Average write speed {((double)blockSize * (double)(blocks + 1)) / 1024 / imageWriteDuration:F3} KiB/sec."); _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 write speed {0:F3} KiB/sec.", ((double)blockSize * (double)(blocks + 1)) / 1024 / imageWriteDuration); #region Trimming if (_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { start = DateTime.UtcNow; UpdateStatus?.Invoke("Trimming skipped sectors"); _dumpLog.WriteLine("Trimming skipped sectors"); ulong[] tmpArray = _resume.BadBlocks.ToArray(); InitProgress?.Invoke(); foreach (ulong badSector in tmpArray) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); break; } PulseProgress?.Invoke($"Trimming sector {badSector}"); error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout, out duration); totalDuration += duration; if (error) { _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, byteAddressed, response); continue; } _resume.BadBlocks.Remove(badSector); extents.Add(badSector); _outputPlugin.WriteSector(cmdBuf, badSector); } EndProgress?.Invoke(); end = DateTime.UtcNow; UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds."); _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); } #endregion Trimming #region Error handling if (_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) { int pass = 1; bool forward = true; bool runningPersistent = false; InitProgress?.Invoke(); repeatRetryLba: ulong[] tmpArray = _resume.BadBlocks.ToArray(); foreach (ulong badSector in tmpArray) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); break; } PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "")); error = _dev.Read(out cmdBuf, out response, (uint)badSector, blockSize, 1, byteAddressed, timeout, out duration); totalDuration += duration; if (error) { _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, byteAddressed, response); } if (!error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); _outputPlugin.WriteSector(cmdBuf, badSector); UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); } else if (runningPersistent) { _outputPlugin.WriteSector(cmdBuf, badSector); } } if (pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); if (!forward) { _resume.BadBlocks.Reverse(); } goto repeatRetryLba; } EndProgress?.Invoke(); } #endregion Error handling currentTry.Extents = ExtentsConverter.ToMetadata(extents); _outputPlugin.SetDumpHardware(_resume.Tries); // TODO: Drive info var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; if (!_outputPlugin.SetMetadata(metadata)) { ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + _outputPlugin.ErrorMessage); } if (_preSidecar != null) { _outputPlugin.SetCicmMetadata(_preSidecar); } _dumpLog.WriteLine("Closing output file."); UpdateStatus?.Invoke("Closing output file."); DateTime closeStart = DateTime.Now; _outputPlugin.Close(); DateTime closeEnd = DateTime.Now; UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); if (_aborted) { UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); return; } double totalChkDuration = 0; if (_metadata) { UpdateStatus?.Invoke("Creating sidecar."); _dumpLog.WriteLine("Creating sidecar."); var filters = new FiltersList(); IFilter filter = filters.GetFilter(_outputPath); IMediaImage inputPlugin = ImageFormat.Detect(filter); if (!inputPlugin.Open(filter)) { StoppingErrorMessage?.Invoke("Could not open created image."); } DateTime chkStart = DateTime.UtcNow; _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); _sidecarClass.InitProgressEvent += InitProgress; _sidecarClass.UpdateProgressEvent += UpdateProgress; _sidecarClass.EndProgressEvent += EndProgress; _sidecarClass.InitProgressEvent2 += InitProgress2; _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; CICMMetadataType sidecar = _sidecarClass.Create(); if (_preSidecar != null) { _preSidecar.BlockMedia = sidecar.BlockMedia; sidecar = _preSidecar; } switch (_dev.Type) { case DeviceType.MMC: sidecar.BlockMedia[0].MultiMediaCard = new MultiMediaCardType(); break; case DeviceType.SecureDigital: sidecar.BlockMedia[0].SecureDigital = new SecureDigitalType(); break; } DumpType cidDump = null; DumpType csdDump = null; DumpType ocrDump = null; if (cid != null) { if (_dev.Type == DeviceType.SecureDigital && _private) { // Clear serial number and manufacturing date cid[9] = 0; cid[10] = 0; cid[11] = 0; cid[12] = 0; cid[13] = 0; cid[14] = 0; } else if (_dev.Type == DeviceType.MMC && _private) { // Clear serial number and manufacturing date cid[10] = 0; cid[11] = 0; cid[12] = 0; cid[13] = 0; cid[14] = 0; } cidDump = new DumpType { Image = _outputPath, Size = (ulong)cid.Length, Checksums = Checksum.GetChecksums(cid).ToArray() }; ret = _outputPlugin.WriteMediaTag(cid, _dev.Type == DeviceType.SecureDigital ? MediaTagType.SD_CID : MediaTagType.MMC_CID); // Cannot write CID to image if (!ret && !_force) { _dumpLog.WriteLine("Cannot write CID to output image."); StoppingErrorMessage?.Invoke("Cannot write CID to output image." + Environment.NewLine + _outputPlugin.ErrorMessage); return; } } if (csd != null) { csdDump = new DumpType { Image = _outputPath, Size = (ulong)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."); StoppingErrorMessage?.Invoke("Cannot write CSD to output image." + Environment.NewLine + _outputPlugin.ErrorMessage); return; } } if (ecsd != null) { sidecar.BlockMedia[0].MultiMediaCard.ExtendedCSD = new DumpType { Image = _outputPath, Size = (ulong)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."); StoppingErrorMessage?.Invoke("Cannot write Extended CSD to output image." + Environment.NewLine + _outputPlugin.ErrorMessage); return; } } if (ocr != null) { ocrDump = new DumpType { Image = _outputPath, Size = (ulong)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."); StoppingErrorMessage?.Invoke("Cannot write OCR to output image." + Environment.NewLine + _outputPlugin.ErrorMessage); return; } } if (scr != null) { sidecar.BlockMedia[0].SecureDigital.SCR = new DumpType { Image = _outputPath, Size = (ulong)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."); StoppingErrorMessage?.Invoke("Cannot write SCR to output image." + Environment.NewLine + _outputPlugin.ErrorMessage); return; } } 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; UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds."); UpdateStatus?. Invoke($"Average checksum speed {((double)blockSize * (double)(blocks + 1)) / 1024 / (totalChkDuration / 1000):F3} KiB/sec."); _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 type, string subType)xmlType = (null, null); switch (_dev.Type) { case DeviceType.MMC: xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.MMC); sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(MediaType.MMC); break; case DeviceType.SecureDigital: CommonTypes.Metadata.MediaType.MediaTypeToString(MediaType.SecureDigital); sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(MediaType.SecureDigital); break; } sidecar.BlockMedia[0].DiskType = xmlType.type; sidecar.BlockMedia[0].DiskSubType = xmlType.subType; // TODO: Implement device firmware revision sidecar.BlockMedia[0].LogicalBlocks = blocks; sidecar.BlockMedia[0].PhysicalBlockSize = physicalBlockSize > 0 ? physicalBlockSize : blockSize; sidecar.BlockMedia[0].LogicalBlockSize = blockSize; sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer; sidecar.BlockMedia[0].Model = _dev.Model; if (!_private) { sidecar.BlockMedia[0].Serial = _dev.Serial; } sidecar.BlockMedia[0].Size = blocks * blockSize; UpdateStatus?.Invoke("Writing metadata sidecar"); var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); } UpdateStatus?.Invoke(""); UpdateStatus?. Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); UpdateStatus?. Invoke($"Average speed: {((double)blockSize * (double)(blocks + 1)) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); if (maxSpeed > 0) { UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); } if (minSpeed > 0 && minSpeed < double.MaxValue) { UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); } UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); UpdateStatus?.Invoke(""); if (_resume.BadBlocks.Count > 0) { _resume.BadBlocks.Sort(); } switch (_dev.Type) { case DeviceType.MMC: Statistics.AddMedia(MediaType.MMC, true); break; case DeviceType.SecureDigital: Statistics.AddMedia(MediaType.SecureDigital, true); break; } }
/// <summary> /// Dumps an ATA device /// </summary> /// <param name="dev">Device</param> /// <param name="devicePath">Path to the device</param> /// <param name="outputPrefix">Prefix for output log 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 sectors</param> /// <param name="persistent">Store whatever data the drive returned on error</param> /// <param name="stopOnError">Stop dump on first error</param> /// <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="InvalidOperationException">If the resume file is invalid</exception> 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, CICMMetadataType preSidecar, uint skip, bool nometadata, bool notrim) { bool aborted; if (dumpRaw) { DicConsole.ErrorWriteLine("Raw dumping not yet supported in ATA devices."); if (force) { DicConsole.ErrorWriteLine("Continuing..."); } else { DicConsole.ErrorWriteLine("Aborting..."); return; } } bool sense; const ushort ATA_PROFILE = 0x0001; const uint TIMEOUT = 5; double imageWriteDuration = 0; dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE."); sense = dev.AtaIdentify(out byte[] cmdBuf, out _); if (!sense && Identify.Decode(cmdBuf).HasValue) { Identify.IdentifyDevice?ataIdNullable = Identify.Decode(cmdBuf); if (ataIdNullable != null) { Identify.IdentifyDevice ataId = ataIdNullable.Value; byte[] ataIdentify = cmdBuf; cmdBuf = new byte[0]; DateTime start; DateTime end; double totalDuration = 0; double currentSpeed = 0; double maxSpeed = double.MinValue; double minSpeed = double.MaxValue; aborted = false; System.Console.CancelKeyPress += (sender, e) => e.Cancel = aborted = true; // Initializate reader dumpLog.WriteLine("Initializing reader."); Reader ataReader = new Reader(dev, TIMEOUT, ataIdentify); // Fill reader blocks ulong blocks = ataReader.GetDeviceBlocks(); // Check block sizes if (ataReader.GetBlockSize()) { dumpLog.WriteLine("ERROR: Cannot get block size: {0}.", ataReader.ErrorMessage); DicConsole.ErrorWriteLine(ataReader.ErrorMessage); return; } uint blockSize = ataReader.LogicalBlockSize; uint physicalsectorsize = ataReader.PhysicalBlockSize; if (ataReader.FindReadCommand()) { dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", ataReader.ErrorMessage); DicConsole.ErrorWriteLine(ataReader.ErrorMessage); return; } // Check how many blocks to read, if error show and return if (ataReader.GetBlocksToRead()) { dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", ataReader.ErrorMessage); 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 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 = !dev.IsCompactFlash && ataId.GeneralConfiguration.HasFlag(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); if (currentTry == null || extents == null) { throw new InvalidOperationException("Could not process resume file, not continuing..."); } MhddLog mhddLog; IbgLog ibgLog; double duration; bool ret = true; if (dev.IsUsb && dev.UsbDescriptors != null && !outputPlugin.SupportedMediaTags.Contains(MediaTagType.USB_Descriptors)) { ret = false; dumpLog.WriteLine("Output format does not support USB descriptors."); DicConsole.ErrorWriteLine("Output format does not support USB descriptors."); } if (dev.IsPcmcia && dev.Cis != null && !outputPlugin.SupportedMediaTags.Contains(MediaTagType.PCMCIA_CIS)) { ret = false; dumpLog.WriteLine("Output format does not support PCMCIA CIS descriptors."); DicConsole.ErrorWriteLine("Output format does not support PCMCIA CIS descriptors."); } if (!outputPlugin.SupportedMediaTags.Contains(MediaTagType.ATA_IDENTIFY)) { ret = false; dumpLog.WriteLine("Output format does not support ATA IDENTIFY."); DicConsole.ErrorWriteLine("Output format does not support ATA IDENTIFY."); } 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; } } ret = outputPlugin.Create(outputPath, dev.IsCompactFlash ? MediaType.CompactFlash : MediaType.GENERIC_HDD, 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; } // Setting geometry outputPlugin.SetGeometry(cylinders, heads, sectors); if (ataReader.IsLba) { DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); if (skip < blocksToRead) { skip = blocksToRead; } mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead); ibgLog = new IbgLog(outputPrefix + ".ibg", ATA_PROFILE); if (resume.NextBlock > 0) { dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock); } bool newTrim = false; start = DateTime.UtcNow; for (ulong i = resume.NextBlock; i < blocks; i += blocksToRead) { if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } 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; } #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); bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration); if (!error) { mhddLog.Write(i, duration); ibgLog.Write(i, currentSpeed * 1024); DateTime writeStart = DateTime.Now; outputPlugin.WriteSectors(cmdBuf, i, blocksToRead); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; extents.Add(i, blocksToRead, true); } else { if (i + skip > blocks) { skip = (uint)(blocks - i); } for (ulong b = i; b < i + skip; b++) { resume.BadBlocks.Add(b); } mhddLog.Write(i, duration < 500 ? 65535 : duration); ibgLog.Write(i, 0); DateTime writeStart = DateTime.Now; outputPlugin.WriteSectors(new byte[blockSize * skip], i, skip); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i); i += skip - blocksToRead; newTrim = true; } double newSpeed = (double)blockSize * blocksToRead / 1048576 / (duration / 1000); if (!double.IsInfinity(newSpeed)) { currentSpeed = newSpeed; } 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); dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", (double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", (double)blockSize * (double)(blocks + 1) / 1024 / imageWriteDuration); #region Trimming if (resume.BadBlocks.Count > 0 && !aborted && !notrim && newTrim) { start = DateTime.UtcNow; dumpLog.WriteLine("Trimming bad sectors"); ulong[] tmpArray = resume.BadBlocks.ToArray(); foreach (ulong badSector in tmpArray) { if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } DicConsole.Write("\rTrimming sector {0}", badSector); bool error = ataReader.ReadBlock(out cmdBuf, badSector, out duration); totalDuration += duration; if (error) { continue; } resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputPlugin.WriteSector(cmdBuf, badSector); } DicConsole.WriteLine(); end = DateTime.UtcNow; dumpLog.WriteLine("Trimmming finished in {0} seconds.", (end - start).TotalSeconds); } #endregion Trimming #region Error handling if (resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0) { int pass = 1; bool forward = true; repeatRetryLba: ulong[] tmpArray = resume.BadBlocks.ToArray(); foreach (ulong badSector in tmpArray) { if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass, forward ? "forward" : "reverse", persistent ? "recovering partial data, " : ""); bool error = ataReader.ReadBlock(out cmdBuf, badSector, out duration); totalDuration += duration; if (!error) { resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputPlugin.WriteSector(cmdBuf, badSector); dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); } else if (persistent) { outputPlugin.WriteSector(cmdBuf, badSector); } } if (pass < retryPasses && !aborted && resume.BadBlocks.Count > 0) { pass++; forward = !forward; resume.BadBlocks.Sort(); resume.BadBlocks.Reverse(); goto repeatRetryLba; } DicConsole.WriteLine(); } #endregion Error handling LBA currentTry.Extents = ExtentsConverter.ToMetadata(extents); } else { mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead); ibgLog = new IbgLog(outputPrefix + ".ibg", ATA_PROFILE); ulong currentBlock = 0; blocks = (ulong)(cylinders * heads * sectors); start = DateTime.UtcNow; for (ushort cy = 0; cy < cylinders; cy++) { for (byte hd = 0; hd < heads; hd++) { for (byte sc = 1; sc < sectors; sc++) { if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } #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 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); totalDuration += duration; if (!error) { mhddLog.Write(currentBlock, duration); ibgLog.Write(currentBlock, currentSpeed * 1024); DateTime writeStart = DateTime.Now; outputPlugin.WriteSector(cmdBuf, (ulong)((cy * heads + hd) * sectors + (sc - 1))); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; extents.Add(currentBlock); dumpLog.WriteLine("Error reading cylinder {0} head {1} sector {2}.", cy, hd, sc); } else { resume.BadBlocks.Add(currentBlock); mhddLog.Write(currentBlock, duration < 500 ? 65535 : duration); ibgLog.Write(currentBlock, 0); DateTime writeStart = DateTime.Now; outputPlugin.WriteSector(new byte[blockSize], (ulong)((cy * heads + hd) * sectors + (sc - 1))); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; } double newSpeed = blockSize / (double)1048576 / (duration / 1000); if (!double.IsInfinity(newSpeed)) { currentSpeed = newSpeed; } currentBlock++; } } } 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); dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", (double)blockSize * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", (double)blockSize * (double)(blocks + 1) / 1024 / (imageWriteDuration / 1000)); } foreach (ulong bad in resume.BadBlocks) { dumpLog.WriteLine("Sector {0} could not be read.", bad); } outputPlugin.SetDumpHardware(resume.Tries); if (preSidecar != null) { outputPlugin.SetCicmMetadata(preSidecar); } dumpLog.WriteLine("Closing output file."); DicConsole.WriteLine("Closing output file."); DateTime closeStart = DateTime.Now; outputPlugin.Close(); DateTime closeEnd = DateTime.Now; dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); if (aborted) { dumpLog.WriteLine("Aborted!"); return; } double totalChkDuration = 0; if (!nometadata) { 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."); } DateTime chkStart = DateTime.UtcNow; CICMMetadataType sidecar = Sidecar.Create(inputPlugin, outputPath, filter.Id, encoding); if (preSidecar != null) { preSidecar.BlockMedia = sidecar.BlockMedia; sidecar = preSidecar; } if (dev.IsUsb) { dumpLog.WriteLine("Reading USB descriptors."); ret = outputPlugin.WriteMediaTag(dev.UsbDescriptors, MediaTagType.USB_Descriptors); if (ret) { sidecar.BlockMedia[0].USB = new USBType { ProductID = dev.UsbProductId, VendorID = dev.UsbVendorId, Descriptors = new DumpType { Image = outputPath, Size = dev.UsbDescriptors.Length, Checksums = Checksum.GetChecksums(dev.UsbDescriptors).ToArray() } } } ; } if (dev.IsPcmcia) { dumpLog.WriteLine("Reading PCMCIA CIS."); ret = outputPlugin.WriteMediaTag(dev.Cis, MediaTagType.PCMCIA_CIS); if (ret) { sidecar.BlockMedia[0].PCMCIA = new PCMCIAType { CIS = new DumpType { Image = outputPath, Size = dev.Cis.Length, Checksums = Checksum.GetChecksums(dev.Cis).ToArray() } } } ; dumpLog.WriteLine("Decoding PCMCIA CIS."); Tuple[] tuples = CIS.GetTuples(dev.Cis); if (tuples != null) { foreach (Tuple tuple in tuples) { switch (tuple.Code) { case TupleCodes.CISTPL_MANFID: ManufacturerIdentificationTuple manfid = CIS.DecodeManufacturerIdentificationTuple(tuple); if (manfid != null) { sidecar.BlockMedia[0].PCMCIA.ManufacturerCode = manfid.ManufacturerID; sidecar.BlockMedia[0].PCMCIA.CardCode = manfid.CardID; sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true; sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true; } break; case TupleCodes.CISTPL_VERS_1: Level1VersionTuple vers = CIS.DecodeLevel1VersionTuple(tuple); if (vers != null) { sidecar.BlockMedia[0].PCMCIA.Manufacturer = vers.Manufacturer; sidecar.BlockMedia[0].PCMCIA.ProductName = vers.Product; sidecar.BlockMedia[0].PCMCIA.Compliance = $"{vers.MajorVersion}.{vers.MinorVersion}"; sidecar.BlockMedia[0].PCMCIA.AdditionalInformation = vers.AdditionalInformation; } break; } } } } ret = outputPlugin.WriteMediaTag(ataIdentify, MediaTagType.ATA_IDENTIFY); if (ret) { sidecar.BlockMedia[0].ATA = new ATAType { Identify = new DumpType { Image = outputPath, Size = cmdBuf.Length, Checksums = Checksum.GetChecksums(cmdBuf).ToArray() } } } ; DateTime chkEnd = DateTime.UtcNow; totalChkDuration = (chkEnd - chkStart).TotalMilliseconds; dumpLog.WriteLine("Sidecar created in {0} seconds.", (chkEnd - chkStart).TotalSeconds); dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", (double)blockSize * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); List <(ulong start, string type)> filesystems = new List <(ulong start, string type)>(); if (sidecar.BlockMedia[0].FileSystemInformation != null) { filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation where partition.FileSystems != null from fileSystem in partition.FileSystems select((ulong)partition.StartSector, fileSystem.Type)); } if (filesystems.Count > 0) { foreach (var filesystem in filesystems.Select(o => new { o.start, o.type }).Distinct()) { dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); } } DicConsole.WriteLine(); string xmlDskTyp, xmlDskSubTyp; if (dev.IsCompactFlash) { 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); } sidecar.BlockMedia[0].DiskType = xmlDskTyp; sidecar.BlockMedia[0].DiskSubType = xmlDskSubTyp; sidecar.BlockMedia[0].Interface = "ATA"; sidecar.BlockMedia[0].LogicalBlocks = (long)blocks; sidecar.BlockMedia[0].PhysicalBlockSize = (int)physicalsectorsize; 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 (cylinders > 0 && heads > 0 && sectors > 0) { sidecar.BlockMedia[0].Cylinders = cylinders; sidecar.BlockMedia[0].CylindersSpecified = true; sidecar.BlockMedia[0].Heads = heads; sidecar.BlockMedia[0].HeadsSpecified = true; sidecar.BlockMedia[0].SectorsPerTrack = sectors; sidecar.BlockMedia[0].SectorsPerTrackSpecified = true; } DicConsole.WriteLine("Writing metadata sidecar"); FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create); XmlSerializer xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); } DicConsole.WriteLine(); DicConsole .WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).", (end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000, imageWriteDuration, (closeEnd - closeStart).TotalSeconds); 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(); } DicConsole.WriteLine(); } if (dev.IsCompactFlash) { Statistics.AddMedia(MediaType.CompactFlash, true); } else if (dev.IsPcmcia) { Statistics.AddMedia(MediaType.PCCardTypeI, true); } else { Statistics.AddMedia(MediaType.GENERIC_HDD, true); } } else { DicConsole.ErrorWriteLine("Unable to communicate with ATA device."); } } } }
public static int Invoke(bool verbose, bool debug, bool diskTags, string imagePath, string length, bool sectorTags, ulong startSector) { MainClass.PrintCopyright(); if (debug) { AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("decode"); AaruConsole.DebugWriteLine("Decode command", "--debug={0}", debug); AaruConsole.DebugWriteLine("Decode command", "--disk-tags={0}", diskTags); AaruConsole.DebugWriteLine("Decode command", "--input={0}", imagePath); AaruConsole.DebugWriteLine("Decode command", "--length={0}", length); AaruConsole.DebugWriteLine("Decode command", "--sector-tags={0}", sectorTags); AaruConsole.DebugWriteLine("Decode command", "--start={0}", startSector); AaruConsole.DebugWriteLine("Decode command", "--verbose={0}", verbose); var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(imagePath); if (inputFilter == null) { AaruConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { AaruConsole.ErrorWriteLine("Unable to recognize image format, not decoding"); return((int)ErrorNumber.UnrecognizedFormat); } inputFormat.Open(inputFilter); Statistics.AddMediaFormat(inputFormat.Format); Statistics.AddMedia(inputFormat.Info.MediaType, false); Statistics.AddFilter(inputFilter.Name); if (diskTags) { if (inputFormat.Info.ReadableMediaTags.Count == 0) { AaruConsole.WriteLine("There are no disk tags in chosen disc image."); } else { foreach (MediaTagType tag in inputFormat.Info.ReadableMediaTags) { switch (tag) { case MediaTagType.SCSI_INQUIRY: { byte[] inquiry = inputFormat.ReadDiskTag(MediaTagType.SCSI_INQUIRY); if (inquiry == null) { AaruConsole.WriteLine("Error reading SCSI INQUIRY response from disc image"); } else { AaruConsole.WriteLine("SCSI INQUIRY command response:"); AaruConsole. WriteLine("================================================================================"); AaruConsole.WriteLine(Inquiry.Prettify(inquiry)); AaruConsole. WriteLine("================================================================================"); } break; } case MediaTagType.ATA_IDENTIFY: { byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATA_IDENTIFY); if (identify == null) { AaruConsole.WriteLine("Error reading ATA IDENTIFY DEVICE response from disc image"); } else { AaruConsole.WriteLine("ATA IDENTIFY DEVICE command response:"); AaruConsole. WriteLine("================================================================================"); AaruConsole.WriteLine(Identify.Prettify(identify)); AaruConsole. WriteLine("================================================================================"); } break; } case MediaTagType.ATAPI_IDENTIFY: { byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY); if (identify == null) { AaruConsole. WriteLine("Error reading ATA IDENTIFY PACKET DEVICE response from disc image"); } else { AaruConsole.WriteLine("ATA IDENTIFY PACKET DEVICE command response:"); AaruConsole. WriteLine("================================================================================"); AaruConsole.WriteLine(Identify.Prettify(identify)); AaruConsole. WriteLine("================================================================================"); } break; } case MediaTagType.CD_ATIP: { byte[] atip = inputFormat.ReadDiskTag(MediaTagType.CD_ATIP); if (atip == null) { AaruConsole.WriteLine("Error reading CD ATIP from disc image"); } else { AaruConsole.WriteLine("CD ATIP:"); AaruConsole. WriteLine("================================================================================"); AaruConsole.WriteLine(ATIP.Prettify(atip)); AaruConsole. WriteLine("================================================================================"); } break; } case MediaTagType.CD_FullTOC: { byte[] fullToc = inputFormat.ReadDiskTag(MediaTagType.CD_FullTOC); if (fullToc == null) { AaruConsole.WriteLine("Error reading CD full TOC from disc image"); } else { AaruConsole.WriteLine("CD full TOC:"); AaruConsole. WriteLine("================================================================================"); AaruConsole.WriteLine(FullTOC.Prettify(fullToc)); AaruConsole. WriteLine("================================================================================"); } break; } case MediaTagType.CD_PMA: { byte[] pma = inputFormat.ReadDiskTag(MediaTagType.CD_PMA); if (pma == null) { AaruConsole.WriteLine("Error reading CD PMA from disc image"); } else { AaruConsole.WriteLine("CD PMA:"); AaruConsole. WriteLine("================================================================================"); AaruConsole.WriteLine(PMA.Prettify(pma)); AaruConsole. WriteLine("================================================================================"); } break; } case MediaTagType.CD_SessionInfo: { byte[] sessionInfo = inputFormat.ReadDiskTag(MediaTagType.CD_SessionInfo); if (sessionInfo == null) { AaruConsole.WriteLine("Error reading CD session information from disc image"); } else { AaruConsole.WriteLine("CD session information:"); AaruConsole. WriteLine("================================================================================"); AaruConsole.WriteLine(Session.Prettify(sessionInfo)); AaruConsole. WriteLine("================================================================================"); } break; } case MediaTagType.CD_TEXT: { byte[] cdText = inputFormat.ReadDiskTag(MediaTagType.CD_TEXT); if (cdText == null) { AaruConsole.WriteLine("Error reading CD-TEXT from disc image"); } else { AaruConsole.WriteLine("CD-TEXT:"); AaruConsole. WriteLine("================================================================================"); AaruConsole.WriteLine(CDTextOnLeadIn.Prettify(cdText)); AaruConsole. WriteLine("================================================================================"); } break; } case MediaTagType.CD_TOC: { byte[] toc = inputFormat.ReadDiskTag(MediaTagType.CD_TOC); if (toc == null) { AaruConsole.WriteLine("Error reading CD TOC from disc image"); } else { AaruConsole.WriteLine("CD TOC:"); AaruConsole. WriteLine("================================================================================"); AaruConsole.WriteLine(TOC.Prettify(toc)); AaruConsole. WriteLine("================================================================================"); } break; } default: AaruConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.", tag); break; } } } } if (sectorTags) { if (length.ToLowerInvariant() == "all") { } else { if (!ulong.TryParse(length, out ulong _)) { AaruConsole.WriteLine("Value \"{0}\" is not a valid number for length.", length); AaruConsole.WriteLine("Not decoding sectors tags"); return(3); } } if (inputFormat.Info.ReadableSectorTags.Count == 0) { AaruConsole.WriteLine("There are no sector tags in chosen disc image."); } else { foreach (SectorTagType tag in inputFormat.Info.ReadableSectorTags) { switch (tag) { default: AaruConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.", tag); break; } } } // TODO: Not implemented } return((int)ErrorNumber.NoError); }
public static int Invoke(bool debug, bool verbose, bool duplicatedSectors, string imagePath, bool separatedTracks, bool wholeDisc) { MainClass.PrintCopyright(); if (debug) { AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("entropy"); AaruConsole.DebugWriteLine("Entropy command", "--debug={0}", debug); AaruConsole.DebugWriteLine("Entropy command", "--duplicated-sectors={0}", duplicatedSectors); AaruConsole.DebugWriteLine("Entropy command", "--input={0}", imagePath); AaruConsole.DebugWriteLine("Entropy command", "--separated-tracks={0}", separatedTracks); AaruConsole.DebugWriteLine("Entropy command", "--verbose={0}", verbose); AaruConsole.DebugWriteLine("Entropy command", "--whole-disc={0}", wholeDisc); var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(imagePath); if (inputFilter == null) { AaruConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { AaruConsole.ErrorWriteLine("Unable to recognize image format, not checksumming"); return((int)ErrorNumber.UnrecognizedFormat); } inputFormat.Open(inputFilter); Statistics.AddMediaFormat(inputFormat.Format); Statistics.AddMedia(inputFormat.Info.MediaType, false); Statistics.AddFilter(inputFilter.Name); var entropyCalculator = new Entropy(debug, inputFormat); entropyCalculator.InitProgressEvent += Progress.InitProgress; entropyCalculator.InitProgress2Event += Progress.InitProgress2; entropyCalculator.UpdateProgressEvent += Progress.UpdateProgress; entropyCalculator.UpdateProgress2Event += Progress.UpdateProgress2; entropyCalculator.EndProgressEvent += Progress.EndProgress; entropyCalculator.EndProgress2Event += Progress.EndProgress2; if (separatedTracks) { EntropyResults[] tracksEntropy = entropyCalculator.CalculateTracksEntropy(duplicatedSectors); foreach (EntropyResults trackEntropy in tracksEntropy) { AaruConsole.WriteLine("Entropy for track {0} is {1:F4}.", trackEntropy.Track, trackEntropy.Entropy); if (trackEntropy.UniqueSectors != null) { AaruConsole.WriteLine("Track {0} has {1} unique sectors ({2:P3})", trackEntropy.Track, trackEntropy.UniqueSectors, (double)trackEntropy.UniqueSectors / (double)trackEntropy.Sectors); } } } if (!wholeDisc) { return((int)ErrorNumber.NoError); } EntropyResults entropy = entropyCalculator.CalculateMediaEntropy(duplicatedSectors); AaruConsole.WriteLine("Entropy for disk is {0:F4}.", entropy.Entropy); if (entropy.UniqueSectors != null) { AaruConsole.WriteLine("Disk has {0} unique sectors ({1:P3})", entropy.UniqueSectors, (double)entropy.UniqueSectors / (double)entropy.Sectors); } return((int)ErrorNumber.NoError); }
public override int Invoke(IEnumerable <string> arguments) { List <string> extra = Options.Parse(arguments); if (showHelp) { Options.WriteOptionDescriptions(CommandSet.Out); return((int)ErrorNumber.HelpRequested); } MainClass.PrintCopyright(); if (MainClass.Debug) { DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (MainClass.Verbose) { DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("analyze"); if (extra.Count > 1) { DicConsole.ErrorWriteLine("Too many arguments."); return((int)ErrorNumber.UnexpectedArgumentCount); } if (extra.Count == 0) { DicConsole.ErrorWriteLine("Missing input image."); return((int)ErrorNumber.MissingArgument); } inputFile = extra[0]; DicConsole.DebugWriteLine("Analyze command", "--debug={0}", MainClass.Debug); DicConsole.DebugWriteLine("Analyze command", "--encoding={0}", encodingName); DicConsole.DebugWriteLine("Analyze command", "--filesystems={0}", searchForFilesystems); DicConsole.DebugWriteLine("Analyze command", "--input={0}", inputFile); DicConsole.DebugWriteLine("Analyze command", "--partitions={0}", searchForPartitions); DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", MainClass.Verbose); FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(inputFile); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } Encoding encoding = null; if (encodingName != null) { try { encoding = Claunia.Encoding.Encoding.GetEncoding(encodingName); if (MainClass.Verbose) { DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); } } catch (ArgumentException) { DicConsole.ErrorWriteLine("Specified encoding is not supported."); return((int)ErrorNumber.EncodingUnknown); } } PluginBase plugins = GetPluginBase.Instance; bool checkraw = false; try { IMediaImage imageFormat = ImageFormat.Detect(inputFilter); if (imageFormat == null) { DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); return((int)ErrorNumber.UnrecognizedFormat); } if (MainClass.Verbose) { DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); } else { DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); } DicConsole.WriteLine(); try { if (!imageFormat.Open(inputFilter)) { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); return((int)ErrorNumber.CannotOpenFormat); } if (MainClass.Verbose) { ImageInfo.PrintImageInfo(imageFormat); DicConsole.WriteLine(); } Statistics.AddMediaFormat(imageFormat.Format); Statistics.AddMedia(imageFormat.Info.MediaType, false); Statistics.AddFilter(inputFilter.Name); } catch (Exception ex) { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.DebugWriteLine("Analyze command", "Stack trace: {0}", ex.StackTrace); return((int)ErrorNumber.CannotOpenFormat); } List <string> idPlugins; IFilesystem plugin; string information; if (searchForPartitions) { List <Partition> partitions = Core.Partitions.GetAll(imageFormat); Core.Partitions.AddSchemesToStats(partitions); if (partitions.Count == 0) { DicConsole.DebugWriteLine("Analyze command", "No partitions found"); if (!searchForFilesystems) { DicConsole.WriteLine("No partitions founds, not searching for filesystems"); return((int)ErrorNumber.NothingFound); } checkraw = true; } else { DicConsole.WriteLine("{0} partitions found.", partitions.Count); for (int i = 0; i < partitions.Count; i++) { DicConsole.WriteLine(); DicConsole.WriteLine("Partition {0}:", partitions[i].Sequence); DicConsole.WriteLine("Partition name: {0}", partitions[i].Name); DicConsole.WriteLine("Partition type: {0}", partitions[i].Type); DicConsole.WriteLine("Partition start: sector {0}, byte {1}", partitions[i].Start, partitions[i].Offset); DicConsole.WriteLine("Partition length: {0} sectors, {1} bytes", partitions[i].Length, partitions[i].Size); DicConsole.WriteLine("Partition scheme: {0}", partitions[i].Scheme); DicConsole.WriteLine("Partition description:"); DicConsole.WriteLine(partitions[i].Description); if (!searchForFilesystems) { continue; } DicConsole.WriteLine("Identifying filesystem on partition"); Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]); if (idPlugins.Count == 0) { DicConsole.WriteLine("Filesystem not identified"); } else if (idPlugins.Count > 1) { DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); foreach (string pluginName in idPlugins) { if (plugins.PluginsList.TryGetValue(pluginName, out plugin)) { DicConsole.WriteLine($"As identified by {plugin.Name}."); plugin.GetInformation(imageFormat, partitions[i], out information, encoding); DicConsole.Write(information); Statistics.AddFilesystem(plugin.XmlFsType.Type); } } } else { plugins.PluginsList.TryGetValue(idPlugins[0], out plugin); if (plugin == null) { continue; } DicConsole.WriteLine($"Identified by {plugin.Name}."); plugin.GetInformation(imageFormat, partitions[i], out information, encoding); DicConsole.Write("{0}", information); Statistics.AddFilesystem(plugin.XmlFsType.Type); } } } } if (checkraw) { Partition wholePart = new Partition { Name = "Whole device", Length = imageFormat.Info.Sectors, Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize }; Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart); if (idPlugins.Count == 0) { DicConsole.WriteLine("Filesystem not identified"); } else if (idPlugins.Count > 1) { DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); foreach (string pluginName in idPlugins) { if (plugins.PluginsList.TryGetValue(pluginName, out plugin)) { DicConsole.WriteLine($"As identified by {plugin.Name}."); plugin.GetInformation(imageFormat, wholePart, out information, encoding); DicConsole.Write(information); Statistics.AddFilesystem(plugin.XmlFsType.Type); } } } else { plugins.PluginsList.TryGetValue(idPlugins[0], out plugin); if (plugin != null) { DicConsole.WriteLine($"Identified by {plugin.Name}."); plugin.GetInformation(imageFormat, wholePart, out information, encoding); DicConsole.Write(information); Statistics.AddFilesystem(plugin.XmlFsType.Type); } } } } catch (Exception ex) { DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); DicConsole.DebugWriteLine("Analyze command", ex.StackTrace); return((int)ErrorNumber.UnexpectedException); } return((int)ErrorNumber.NoError); }
public static int Invoke(bool debug, bool verbose, string imagePath) { MainClass.PrintCopyright(); if (debug) { AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("image-info"); AaruConsole.DebugWriteLine("Analyze command", "--debug={0}", debug); AaruConsole.DebugWriteLine("Analyze command", "--input={0}", imagePath); AaruConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose); var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(imagePath); if (inputFilter == null) { AaruConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } try { IMediaImage imageFormat = ImageFormat.Detect(inputFilter); if (imageFormat == null) { AaruConsole.WriteLine("Image format not identified."); return((int)ErrorNumber.UnrecognizedFormat); } AaruConsole.WriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); AaruConsole.WriteLine(); try { if (!imageFormat.Open(inputFilter)) { AaruConsole.WriteLine("Unable to open image format"); AaruConsole.WriteLine("No error given"); return((int)ErrorNumber.CannotOpenFormat); } ImageInfo.PrintImageInfo(imageFormat); Statistics.AddMediaFormat(imageFormat.Format); Statistics.AddMedia(imageFormat.Info.MediaType, false); Statistics.AddFilter(inputFilter.Name); } catch (Exception ex) { AaruConsole.ErrorWriteLine("Unable to open image format"); AaruConsole.ErrorWriteLine("Error: {0}", ex.Message); AaruConsole.DebugWriteLine("Image-info command", "Stack trace: {0}", ex.StackTrace); return((int)ErrorNumber.CannotOpenFormat); } } catch (Exception ex) { AaruConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); AaruConsole.DebugWriteLine("Image-info command", ex.StackTrace); return((int)ErrorNumber.UnexpectedException); } return((int)ErrorNumber.NoError); }
/// <summary> /// Dumps an Xbox Game Disc using a Kreon drive /// </summary> /// <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 raw/long sectors</param> /// <param name="persistent">Store whatever data the drive returned on error</param> /// <param name="stopOnError">Stop dump on first error</param> /// <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="mediaTags">Media tags as retrieved in MMC layer</param> /// <param name="dskType">Disc type as detected in MMC layer</param> /// <param name="outputPath">Path to output file</param> /// <param name="formatOptions">Formats to pass to output file plugin</param> /// <exception cref="InvalidOperationException"> /// If the provided resume does not correspond with the current in progress /// dump /// </exception> internal static void Dump(Device dev, string devicePath, IWritableImage outputPlugin, ushort retryPasses, bool force, bool dumpRaw, bool persistent, bool stopOnError, Dictionary <MediaTagType, byte[]> mediaTags, ref MediaType dskType, ref Resume resume, ref DumpLog dumpLog, Encoding encoding, string outputPrefix, string outputPath, Dictionary <string, string> formatOptions, CICMMetadataType preSidecar, uint skip, bool nometadata, bool notrim) { bool sense; ulong blocks; const uint BLOCK_SIZE = 2048; uint blocksToRead = 64; DateTime start; DateTime end; double totalDuration = 0; double currentSpeed = 0; double maxSpeed = double.MinValue; double minSpeed = double.MaxValue; bool aborted = false; System.Console.CancelKeyPress += (sender, e) => e.Cancel = aborted = true; if (mediaTags.ContainsKey(MediaTagType.DVD_PFI)) { mediaTags.Remove(MediaTagType.DVD_PFI); } if (mediaTags.ContainsKey(MediaTagType.DVD_DMI)) { mediaTags.Remove(MediaTagType.DVD_DMI); } dumpLog.WriteLine("Reading Xbox Security Sector."); sense = dev.KreonExtractSs(out byte[] ssBuf, out byte[] senseBuf, dev.Timeout, out _); if (sense) { dumpLog.WriteLine("Cannot get Xbox Security Sector, not continuing."); DicConsole.ErrorWriteLine("Cannot get Xbox Security Sector, not continuing."); return; } dumpLog.WriteLine("Decoding Xbox Security Sector."); SS.SecuritySector?xboxSs = SS.Decode(ssBuf); if (!xboxSs.HasValue) { dumpLog.WriteLine("Cannot decode Xbox Security Sector, not continuing."); DicConsole.ErrorWriteLine("Cannot decode Xbox Security Sector, not continuing."); return; } byte[] tmpBuf = new byte[ssBuf.Length - 4]; Array.Copy(ssBuf, 4, tmpBuf, 0, ssBuf.Length - 4); mediaTags.Add(MediaTagType.Xbox_SecuritySector, tmpBuf); ulong l0Video, l1Video, middleZone, gameSize, totalSize, layerBreak; // Get video partition size DicConsole.DebugWriteLine("Dump-media command", "Getting video partition size"); dumpLog.WriteLine("Locking drive."); sense = dev.KreonLock(out senseBuf, dev.Timeout, out _); if (sense) { dumpLog.WriteLine("Cannot lock drive, not continuing."); 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 _); if (sense) { dumpLog.WriteLine("Cannot get disc capacity."); 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 _); 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); mediaTags.Add(MediaTagType.DVD_PFI, tmpBuf); DicConsole.DebugWriteLine("Dump-media command", "Video partition total size: {0} sectors", totalSize); l0Video = PFI.Decode(readBuffer).Value.Layer0EndPSN - 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 _); 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); mediaTags.Add(MediaTagType.DVD_DMI, tmpBuf); // Get game partition size DicConsole.DebugWriteLine("Dump-media command", "Getting game partition size"); dumpLog.WriteLine("Unlocking drive (Xtreme)."); sense = dev.KreonUnlockXtreme(out senseBuf, dev.Timeout, out _); if (sense) { dumpLog.WriteLine("Cannot unlock drive, not continuing."); DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing."); return; } dumpLog.WriteLine("Getting game partition size."); sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out _); if (sense) { dumpLog.WriteLine("Cannot get disc capacity."); DicConsole.ErrorWriteLine("Cannot get disc capacity."); return; } 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 DicConsole.DebugWriteLine("Dump-media command", "Getting middle zone size"); dumpLog.WriteLine("Unlocking drive (Wxripper)."); sense = dev.KreonUnlockWxripper(out senseBuf, dev.Timeout, out _); if (sense) { dumpLog.WriteLine("Cannot unlock drive, not continuing."); DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing."); return; } dumpLog.WriteLine("Getting disc size."); sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out _); if (sense) { dumpLog.WriteLine("Cannot get disc capacity."); 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 _); 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 - (PFI.Decode(readBuffer).Value.Layer0EndPSN - PFI.Decode(readBuffer).Value.DataAreaStartPSN + 1) - gameSize + 1; tmpBuf = new byte[readBuffer.Length - 4]; Array.Copy(readBuffer, 4, tmpBuf, 0, readBuffer.Length - 4); mediaTags.Add(MediaTagType.Xbox_PFI, tmpBuf); dumpLog.WriteLine("Reading Disc Manufacturing Information."); sense = dev.ReadDiscStructure(out readBuffer, out senseBuf, MmcDiscStructureMediaType.Dvd, 0, 0, MmcDiscStructureFormat.DiscManufacturingInformation, 0, 0, out _); 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); mediaTags.Add(MediaTagType.Xbox_DMI, tmpBuf); totalSize = l0Video + l1Video + middleZone * 2 + gameSize; layerBreak = l0Video + middleZone + gameSize / 2; DicConsole.WriteLine("Video layer 0 size: {0} sectors", l0Video); DicConsole.WriteLine("Video layer 1 size: {0} sectors", l1Video); DicConsole.WriteLine("Middle zone size: {0} sectors", middleZone); DicConsole.WriteLine("Game data size: {0} sectors", gameSize); DicConsole.WriteLine("Total size: {0} sectors", totalSize); DicConsole.WriteLine("Real layer break: {0}", layerBreak); DicConsole.WriteLine(); dumpLog.WriteLine("Video layer 0 size: {0} sectors", l0Video); dumpLog.WriteLine("Video layer 1 size: {0} sectors", l1Video); dumpLog.WriteLine("Middle zone 0 size: {0} sectors", middleZone); dumpLog.WriteLine("Game data 0 size: {0} sectors", gameSize); 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, BLOCK_SIZE, 0, 1, false, dev.Timeout, out _); if (!read12) { dumpLog.WriteLine("Cannot read medium, aborting scan..."); DicConsole.ErrorWriteLine("Cannot read medium, aborting scan..."); return; } dumpLog.WriteLine("Using SCSI READ (12) command."); DicConsole.WriteLine("Using SCSI READ (12) command."); while (true) { if (read12) { sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, 0, BLOCK_SIZE, 0, blocksToRead, false, dev.Timeout, out _); if (sense || dev.Error) { blocksToRead /= 2; } } if (!dev.Error || blocksToRead == 1) { break; } } if (dev.Error) { dumpLog.WriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError); DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError); return; } if (skip < blocksToRead) { skip = blocksToRead; } 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; } } dumpLog.WriteLine("Reading {0} sectors at a time.", blocksToRead); DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); MhddLog mhddLog = new MhddLog(outputPrefix + ".mhddlog.bin", dev, blocks, BLOCK_SIZE, blocksToRead); IbgLog ibgLog = new IbgLog(outputPrefix + ".ibg", 0x0010); ret = outputPlugin.Create(outputPath, dskType, formatOptions, blocks, BLOCK_SIZE); // 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; } start = DateTime.UtcNow; double imageWriteDuration = 0; double cmdDuration = 0; 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); if (currentTry == null || extents == null) { throw new NotImplementedException("Could not process resume file, not continuing..."); } outputPlugin.SetTracks(new List <Track> { new Track { TrackBytesPerSector = (int)BLOCK_SIZE, TrackEndSector = blocks - 1, TrackSequence = 1, TrackRawBytesPerSector = (int)BLOCK_SIZE, TrackSubchannelType = TrackSubchannelType.None, TrackSession = 1, TrackType = TrackType.Data } }); ulong currentSector = resume.NextBlock; if (resume.NextBlock > 0) { dumpLog.WriteLine("Resuming from block {0}.", resume.NextBlock); } bool newTrim = false; dumpLog.WriteLine("Reading game partition."); for (int e = 0; e <= 16; e++) { if (aborted) { resume.NextBlock = currentSector; currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } if (currentSector >= blocks) { break; } ulong extentStart, extentEnd; // Extents if (e < 16) { 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; } 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; } } // After last extent else { extentStart = blocks; extentEnd = blocks; } if (currentSector > extentEnd) { continue; } for (ulong i = currentSector; i < extentStart; i += blocksToRead) { saveBlocksToRead = blocksToRead; if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } 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; } #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, BLOCK_SIZE, 0, blocksToRead, false, dev.Timeout, out cmdDuration); totalDuration += cmdDuration; if (!sense && !dev.Error) { mhddLog.Write(i, cmdDuration); ibgLog.Write(i, currentSpeed * 1024); DateTime writeStart = DateTime.Now; outputPlugin.WriteSectors(readBuffer, i, blocksToRead); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; extents.Add(i, blocksToRead, true); } else { // TODO: Reset device after X errors if (stopOnError) { return; // TODO: Return more cleanly } if (i + skip > blocks) { skip = (uint)(blocks - i); } // Write empty data DateTime writeStart = DateTime.Now; outputPlugin.WriteSectors(new byte[BLOCK_SIZE * skip], i, skip); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; for (ulong b = i; b < i + skip; b++) { resume.BadBlocks.Add(b); } DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); ibgLog.Write(i, 0); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, i); i += skip - blocksToRead; string[] senseLines = Sense.PrettifySense(senseBuf).Split(new[] { Environment.NewLine }, StringSplitOptions .RemoveEmptyEntries); foreach (string senseLine in senseLines) { dumpLog.WriteLine(senseLine); } newTrim = true; } double newSpeed = (double)BLOCK_SIZE * blocksToRead / 1048576 / (cmdDuration / 1000); if (!double.IsInfinity(newSpeed)) { currentSpeed = newSpeed; } blocksToRead = saveBlocksToRead; currentSector = i + 1; resume.NextBlock = currentSector; } for (ulong i = extentStart; i <= extentEnd; i += blocksToRead) { saveBlocksToRead = blocksToRead; if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } if (extentEnd - i < blocksToRead) { blocksToRead = (uint)(extentEnd - i) + 1; } mhddLog.Write(i, cmdDuration); ibgLog.Write(i, currentSpeed * 1024); // Write empty data DateTime writeStart = DateTime.Now; outputPlugin.WriteSectors(new byte[BLOCK_SIZE * blocksToRead], i, blocksToRead); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; blocksToRead = saveBlocksToRead; extents.Add(i, blocksToRead, true); currentSector = i + 1; resume.NextBlock = currentSector; } if (!aborted) { currentSector = extentEnd + 1; } } // Middle Zone D dumpLog.WriteLine("Writing Middle Zone D (empty)."); for (ulong middle = currentSector - blocks - 1; middle < middleZone - 1; middle += blocksToRead) { if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } 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); mhddLog.Write(middle + currentSector, cmdDuration); ibgLog.Write(middle + currentSector, currentSpeed * 1024); // Write empty data DateTime writeStart = DateTime.Now; outputPlugin.WriteSectors(new byte[BLOCK_SIZE * blocksToRead], middle + currentSector, blocksToRead); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; extents.Add(currentSector, blocksToRead, true); currentSector += blocksToRead; resume.NextBlock = currentSector; } blocksToRead = saveBlocksToRead; dumpLog.WriteLine("Locking drive."); sense = dev.KreonLock(out senseBuf, dev.Timeout, out _); if (sense) { dumpLog.WriteLine("Cannot lock drive, not continuing."); DicConsole.ErrorWriteLine("Cannot lock drive, not continuing."); return; } sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out _); if (sense) { DicConsole.ErrorWriteLine("Cannot get disc capacity."); return; } // Video Layer 1 dumpLog.WriteLine("Reading Video Layer 1."); for (ulong l1 = currentSector - blocks - middleZone + l0Video; l1 < l0Video + l1Video; l1 += blocksToRead) { if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } 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; } #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); sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)l1, BLOCK_SIZE, 0, blocksToRead, false, dev.Timeout, out cmdDuration); totalDuration += cmdDuration; if (!sense && !dev.Error) { mhddLog.Write(currentSector, cmdDuration); ibgLog.Write(currentSector, currentSpeed * 1024); DateTime writeStart = DateTime.Now; outputPlugin.WriteSectors(readBuffer, currentSector, blocksToRead); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; extents.Add(currentSector, blocksToRead, true); } else { // TODO: Reset device after X errors if (stopOnError) { return; // TODO: Return more cleanly } // Write empty data DateTime writeStart = DateTime.Now; outputPlugin.WriteSectors(new byte[BLOCK_SIZE * skip], currentSector, skip); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; // TODO: Handle errors in video partition //errored += blocksToRead; //resume.BadBlocks.Add(l1); DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); mhddLog.Write(l1, cmdDuration < 500 ? 65535 : cmdDuration); ibgLog.Write(l1, 0); dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", skip, l1); l1 += skip - blocksToRead; string[] senseLines = Sense.PrettifySense(senseBuf).Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); foreach (string senseLine in senseLines) { dumpLog.WriteLine(senseLine); } } double newSpeed = (double)BLOCK_SIZE * blocksToRead / 1048576 / (cmdDuration / 1000); if (!double.IsInfinity(newSpeed)) { currentSpeed = newSpeed; } currentSector += blocksToRead; resume.NextBlock = currentSector; } dumpLog.WriteLine("Unlocking drive (Wxripper)."); sense = dev.KreonUnlockWxripper(out senseBuf, dev.Timeout, out _); if (sense) { dumpLog.WriteLine("Cannot unlock drive, not continuing."); DicConsole.ErrorWriteLine("Cannot unlock drive, not continuing."); return; } sense = dev.ReadCapacity(out readBuffer, out senseBuf, dev.Timeout, out _); if (sense) { DicConsole.ErrorWriteLine("Cannot get disc capacity."); return; } end = DateTime.UtcNow; DicConsole.WriteLine(); mhddLog.Close(); ibgLog.Close(dev, blocks, BLOCK_SIZE, (end - start).TotalSeconds, currentSpeed * 1024, BLOCK_SIZE * (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)BLOCK_SIZE * (double)(blocks + 1) / 1024 / (totalDuration / 1000)); dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", (double)BLOCK_SIZE * (double)(blocks + 1) / 1024 / imageWriteDuration); #region Trimming if (resume.BadBlocks.Count > 0 && !aborted && !notrim && newTrim) { start = DateTime.UtcNow; dumpLog.WriteLine("Trimming bad sectors"); ulong[] tmpArray = resume.BadBlocks.ToArray(); foreach (ulong badSector in tmpArray) { if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } DicConsole.Write("\rTrimming sector {0}", badSector); sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)badSector, BLOCK_SIZE, 0, 1, false, dev.Timeout, out cmdDuration); totalDuration += cmdDuration; if (sense || dev.Error) { continue; } resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputPlugin.WriteSector(readBuffer, badSector); } DicConsole.WriteLine(); end = DateTime.UtcNow; dumpLog.WriteLine("Trimmming finished in {0} seconds.", (end - start).TotalSeconds); } #endregion Trimming #region Error handling if (resume.BadBlocks.Count > 0 && !aborted && retryPasses > 0) { List <ulong> tmpList = new List <ulong>(); foreach (ulong ur in resume.BadBlocks) { for (ulong i = ur; i < ur + blocksToRead; i++) { tmpList.Add(i); } } tmpList.Sort(); int pass = 1; bool forward = true; bool runningPersistent = false; resume.BadBlocks = tmpList; Modes.ModePage?currentModePage = null; byte[] md6; byte[] md10; if (persistent) { Modes.ModePage_01_MMC pgMmc; sense = dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, dev.Timeout, out _); if (sense) { sense = dev.ModeSense10(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, dev.Timeout, out _); if (!sense) { Modes.DecodedMode?dcMode10 = Modes.DecodeMode10(readBuffer, PeripheralDeviceTypes.MultiMediaDevice); if (dcMode10.HasValue) { foreach (Modes.ModePage modePage in dcMode10.Value.Pages) { if (modePage.Page == 0x01 && modePage.Subpage == 0x00) { currentModePage = modePage; } } } } } else { Modes.DecodedMode?dcMode6 = Modes.DecodeMode6(readBuffer, PeripheralDeviceTypes.MultiMediaDevice); if (dcMode6.HasValue) { foreach (Modes.ModePage modePage in dcMode6.Value.Pages) { if (modePage.Page == 0x01 && modePage.Subpage == 0x00) { currentModePage = modePage; } } } } if (currentModePage == null) { pgMmc = new Modes.ModePage_01_MMC { PS = false, ReadRetryCount = 0x20, Parameter = 0x00 }; currentModePage = new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01_MMC(pgMmc) }; } pgMmc = new Modes.ModePage_01_MMC { PS = false, ReadRetryCount = 255, Parameter = 0x20 }; Modes.DecodedMode md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), Pages = new[] { new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01_MMC(pgMmc) } } }; md6 = Modes.EncodeMode6(md, dev.ScsiType); md10 = Modes.EncodeMode10(md, dev.ScsiType); dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks)."); sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out _); if (sense) { sense = dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out _); } if (sense) { DicConsole .WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); DicConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf)); dumpLog.WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); } else { runningPersistent = true; } } repeatRetry: ulong[] tmpArray = resume.BadBlocks.ToArray(); foreach (ulong badSector in tmpArray) { if (aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); dumpLog.WriteLine("Aborted!"); break; } DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : ""); sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)badSector, BLOCK_SIZE, 0, 1, false, dev.Timeout, out cmdDuration); totalDuration += cmdDuration; if (!sense && !dev.Error) { resume.BadBlocks.Remove(badSector); extents.Add(badSector); outputPlugin.WriteSector(readBuffer, badSector); dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); } else if (runningPersistent) { outputPlugin.WriteSector(readBuffer, badSector); } } if (pass < retryPasses && !aborted && resume.BadBlocks.Count > 0) { pass++; forward = !forward; resume.BadBlocks.Sort(); resume.BadBlocks.Reverse(); goto repeatRetry; } if (runningPersistent && currentModePage.HasValue) { Modes.DecodedMode md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), Pages = new[] { currentModePage.Value } }; md6 = Modes.EncodeMode6(md, dev.ScsiType); md10 = Modes.EncodeMode10(md, dev.ScsiType); dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status)."); sense = dev.ModeSelect(md6, out senseBuf, true, false, dev.Timeout, out _); if (sense) { dev.ModeSelect10(md10, out senseBuf, true, false, dev.Timeout, out _); } } DicConsole.WriteLine(); } #endregion Error handling resume.BadBlocks.Sort(); currentTry.Extents = ExtentsConverter.ToMetadata(extents); foreach (KeyValuePair <MediaTagType, byte[]> tag in mediaTags) { ret = outputPlugin.WriteMediaTag(tag.Value, tag.Key); if (ret || force) { continue; } // Cannot write tag to image dumpLog.WriteLine($"Cannot write tag {tag.Key}."); throw new ArgumentException(outputPlugin.ErrorMessage); } resume.BadBlocks.Sort(); foreach (ulong bad in resume.BadBlocks) { dumpLog.WriteLine("Sector {0} could not be read.", bad); } currentTry.Extents = ExtentsConverter.ToMetadata(extents); outputPlugin.SetDumpHardware(resume.Tries); if (preSidecar != null) { outputPlugin.SetCicmMetadata(preSidecar); } dumpLog.WriteLine("Closing output file."); DicConsole.WriteLine("Closing output file."); DateTime closeStart = DateTime.Now; outputPlugin.Close(); DateTime closeEnd = DateTime.Now; dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); if (aborted) { dumpLog.WriteLine("Aborted!"); return; } double totalChkDuration = 0; if (!nometadata) { 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."); } DateTime chkStart = DateTime.UtcNow; CICMMetadataType sidecar = Sidecar.Create(inputPlugin, outputPath, filter.Id, encoding); end = DateTime.UtcNow; if (preSidecar != null) { preSidecar.OpticalDisc = sidecar.OpticalDisc; sidecar = preSidecar; } totalChkDuration = (end - chkStart).TotalMilliseconds; dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", (double)BLOCK_SIZE * (double)(blocks + 1) / 1024 / (totalChkDuration / 1000)); foreach (KeyValuePair <MediaTagType, byte[]> tag in mediaTags) { Mmc.AddMediaTagToSidecar(outputPath, tag, ref sidecar); } List <(ulong start, string type)> filesystems = new List <(ulong start, string type)>(); if (sidecar.OpticalDisc[0].Track != null) { filesystems.AddRange(from xmlTrack in sidecar.OpticalDisc[0].Track where xmlTrack.FileSystemInformation != null from partition in xmlTrack.FileSystemInformation where partition.FileSystems != null from fileSystem in partition.FileSystems select((ulong)partition.StartSector, fileSystem.Type)); } if (filesystems.Count > 0) { foreach (var filesystem in filesystems.Select(o => new { o.start, o.type }).Distinct()) { dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); } } sidecar.OpticalDisc[0].Layers = new LayersType { type = LayersTypeType.OTP, typeSpecified = true, Sectors = new SectorsType[1] }; sidecar.OpticalDisc[0].Layers.Sectors[0] = new SectorsType { Value = (long)layerBreak }; sidecar.OpticalDisc[0].Sessions = 1; sidecar.OpticalDisc[0].Dimensions = Dimensions.DimensionsFromMediaType(dskType); Metadata.MediaType.MediaTypeToString(dskType, out string xmlDskTyp, out string xmlDskSubTyp); sidecar.OpticalDisc[0].DiscType = xmlDskTyp; sidecar.OpticalDisc[0].DiscSubType = xmlDskSubTyp; foreach (KeyValuePair <MediaTagType, byte[]> tag in mediaTags) { if (outputPlugin.SupportedMediaTags.Contains(tag.Key)) { Mmc.AddMediaTagToSidecar(outputPath, tag, ref sidecar); } } DicConsole.WriteLine("Writing metadata sidecar"); FileStream xmlFs = new FileStream(outputPrefix + ".cicm.xml", FileMode.Create); XmlSerializer xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); } DicConsole.WriteLine(); DicConsole.WriteLine("Took a total of {0:F3} seconds ({1:F3} processing commands, {2:F3} checksumming, {3:F3} writing, {4:F3} closing).", (end - start).TotalSeconds, totalDuration / 1000, totalChkDuration / 1000, imageWriteDuration, (closeEnd - closeStart).TotalSeconds); DicConsole.WriteLine("Avegare speed: {0:F3} MiB/sec.", (double)BLOCK_SIZE * (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(); Statistics.AddMedia(dskType, true); }
public void Test() { Environment.CurrentDirectory = DataFolder; var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(TestFile); Dictionary <string, string> options = ParsedOptions; options["debug"] = Debug.ToString(); Assert.IsNotNull(inputFilter, "Cannot open specified file."); Encoding encodingClass = null; if (Encoding != null) { encodingClass = Claunia.Encoding.Encoding.GetEncoding(Encoding); } PluginBase plugins = GetPluginBase.Instance; IMediaImage imageFormat = ImageFormat.Detect(inputFilter); Assert.NotNull(imageFormat, "Image format not identified, not proceeding with analysis."); Assert.True(imageFormat.Open(inputFilter), "Unable to open image format"); List <Partition> partitions = Core.Partitions.GetAll(imageFormat); if (partitions.Count == 0) { Assert.IsFalse(ExpectPartitions, "No partitions found"); partitions.Add(new Partition { Description = "Whole device", Length = imageFormat.Info.Sectors, Offset = 0, Size = imageFormat.Info.SectorSize * imageFormat.Info.Sectors, Sequence = 1, Start = 0 }); } bool filesystemFound = false; for (int i = 0; i < partitions.Count; i++) { Core.Filesystems.Identify(imageFormat, out List <string> idPlugins, partitions[i]); if (idPlugins.Count == 0) { continue; } IReadOnlyFilesystem plugin; Errno error; if (idPlugins.Count > 1) { foreach (string pluginName in idPlugins) { if (plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) { Assert.IsNotNull(plugin, "Could not instantiate filesystem plugin"); var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?. Invoke(new object[] {}); Assert.IsNotNull(fs, $"Could not instantiate filesystem {pluginName}"); filesystemFound = true; error = fs.Mount(imageFormat, partitions[i], encodingClass, options, Namespace); Assert.AreEqual(Errno.NoError, error, $"Could not mount {pluginName} in partition {i}."); ExtractFilesInDir("/", fs, Xattrs); } } } else { plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); if (plugin is null) { continue; } var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] {}); Assert.IsNotNull(fs, $"Could not instantiate filesystem {plugin.Name}"); filesystemFound = true; error = fs.Mount(imageFormat, partitions[i], encodingClass, options, Namespace); Assert.AreEqual(Errno.NoError, error, $"Could not mount {plugin.Name} in partition {i}."); ExtractFilesInDir("/", fs, Xattrs); } } Assert.IsTrue(filesystemFound, "No filesystems found."); }
internal static void DoLs(LsOptions options) { DicConsole.DebugWriteLine("Ls command", "--debug={0}", options.Debug); DicConsole.DebugWriteLine("Ls command", "--verbose={0}", options.Verbose); DicConsole.DebugWriteLine("Ls command", "--input={0}", options.InputFile); FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(options.InputFile); Dictionary <string, string> parsedOptions = Options.Parse(options.Options); DicConsole.DebugWriteLine("Ls command", "Parsed options:"); foreach (KeyValuePair <string, string> parsedOption in parsedOptions) { DicConsole.DebugWriteLine("Ls command", "{0} = {1}", parsedOption.Key, parsedOption.Value); } parsedOptions.Add("debug", options.Debug.ToString()); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return; } Encoding encoding = null; if (options.EncodingName != null) { try { encoding = Claunia.Encoding.Encoding.GetEncoding(options.EncodingName); if (options.Verbose) { DicConsole.VerboseWriteLine("Using encoding for {0}.", encoding.EncodingName); } } catch (ArgumentException) { DicConsole.ErrorWriteLine("Specified encoding is not supported."); return; } } PluginBase plugins = new PluginBase(); try { IMediaImage imageFormat = ImageFormat.Detect(inputFilter); if (imageFormat == null) { DicConsole.WriteLine("Image format not identified, not proceeding with analysis."); return; } if (options.Verbose) { DicConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); } else { DicConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); } try { if (!imageFormat.Open(inputFilter)) { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); return; } DicConsole.DebugWriteLine("Ls command", "Correctly opened image file."); DicConsole.DebugWriteLine("Ls command", "Image without headers is {0} bytes.", imageFormat.Info.ImageSize); DicConsole.DebugWriteLine("Ls command", "Image has {0} sectors.", imageFormat.Info.Sectors); DicConsole.DebugWriteLine("Ls command", "Image identifies disk type as {0}.", imageFormat.Info.MediaType); Core.Statistics.AddMediaFormat(imageFormat.Format); Core.Statistics.AddMedia(imageFormat.Info.MediaType, false); Core.Statistics.AddFilter(inputFilter.Name); } catch (Exception ex) { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); return; } List <Partition> partitions = Core.Partitions.GetAll(imageFormat); Core.Partitions.AddSchemesToStats(partitions); List <string> idPlugins; IReadOnlyFilesystem plugin; Errno error; if (partitions.Count == 0) { DicConsole.DebugWriteLine("Ls command", "No partitions found"); } else { DicConsole.WriteLine("{0} partitions found.", partitions.Count); for (int i = 0; i < partitions.Count; i++) { DicConsole.WriteLine(); DicConsole.WriteLine("Partition {0}:", partitions[i].Sequence); DicConsole.WriteLine("Identifying filesystem on partition"); Core.Filesystems.Identify(imageFormat, out idPlugins, partitions[i]); if (idPlugins.Count == 0) { DicConsole.WriteLine("Filesystem not identified"); } else if (idPlugins.Count > 1) { DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); foreach (string pluginName in idPlugins) { if (plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) { DicConsole.WriteLine($"As identified by {plugin.Name}."); IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin .GetType() .GetConstructor(Type.EmptyTypes) ?.Invoke(new object[] { }); if (fs == null) { continue; } error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions); if (error == Errno.NoError) { List <string> rootDir = new List <string>(); error = fs.ReadDir("/", out rootDir); if (error == Errno.NoError) { foreach (string entry in rootDir) { DicConsole.WriteLine("{0}", entry); } } else { DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); } Core.Statistics.AddFilesystem(fs.XmlFsType.Type); } else { DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } else { plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); if (plugin == null) { continue; } DicConsole.WriteLine($"Identified by {plugin.Name}."); IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin .GetType().GetConstructor(Type.EmptyTypes) ?.Invoke(new object[] { }); if (fs == null) { continue; } error = fs.Mount(imageFormat, partitions[i], encoding, parsedOptions); if (error == Errno.NoError) { List <string> rootDir = new List <string>(); error = fs.ReadDir("/", out rootDir); if (error == Errno.NoError) { foreach (string entry in rootDir) { DicConsole.WriteLine("{0}", entry); } } else { DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); } Core.Statistics.AddFilesystem(fs.XmlFsType.Type); } else { DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } Partition wholePart = new Partition { Name = "Whole device", Length = imageFormat.Info.Sectors, Size = imageFormat.Info.Sectors * imageFormat.Info.SectorSize }; Core.Filesystems.Identify(imageFormat, out idPlugins, wholePart); if (idPlugins.Count == 0) { DicConsole.WriteLine("Filesystem not identified"); } else if (idPlugins.Count > 1) { DicConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); foreach (string pluginName in idPlugins) { if (plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) { DicConsole.WriteLine($"As identified by {plugin.Name}."); IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin .GetType().GetConstructor(Type.EmptyTypes) ?.Invoke(new object[] { }); if (fs == null) { continue; } error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions); if (error == Errno.NoError) { List <string> rootDir = new List <string>(); error = fs.ReadDir("/", out rootDir); if (error == Errno.NoError) { foreach (string entry in rootDir) { DicConsole.WriteLine("{0}", entry); } } else { DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); } Core.Statistics.AddFilesystem(fs.XmlFsType.Type); } else { DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } else { plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); if (plugin != null) { DicConsole.WriteLine($"Identified by {plugin.Name}."); IReadOnlyFilesystem fs = (IReadOnlyFilesystem)plugin .GetType().GetConstructor(Type.EmptyTypes)?.Invoke(new object[] { }); if (fs != null) { error = fs.Mount(imageFormat, wholePart, encoding, parsedOptions); if (error == Errno.NoError) { List <string> rootDir = new List <string>(); error = fs.ReadDir("/", out rootDir); if (error == Errno.NoError) { foreach (string entry in rootDir) { if (options.Long) { FileEntryInfo stat = new FileEntryInfo(); List <string> xattrs = new List <string>(); error = fs.Stat(entry, out stat); if (error == Errno.NoError) { DicConsole.WriteLine("{0}\t{1}\t{2} bytes\t{3}", stat.CreationTimeUtc, stat.Inode, stat.Length, entry); error = fs.ListXAttr(entry, out xattrs); if (error != Errno.NoError) { continue; } foreach (string xattr in xattrs) { byte[] xattrBuf = new byte[0]; error = fs.GetXattr(entry, xattr, ref xattrBuf); if (error == Errno.NoError) { DicConsole.WriteLine("\t\t{0}\t{1} bytes", xattr, xattrBuf.Length); } } } else { DicConsole.WriteLine("{0}", entry); } } else { DicConsole.WriteLine("{0}", entry); } } } else { DicConsole.ErrorWriteLine("Error {0} reading root directory {0}", error.ToString()); } Core.Statistics.AddFilesystem(fs.XmlFsType.Type); } else { DicConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } } catch (Exception ex) { DicConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); DicConsole.DebugWriteLine("Ls command", ex.StackTrace); } Core.Statistics.AddCommand("ls"); }
internal static void DoEntropy(EntropyOptions options) { DicConsole.DebugWriteLine("Entropy command", "--debug={0}", options.Debug); DicConsole.DebugWriteLine("Entropy command", "--verbose={0}", options.Verbose); DicConsole.DebugWriteLine("Entropy command", "--separated-tracks={0}", options.SeparatedTracks); DicConsole.DebugWriteLine("Entropy command", "--whole-disc={0}", options.WholeDisc); DicConsole.DebugWriteLine("Entropy command", "--input={0}", options.InputFile); DicConsole.DebugWriteLine("Entropy command", "--duplicated-sectors={0}", options.DuplicatedSectors); FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(options.InputFile); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return; } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming"); return; } inputFormat.Open(inputFilter); Core.Statistics.AddMediaFormat(inputFormat.Format); Core.Statistics.AddMedia(inputFormat.Info.MediaType, false); Core.Statistics.AddFilter(inputFilter.Name); double entropy = 0; ulong[] entTable; ulong sectors; if (options.SeparatedTracks) { try { List <Track> inputTracks = inputFormat.Tracks; foreach (Track currentTrack in inputTracks) { entTable = new ulong[256]; ulong trackSize = 0; List <string> uniqueSectorsPerTrack = new List <string>(); sectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector + 1; DicConsole.WriteLine("Track {0} has {1} sectors", currentTrack.TrackSequence, sectors); for (ulong i = currentTrack.TrackStartSector; i <= currentTrack.TrackEndSector; i++) { DicConsole.Write("\rEntropying sector {0} of track {1}", i + 1, currentTrack.TrackSequence); byte[] sector = inputFormat.ReadSector(i, currentTrack.TrackSequence); if (options.DuplicatedSectors) { string sectorHash = Sha1Context.Data(sector, out _); if (!uniqueSectorsPerTrack.Contains(sectorHash)) { uniqueSectorsPerTrack.Add(sectorHash); } } foreach (byte b in sector) { entTable[b]++; } trackSize += (ulong)sector.LongLength; } entropy += entTable.Select(l => (double)l / (double)trackSize) .Select(frequency => - (frequency * Math.Log(frequency, 2))).Sum(); DicConsole.WriteLine("Entropy for track {0} is {1:F4}.", currentTrack.TrackSequence, entropy); if (options.DuplicatedSectors) { DicConsole.WriteLine("Track {0} has {1} unique sectors ({1:P3})", currentTrack.TrackSequence, uniqueSectorsPerTrack.Count, (double)uniqueSectorsPerTrack.Count / (double)sectors); } DicConsole.WriteLine(); } } catch (Exception ex) { if (options.Debug) { DicConsole.DebugWriteLine("Could not get tracks because {0}", ex.Message); } else { DicConsole.ErrorWriteLine("Unable to get separate tracks, not calculating their entropy"); } } } if (!options.WholeDisc) { return; } entTable = new ulong[256]; ulong diskSize = 0; List <string> uniqueSectors = new List <string>(); sectors = inputFormat.Info.Sectors; DicConsole.WriteLine("Sectors {0}", sectors); for (ulong i = 0; i < sectors; i++) { DicConsole.Write("\rEntropying sector {0}", i + 1); byte[] sector = inputFormat.ReadSector(i); if (options.DuplicatedSectors) { string sectorHash = Sha1Context.Data(sector, out _); if (!uniqueSectors.Contains(sectorHash)) { uniqueSectors.Add(sectorHash); } } foreach (byte b in sector) { entTable[b]++; } diskSize += (ulong)sector.LongLength; } entropy += entTable.Select(l => (double)l / (double)diskSize) .Select(frequency => - (frequency * Math.Log(frequency, 2))).Sum(); DicConsole.WriteLine(); DicConsole.WriteLine("Entropy for disk is {0:F4}.", entropy); if (options.DuplicatedSectors) { DicConsole.WriteLine("Disk has {0} unique sectors ({1:P3})", uniqueSectors.Count, (double)uniqueSectors.Count / (double)sectors); } Core.Statistics.AddCommand("entropy"); }
public override int Invoke(IEnumerable <string> arguments) { List <string> extra = Options.Parse(arguments); if (showHelp) { Options.WriteOptionDescriptions(CommandSet.Out); return((int)ErrorNumber.HelpRequested); } MainClass.PrintCopyright(); if (MainClass.Debug) { DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (MainClass.Verbose) { DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("verify"); if (extra.Count > 1) { DicConsole.ErrorWriteLine("Too many arguments."); return((int)ErrorNumber.UnexpectedArgumentCount); } if (extra.Count == 0) { DicConsole.ErrorWriteLine("Missing input image."); return((int)ErrorNumber.MissingArgument); } inputFile = extra[0]; DicConsole.DebugWriteLine("Verify command", "--debug={0}", MainClass.Debug); DicConsole.DebugWriteLine("Verify command", "--input={0}", inputFile); DicConsole.DebugWriteLine("Verify command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Verify command", "--verify-disc={0}", verifyDisc); DicConsole.DebugWriteLine("Verify command", "--verify-sectors={0}", verifySectors); FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(inputFile); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying"); return((int)ErrorNumber.FormatNotFound); } inputFormat.Open(inputFilter); Statistics.AddMediaFormat(inputFormat.Format); Statistics.AddMedia(inputFormat.Info.MediaType, false); Statistics.AddFilter(inputFilter.Name); bool?correctImage = null; long totalSectors = 0; long errorSectors = 0; bool?correctSectors = null; long unknownSectors = 0; IVerifiableImage verifiableImage = inputFormat as IVerifiableImage; IVerifiableSectorsImage verifiableSectorsImage = inputFormat as IVerifiableSectorsImage; if (verifiableImage is null && verifiableSectorsImage is null) { DicConsole.ErrorWriteLine("The specified image does not support any kind of verification"); return((int)ErrorNumber.NotVerificable); } if (verifyDisc && verifiableImage != null) { DateTime startCheck = DateTime.UtcNow; bool? discCheckStatus = verifiableImage.VerifyMediaImage(); DateTime endCheck = DateTime.UtcNow; TimeSpan checkTime = endCheck - startCheck; switch (discCheckStatus) { case true: DicConsole.WriteLine("Disc image checksums are correct"); break; case false: DicConsole.WriteLine("Disc image checksums are incorrect"); break; case null: DicConsole.WriteLine("Disc image does not contain checksums"); break; } correctImage = discCheckStatus; DicConsole.VerboseWriteLine("Checking disc image checksums took {0} seconds", checkTime.TotalSeconds); } if (verifySectors) { DateTime startCheck = DateTime.Now; DateTime endCheck = startCheck; List <ulong> failingLbas = new List <ulong>(); List <ulong> unknownLbas = new List <ulong>(); if (verifiableSectorsImage is IOpticalMediaImage opticalMediaImage) { List <Track> inputTracks = opticalMediaImage.Tracks; ulong currentSectorAll = 0; startCheck = DateTime.UtcNow; foreach (Track currentTrack in inputTracks) { ulong remainingSectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector; ulong currentSector = 0; while (remainingSectors > 0) { DicConsole.Write("\rChecking sector {0} of {1}, on track {2}", currentSectorAll, inputFormat.Info.Sectors, currentTrack.TrackSequence); List <ulong> tempfailingLbas; List <ulong> tempunknownLbas; if (remainingSectors < 512) { opticalMediaImage.VerifySectors(currentSector, (uint)remainingSectors, currentTrack.TrackSequence, out tempfailingLbas, out tempunknownLbas); } else { opticalMediaImage.VerifySectors(currentSector, 512, currentTrack.TrackSequence, out tempfailingLbas, out tempunknownLbas); } failingLbas.AddRange(tempfailingLbas); unknownLbas.AddRange(tempunknownLbas); if (remainingSectors < 512) { currentSector += remainingSectors; currentSectorAll += remainingSectors; remainingSectors = 0; } else { currentSector += 512; currentSectorAll += 512; remainingSectors -= 512; } } } endCheck = DateTime.UtcNow; } else if (verifiableSectorsImage != null) { ulong remainingSectors = inputFormat.Info.Sectors; ulong currentSector = 0; startCheck = DateTime.UtcNow; while (remainingSectors > 0) { DicConsole.Write("\rChecking sector {0} of {1}", currentSector, inputFormat.Info.Sectors); List <ulong> tempfailingLbas; List <ulong> tempunknownLbas; if (remainingSectors < 512) { verifiableSectorsImage.VerifySectors(currentSector, (uint)remainingSectors, out tempfailingLbas, out tempunknownLbas); } else { verifiableSectorsImage.VerifySectors(currentSector, 512, out tempfailingLbas, out tempunknownLbas); } failingLbas.AddRange(tempfailingLbas); unknownLbas.AddRange(tempunknownLbas); if (remainingSectors < 512) { currentSector += remainingSectors; remainingSectors = 0; } else { currentSector += 512; remainingSectors -= 512; } } endCheck = DateTime.UtcNow; } TimeSpan checkTime = endCheck - startCheck; DicConsole.Write("\r" + new string(' ', System.Console.WindowWidth - 1) + "\r"); if (unknownSectors > 0) { DicConsole.WriteLine("There is at least one sector that does not contain a checksum"); } if (errorSectors > 0) { DicConsole.WriteLine("There is at least one sector with incorrect checksum or errors"); } if (unknownSectors == 0 && errorSectors == 0) { DicConsole.WriteLine("All sector checksums are correct"); } DicConsole.VerboseWriteLine("Checking sector checksums took {0} seconds", checkTime.TotalSeconds); if (MainClass.Verbose) { DicConsole.VerboseWriteLine("LBAs with error:"); if (failingLbas.Count == (int)inputFormat.Info.Sectors) { DicConsole.VerboseWriteLine("\tall sectors."); } else { foreach (ulong t in failingLbas) { DicConsole.VerboseWriteLine("\t{0}", t); } } DicConsole.WriteLine("LBAs without checksum:"); if (unknownLbas.Count == (int)inputFormat.Info.Sectors) { DicConsole.VerboseWriteLine("\tall sectors."); } else { foreach (ulong t in unknownLbas) { DicConsole.VerboseWriteLine("\t{0}", t); } } } DicConsole.WriteLine("Total sectors........... {0}", inputFormat.Info.Sectors); DicConsole.WriteLine("Total errors............ {0}", failingLbas.Count); DicConsole.WriteLine("Total unknowns.......... {0}", unknownLbas.Count); DicConsole.WriteLine("Total errors+unknowns... {0}", failingLbas.Count + unknownLbas.Count); totalSectors = (long)inputFormat.Info.Sectors; errorSectors = failingLbas.Count; unknownSectors = unknownLbas.Count; if (failingLbas.Count > 0) { correctSectors = false; } else if ((ulong)unknownLbas.Count < inputFormat.Info.Sectors) { correctSectors = true; } } switch (correctImage) { case null when correctSectors is null: return((int)ErrorNumber.NotVerificable); case null when correctSectors == false: return((int)ErrorNumber.BadSectorsImageNotVerified); case null when correctSectors == true: return((int)ErrorNumber.CorrectSectorsImageNotVerified); case false when correctSectors is null: return((int)ErrorNumber.BadImageSectorsNotVerified); case false when correctSectors == false: return((int)ErrorNumber.BadImageBadSectors); case false when correctSectors == true: return((int)ErrorNumber.CorrectSectorsBadImage); case true when correctSectors is null: return((int)ErrorNumber.CorrectImageSectorsNotVerified); case true when correctSectors == false: return((int)ErrorNumber.CorrectImageBadSectors); case true when correctSectors == true: return((int)ErrorNumber.NoError); } return((int)ErrorNumber.NoError); }
public override int Invoke(IEnumerable <string> arguments) { List <string> extra = Options.Parse(arguments); if (showHelp) { Options.WriteOptionDescriptions(CommandSet.Out); return((int)ErrorNumber.HelpRequested); } MainClass.PrintCopyright(); if (MainClass.Debug) { DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (MainClass.Verbose) { DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("entropy"); if (extra.Count > 1) { DicConsole.ErrorWriteLine("Too many arguments."); return((int)ErrorNumber.UnexpectedArgumentCount); } if (extra.Count == 0) { DicConsole.ErrorWriteLine("Missing input image."); return((int)ErrorNumber.MissingArgument); } inputFile = extra[0]; DicConsole.DebugWriteLine("Entropy command", "--debug={0}", MainClass.Debug); DicConsole.DebugWriteLine("Entropy command", "--duplicated-sectors={0}", duplicatedSectors); DicConsole.DebugWriteLine("Entropy command", "--input={0}", inputFile); DicConsole.DebugWriteLine("Entropy command", "--separated-tracks={0}", separatedTracks); DicConsole.DebugWriteLine("Entropy command", "--verbose={0}", MainClass.Verbose); DicConsole.DebugWriteLine("Entropy command", "--whole-disc={0}", wholeDisc); FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(inputFile); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not checksumming"); return((int)ErrorNumber.UnrecognizedFormat); } inputFormat.Open(inputFilter); Statistics.AddMediaFormat(inputFormat.Format); Statistics.AddMedia(inputFormat.Info.MediaType, false); Statistics.AddFilter(inputFilter.Name); Entropy entropyCalculator = new Entropy(MainClass.Debug, MainClass.Verbose, inputFormat); entropyCalculator.InitProgressEvent += Progress.InitProgress; entropyCalculator.InitProgress2Event += Progress.InitProgress2; entropyCalculator.UpdateProgressEvent += Progress.UpdateProgress; entropyCalculator.UpdateProgress2Event += Progress.UpdateProgress2; entropyCalculator.EndProgressEvent += Progress.EndProgress; entropyCalculator.EndProgress2Event += Progress.EndProgress2; if (separatedTracks) { EntropyResults[] tracksEntropy = entropyCalculator.CalculateTracksEntropy(duplicatedSectors); foreach (EntropyResults trackEntropy in tracksEntropy) { DicConsole.WriteLine("Entropy for track {0} is {1:F4}.", trackEntropy.Track, trackEntropy.Entropy); if (trackEntropy.UniqueSectors != null) { DicConsole.WriteLine("Track {0} has {1} unique sectors ({2:P3})", trackEntropy.Track, trackEntropy.UniqueSectors, (double)trackEntropy.UniqueSectors / (double)trackEntropy.Sectors); } } } if (!wholeDisc) { return((int)ErrorNumber.NoError); } EntropyResults entropy = entropyCalculator.CalculateMediaEntropy(duplicatedSectors); DicConsole.WriteLine("Entropy for disk is {0:F4}.", entropy.Entropy); if (entropy.UniqueSectors != null) { DicConsole.WriteLine("Disk has {0} unique sectors ({1:P3})", entropy.UniqueSectors, (double)entropy.UniqueSectors / (double)entropy.Sectors); } return((int)ErrorNumber.NoError); }
public static int Invoke(bool debug, bool verbose, string imagePath, bool verifyDisc = true, bool verifySectors = true) { MainClass.PrintCopyright(); if (debug) { AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("verify"); AaruConsole.DebugWriteLine("Verify command", "--debug={0}", debug); AaruConsole.DebugWriteLine("Verify command", "--input={0}", imagePath); AaruConsole.DebugWriteLine("Verify command", "--verbose={0}", verbose); AaruConsole.DebugWriteLine("Verify command", "--verify-disc={0}", verifyDisc); AaruConsole.DebugWriteLine("Verify command", "--verify-sectors={0}", verifySectors); var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(imagePath); if (inputFilter == null) { AaruConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { AaruConsole.ErrorWriteLine("Unable to recognize image format, not verifying"); return((int)ErrorNumber.FormatNotFound); } inputFormat.Open(inputFilter); Statistics.AddMediaFormat(inputFormat.Format); Statistics.AddMedia(inputFormat.Info.MediaType, false); Statistics.AddFilter(inputFilter.Name); bool?correctImage = null; long errorSectors = 0; bool?correctSectors = null; long unknownSectors = 0; var verifiableImage = inputFormat as IVerifiableImage; var verifiableSectorsImage = inputFormat as IVerifiableSectorsImage; if (verifiableImage is null && verifiableSectorsImage is null) { AaruConsole.ErrorWriteLine("The specified image does not support any kind of verification"); return((int)ErrorNumber.NotVerifiable); } if (verifyDisc && verifiableImage != null) { DateTime startCheck = DateTime.UtcNow; bool? discCheckStatus = verifiableImage.VerifyMediaImage(); DateTime endCheck = DateTime.UtcNow; TimeSpan checkTime = endCheck - startCheck; switch (discCheckStatus) { case true: AaruConsole.WriteLine("Disc image checksums are correct"); break; case false: AaruConsole.WriteLine("Disc image checksums are incorrect"); break; case null: AaruConsole.WriteLine("Disc image does not contain checksums"); break; } correctImage = discCheckStatus; AaruConsole.VerboseWriteLine("Checking disc image checksums took {0} seconds", checkTime.TotalSeconds); } if (verifySectors) { DateTime startCheck = DateTime.Now; DateTime endCheck = startCheck; List <ulong> failingLbas = new List <ulong>(); List <ulong> unknownLbas = new List <ulong>(); if (verifiableSectorsImage is IOpticalMediaImage opticalMediaImage && opticalMediaImage.Tracks != null) { List <Track> inputTracks = opticalMediaImage.Tracks; ulong currentSectorAll = 0; startCheck = DateTime.UtcNow; foreach (Track currentTrack in inputTracks) { ulong remainingSectors = currentTrack.TrackEndSector - currentTrack.TrackStartSector; ulong currentSector = 0; while (remainingSectors > 0) { AaruConsole.Write("\rChecking sector {0} of {1}, on track {2}", currentSectorAll, inputFormat.Info.Sectors, currentTrack.TrackSequence); List <ulong> tempFailingLbas; List <ulong> tempUnknownLbas; if (remainingSectors < 512) { opticalMediaImage.VerifySectors(currentSector, (uint)remainingSectors, currentTrack.TrackSequence, out tempFailingLbas, out tempUnknownLbas); } else { opticalMediaImage.VerifySectors(currentSector, 512, currentTrack.TrackSequence, out tempFailingLbas, out tempUnknownLbas); } failingLbas.AddRange(tempFailingLbas); unknownLbas.AddRange(tempUnknownLbas); if (remainingSectors < 512) { currentSector += remainingSectors; currentSectorAll += remainingSectors; remainingSectors = 0; } else { currentSector += 512; currentSectorAll += 512; remainingSectors -= 512; } } } endCheck = DateTime.UtcNow; } else if (verifiableSectorsImage != null) { ulong remainingSectors = inputFormat.Info.Sectors; ulong currentSector = 0; startCheck = DateTime.UtcNow; while (remainingSectors > 0) { AaruConsole.Write("\rChecking sector {0} of {1}", currentSector, inputFormat.Info.Sectors); List <ulong> tempFailingLbas; List <ulong> tempUnknownLbas; if (remainingSectors < 512) { verifiableSectorsImage.VerifySectors(currentSector, (uint)remainingSectors, out tempFailingLbas, out tempUnknownLbas); } else { verifiableSectorsImage.VerifySectors(currentSector, 512, out tempFailingLbas, out tempUnknownLbas); } failingLbas.AddRange(tempFailingLbas); unknownLbas.AddRange(tempUnknownLbas); if (remainingSectors < 512) { currentSector += remainingSectors; remainingSectors = 0; } else { currentSector += 512; remainingSectors -= 512; } } endCheck = DateTime.UtcNow; } TimeSpan checkTime = endCheck - startCheck; AaruConsole.Write("\r" + new string(' ', System.Console.WindowWidth - 1) + "\r"); if (unknownSectors > 0) { AaruConsole.WriteLine("There is at least one sector that does not contain a checksum"); } if (errorSectors > 0) { AaruConsole.WriteLine("There is at least one sector with incorrect checksum or errors"); } if (unknownSectors == 0 && errorSectors == 0) { AaruConsole.WriteLine("All sector checksums are correct"); } AaruConsole.VerboseWriteLine("Checking sector checksums took {0} seconds", checkTime.TotalSeconds); if (verbose) { AaruConsole.VerboseWriteLine("LBAs with error:"); if (failingLbas.Count == (int)inputFormat.Info.Sectors) { AaruConsole.VerboseWriteLine("\tall sectors."); } else { foreach (ulong t in failingLbas) { AaruConsole.VerboseWriteLine("\t{0}", t); } } AaruConsole.WriteLine("LBAs without checksum:"); if (unknownLbas.Count == (int)inputFormat.Info.Sectors) { AaruConsole.VerboseWriteLine("\tall sectors."); } else { foreach (ulong t in unknownLbas) { AaruConsole.VerboseWriteLine("\t{0}", t); } } } AaruConsole.WriteLine("Total sectors........... {0}", inputFormat.Info.Sectors); AaruConsole.WriteLine("Total errors............ {0}", failingLbas.Count); AaruConsole.WriteLine("Total unknowns.......... {0}", unknownLbas.Count); AaruConsole.WriteLine("Total errors+unknowns... {0}", failingLbas.Count + unknownLbas.Count); if (failingLbas.Count > 0) { correctSectors = false; } else if ((ulong)unknownLbas.Count < inputFormat.Info.Sectors) { correctSectors = true; } }
/// <summary>Creates optical metadata sidecar</summary> /// <param name="blockSize">Size of the read sector in bytes</param> /// <param name="blocks">Total number of positive sectors</param> /// <param name="mediaType">Disc type</param> /// <param name="layers">Disc layers</param> /// <param name="mediaTags">Media tags</param> /// <param name="sessions">Disc sessions</param> /// <param name="totalChkDuration">Total time spent doing checksums</param> /// <param name="discOffset">Disc write offset</param> void WriteOpticalSidecar(uint blockSize, ulong blocks, MediaType mediaType, LayersType layers, Dictionary <MediaTagType, byte[]> mediaTags, int sessions, out double totalChkDuration, int?discOffset) { _dumpLog.WriteLine("Creating sidecar."); var filters = new FiltersList(); IFilter filter = filters.GetFilter(_outputPath); IMediaImage inputPlugin = ImageFormat.Detect(filter); totalChkDuration = 0; if (!inputPlugin.Open(filter)) { StoppingErrorMessage?.Invoke("Could not open created image."); return; } DateTime chkStart = DateTime.UtcNow; // ReSharper disable once UseObjectOrCollectionInitializer _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); _sidecarClass.InitProgressEvent += InitProgress; _sidecarClass.UpdateProgressEvent += UpdateProgress; _sidecarClass.EndProgressEvent += EndProgress; _sidecarClass.InitProgressEvent2 += InitProgress2; _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; CICMMetadataType sidecar = _sidecarClass.Create(); DateTime 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)); if (_preSidecar != null) { _preSidecar.OpticalDisc = sidecar.OpticalDisc; sidecar = _preSidecar; } List <(ulong start, string type)> filesystems = new List <(ulong start, string type)>(); if (sidecar.OpticalDisc[0].Track != null) { filesystems.AddRange(from xmlTrack in sidecar.OpticalDisc[0].Track where xmlTrack.FileSystemInformation != null from partition in xmlTrack.FileSystemInformation where partition.FileSystems != null from fileSystem in partition.FileSystems select(partition.StartSector, fileSystem.Type)); } if (filesystems.Count > 0) { foreach (var filesystem in filesystems.Select(o => new { o.start, o.type }).Distinct()) { _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); } } sidecar.OpticalDisc[0].Dimensions = Dimensions.DimensionsFromMediaType(mediaType); (string type, string subType)discType = CommonTypes.Metadata.MediaType.MediaTypeToString(mediaType); sidecar.OpticalDisc[0].DiscType = discType.type; sidecar.OpticalDisc[0].DiscSubType = discType.subType; sidecar.OpticalDisc[0].DumpHardwareArray = _resume.Tries.ToArray(); sidecar.OpticalDisc[0].Sessions = (uint)sessions; sidecar.OpticalDisc[0].Layers = layers; if (discOffset.HasValue) { sidecar.OpticalDisc[0].Offset = (int)(discOffset / 4); sidecar.OpticalDisc[0].OffsetSpecified = true; } if (mediaTags != null) { foreach (KeyValuePair <MediaTagType, byte[]> tag in mediaTags.Where(tag => _outputPlugin. SupportedMediaTags. Contains(tag.Key))) { AddMediaTagToSidecar(_outputPath, tag, ref sidecar); } } UpdateStatus?.Invoke("Writing metadata sidecar"); var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); }
/// <summary>Dumps an ATA device</summary> void Ata() { if (_dumpRaw) { if (_force) { ErrorMessage?.Invoke("Raw dumping not yet supported in ATA devices, continuing..."); } else { StoppingErrorMessage?.Invoke("Raw dumping not yet supported in ATA devices, aborting..."); return; } } const ushort ataProfile = 0x0001; const uint timeout = 5; double imageWriteDuration = 0; MediaType mediaType = MediaType.Unknown; UpdateStatus?.Invoke("Requesting ATA IDENTIFY DEVICE."); _dumpLog.WriteLine("Requesting ATA IDENTIFY DEVICE."); bool sense = _dev.AtaIdentify(out byte[] cmdBuf, out AtaErrorRegistersChs errorChs); if (sense) { _errorLog?.WriteLine("ATA IDENTIFY DEVICE", _dev.Error, _dev.LastError, errorChs); } else if (Identify.Decode(cmdBuf).HasValue) { Identify.IdentifyDevice?ataIdNullable = Identify.Decode(cmdBuf); if (ataIdNullable != null) { Identify.IdentifyDevice ataId = ataIdNullable.Value; byte[] ataIdentify = cmdBuf; cmdBuf = new byte[0]; DateTime start; DateTime end; double totalDuration = 0; double currentSpeed = 0; double maxSpeed = double.MinValue; double minSpeed = double.MaxValue; // Initialize reader UpdateStatus?.Invoke("Initializing reader."); _dumpLog.WriteLine("Initializing reader."); var ataReader = new Reader(_dev, timeout, ataIdentify, _errorLog); // Fill reader blocks ulong blocks = ataReader.GetDeviceBlocks(); // Check block sizes if (ataReader.GetBlockSize()) { _dumpLog.WriteLine("ERROR: Cannot get block size: {0}.", ataReader.ErrorMessage); ErrorMessage(ataReader.ErrorMessage); return; } uint blockSize = ataReader.LogicalBlockSize; uint physicalSectorSize = ataReader.PhysicalBlockSize; if (ataReader.FindReadCommand()) { _dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", ataReader.ErrorMessage); ErrorMessage(ataReader.ErrorMessage); return; } // Check how many blocks to read, if error show and return if (ataReader.GetBlocksToRead(_maximumReadable)) { _dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", ataReader.ErrorMessage); ErrorMessage(ataReader.ErrorMessage); return; } uint blocksToRead = ataReader.BlocksToRead; ushort cylinders = ataReader.Cylinders; byte heads = ataReader.Heads; byte sectors = ataReader.Sectors; UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes)."); UpdateStatus?. Invoke($"Device reports {cylinders} cylinders {heads} heads {sectors} sectors per track."); UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time."); UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block."); UpdateStatus?.Invoke($"Device reports {physicalSectorSize} bytes per physical block."); _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 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 = !_dev.IsCompactFlash && ataId.GeneralConfiguration.HasFlag(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, _dev.FirmwareRevision, _private); if (currentTry == null || extents == null) { StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); return; } MhddLog mhddLog; IbgLog ibgLog; double duration; bool ret = true; if (_dev.IsUsb && _dev.UsbDescriptors != null && !_outputPlugin.SupportedMediaTags.Contains(MediaTagType.USB_Descriptors)) { ret = false; _dumpLog.WriteLine("Output format does not support USB descriptors."); ErrorMessage("Output format does not support USB descriptors."); } if (_dev.IsPcmcia && _dev.Cis != null && !_outputPlugin.SupportedMediaTags.Contains(MediaTagType.PCMCIA_CIS)) { ret = false; _dumpLog.WriteLine("Output format does not support PCMCIA CIS descriptors."); ErrorMessage("Output format does not support PCMCIA CIS descriptors."); } if (!_outputPlugin.SupportedMediaTags.Contains(MediaTagType.ATA_IDENTIFY)) { ret = false; _dumpLog.WriteLine("Output format does not support ATA IDENTIFY."); ErrorMessage("Output format does not support ATA IDENTIFY."); } if (!ret) { _dumpLog.WriteLine("Several media tags not supported, {0}continuing...", _force ? "" : "not "); if (_force) { ErrorMessage("Several media tags not supported, continuing..."); } else { StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing..."); return; } } mediaType = MediaTypeFromDevice.GetFromAta(_dev.Manufacturer, _dev.Model, _dev.IsRemovable, _dev.IsCompactFlash, _dev.IsPcmcia, blocks); ret = _outputPlugin.Create(_outputPath, mediaType, _formatOptions, blocks, blockSize); // Cannot create image if (!ret) { _dumpLog.WriteLine("Error creating output image, not continuing."); _dumpLog.WriteLine(_outputPlugin.ErrorMessage); StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + _outputPlugin.ErrorMessage); return; } // Setting geometry _outputPlugin.SetGeometry(cylinders, heads, sectors); if (ataReader.IsLba) { UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time."); if (_skip < blocksToRead) { _skip = blocksToRead; } mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private); ibgLog = new IbgLog(_outputPrefix + ".ibg", ataProfile); if (_resume.NextBlock > 0) { UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}."); _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); } bool newTrim = false; start = DateTime.UtcNow; DateTime timeSpeedStart = DateTime.UtcNow; ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for (ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); break; } if (blocks - i < blocksToRead) { blocksToRead = (byte)(blocks - i); } if (currentSpeed > maxSpeed && currentSpeed > 0) { maxSpeed = currentSpeed; } if (currentSpeed < minSpeed && currentSpeed > 0) { minSpeed = currentSpeed; } UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, (long)blocks); bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration); if (!error) { mhddLog.Write(i, duration); ibgLog.Write(i, currentSpeed * 1024); DateTime writeStart = DateTime.Now; _outputPlugin.WriteSectors(cmdBuf, i, blocksToRead); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; extents.Add(i, blocksToRead, true); } else { if (i + _skip > blocks) { _skip = (uint)(blocks - i); } for (ulong b = i; b < i + _skip; b++) { _resume.BadBlocks.Add(b); } mhddLog.Write(i, duration < 500 ? 65535 : duration); ibgLog.Write(i, 0); DateTime writeStart = DateTime.Now; _outputPlugin.WriteSectors(new byte[blockSize * _skip], i, _skip); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); i += _skip - blocksToRead; newTrim = true; } sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; if (elapsed < 1) { continue; } currentSpeed = (sectorSpeedStart * blockSize) / (1048576 * elapsed); sectorSpeedStart = 0; timeSpeedStart = DateTime.UtcNow; } end = DateTime.Now; EndProgress?.Invoke(); mhddLog.Close(); ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000), _devicePath); UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); UpdateStatus?. Invoke($"Average dump speed {((double)blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000):F3} KiB/sec."); UpdateStatus?. Invoke($"Average write speed {((double)blockSize * (double)(blocks + 1)) / 1024 / imageWriteDuration:F3} KiB/sec."); _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 write speed {0:F3} KiB/sec.", ((double)blockSize * (double)(blocks + 1)) / 1024 / imageWriteDuration); #region Trimming if (_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { start = DateTime.UtcNow; UpdateStatus?.Invoke("Trimming skipped sectors"); _dumpLog.WriteLine("Trimming skipped sectors"); ulong[] tmpArray = _resume.BadBlocks.ToArray(); InitProgress?.Invoke(); foreach (ulong badSector in tmpArray) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); break; } PulseProgress?.Invoke($"Trimming sector {badSector}"); bool error = ataReader.ReadBlock(out cmdBuf, badSector, out duration); totalDuration += duration; if (error) { continue; } _resume.BadBlocks.Remove(badSector); extents.Add(badSector); _outputPlugin.WriteSector(cmdBuf, badSector); } EndProgress?.Invoke(); end = DateTime.UtcNow; UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds."); _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds); } #endregion Trimming #region Error handling if (_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) { int pass = 1; bool forward = true; InitProgress?.Invoke(); repeatRetryLba: ulong[] tmpArray = _resume.BadBlocks.ToArray(); foreach (ulong badSector in tmpArray) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); break; } PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass, forward ? "forward" : "reverse", _persistent ? "recovering partial data, " : "")); bool error = ataReader.ReadBlock(out cmdBuf, badSector, out duration); totalDuration += duration; if (!error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); _outputPlugin.WriteSector(cmdBuf, badSector); UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); } else if (_persistent) { _outputPlugin.WriteSector(cmdBuf, badSector); } } if (pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); if (!forward) { _resume.BadBlocks.Reverse(); } goto repeatRetryLba; } EndProgress?.Invoke(); } #endregion Error handling LBA currentTry.Extents = ExtentsConverter.ToMetadata(extents); } else { mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private); ibgLog = new IbgLog(_outputPrefix + ".ibg", ataProfile); ulong currentBlock = 0; blocks = (ulong)(cylinders * heads * sectors); start = DateTime.UtcNow; DateTime timeSpeedStart = DateTime.UtcNow; ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for (ushort cy = 0; cy < cylinders; cy++) { for (byte hd = 0; hd < heads; hd++) { for (byte sc = 1; sc < sectors; sc++) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); break; } if (currentSpeed > maxSpeed && currentSpeed > 0) { maxSpeed = currentSpeed; } if (currentSpeed < minSpeed && currentSpeed > 0) { minSpeed = currentSpeed; } PulseProgress?. Invoke($"Reading cylinder {cy} head {hd} sector {sc} ({currentSpeed:F3} MiB/sec.)"); bool error = ataReader.ReadChs(out cmdBuf, cy, hd, sc, out duration); totalDuration += duration; if (!error) { mhddLog.Write(currentBlock, duration); ibgLog.Write(currentBlock, currentSpeed * 1024); DateTime writeStart = DateTime.Now; _outputPlugin.WriteSector(cmdBuf, (ulong)((((cy * heads) + hd) * sectors) + (sc - 1))); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; extents.Add(currentBlock); _dumpLog.WriteLine("Error reading cylinder {0} head {1} sector {2}.", cy, hd, sc); } else { _resume.BadBlocks.Add(currentBlock); mhddLog.Write(currentBlock, duration < 500 ? 65535 : duration); ibgLog.Write(currentBlock, 0); DateTime writeStart = DateTime.Now; _outputPlugin.WriteSector(new byte[blockSize], (ulong)((((cy * heads) + hd) * sectors) + (sc - 1))); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; } sectorSpeedStart++; currentBlock++; double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; if (elapsed < 1) { continue; } currentSpeed = (sectorSpeedStart * blockSize) / (1048576 * elapsed); sectorSpeedStart = 0; timeSpeedStart = DateTime.UtcNow; } } } end = DateTime.Now; EndProgress?.Invoke(); mhddLog.Close(); ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000), _devicePath); UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); UpdateStatus?. Invoke($"Average dump speed {((double)blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000):F3} KiB/sec."); UpdateStatus?. Invoke($"Average write speed {((double)blockSize * (double)(blocks + 1)) / 1024 / (imageWriteDuration / 1000):F3} KiB/sec."); _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 write speed {0:F3} KiB/sec.", ((double)blockSize * (double)(blocks + 1)) / 1024 / (imageWriteDuration / 1000)); } foreach (ulong bad in _resume.BadBlocks) { _dumpLog.WriteLine("Sector {0} could not be read.", bad); } _outputPlugin.SetDumpHardware(_resume.Tries); // TODO: Non-removable var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; if (!_outputPlugin.SetMetadata(metadata)) { ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + _outputPlugin.ErrorMessage); } if (_preSidecar != null) { _outputPlugin.SetCicmMetadata(_preSidecar); } _dumpLog.WriteLine("Closing output file."); UpdateStatus?.Invoke("Closing output file."); DateTime closeStart = DateTime.Now; _outputPlugin.Close(); DateTime closeEnd = DateTime.Now; UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); if (_aborted) { _dumpLog.WriteLine("Aborted!"); UpdateStatus?.Invoke("Aborted!"); return; } double totalChkDuration = 0; if (_metadata) { _dumpLog.WriteLine("Creating sidecar."); UpdateStatus?.Invoke("Creating sidecar."); var filters = new FiltersList(); IFilter filter = filters.GetFilter(_outputPath); IMediaImage inputPlugin = ImageFormat.Detect(filter); if (!inputPlugin.Open(filter)) { StoppingErrorMessage?.Invoke("Could not open created image."); return; } DateTime chkStart = DateTime.UtcNow; _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); _sidecarClass.InitProgressEvent += InitProgress; _sidecarClass.UpdateProgressEvent += UpdateProgress; _sidecarClass.EndProgressEvent += EndProgress; _sidecarClass.InitProgressEvent2 += InitProgress2; _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; CICMMetadataType sidecar = _sidecarClass.Create(); if (_preSidecar != null) { _preSidecar.BlockMedia = sidecar.BlockMedia; sidecar = _preSidecar; } if (_dev.IsUsb && _dev.UsbDescriptors != null) { _dumpLog.WriteLine("Reading USB descriptors."); UpdateStatus?.Invoke("Reading USB descriptors."); ret = _outputPlugin.WriteMediaTag(_dev.UsbDescriptors, MediaTagType.USB_Descriptors); if (ret) { sidecar.BlockMedia[0].USB = new USBType { ProductID = _dev.UsbProductId, VendorID = _dev.UsbVendorId, Descriptors = new DumpType { Image = _outputPath, Size = (ulong)_dev.UsbDescriptors.Length, Checksums = Checksum.GetChecksums(_dev.UsbDescriptors).ToArray() } } } ; } if (_dev.IsPcmcia && _dev.Cis != null) { _dumpLog.WriteLine("Reading PCMCIA CIS."); UpdateStatus?.Invoke("Reading PCMCIA CIS."); ret = _outputPlugin.WriteMediaTag(_dev.Cis, MediaTagType.PCMCIA_CIS); if (ret) { sidecar.BlockMedia[0].PCMCIA = new PCMCIAType { CIS = new DumpType { Image = _outputPath, Size = (ulong)_dev.Cis.Length, Checksums = Checksum.GetChecksums(_dev.Cis).ToArray() } } } ; _dumpLog.WriteLine("Decoding PCMCIA CIS."); UpdateStatus?.Invoke("Decoding PCMCIA CIS."); Tuple[] tuples = CIS.GetTuples(_dev.Cis); if (tuples != null) { foreach (Tuple tuple in tuples) { switch (tuple.Code) { case TupleCodes.CISTPL_MANFID: ManufacturerIdentificationTuple manufacturerId = CIS.DecodeManufacturerIdentificationTuple(tuple); if (manufacturerId != null) { sidecar.BlockMedia[0].PCMCIA.ManufacturerCode = manufacturerId.ManufacturerID; sidecar.BlockMedia[0].PCMCIA.CardCode = manufacturerId.CardID; sidecar.BlockMedia[0].PCMCIA.ManufacturerCodeSpecified = true; sidecar.BlockMedia[0].PCMCIA.CardCodeSpecified = true; } break; case TupleCodes.CISTPL_VERS_1: Level1VersionTuple version = CIS.DecodeLevel1VersionTuple(tuple); if (version != null) { sidecar.BlockMedia[0].PCMCIA.Manufacturer = version.Manufacturer; sidecar.BlockMedia[0].PCMCIA.ProductName = version.Product; sidecar.BlockMedia[0].PCMCIA.Compliance = $"{version.MajorVersion}.{version.MinorVersion}"; sidecar.BlockMedia[0].PCMCIA.AdditionalInformation = version.AdditionalInformation; } break; } } } } if (!_private) { DeviceReport.ClearIdentify(ataIdentify); } ret = _outputPlugin.WriteMediaTag(ataIdentify, MediaTagType.ATA_IDENTIFY); if (ret) { sidecar.BlockMedia[0].ATA = new ATAType { Identify = new DumpType { Image = _outputPath, Size = (ulong)cmdBuf.Length, Checksums = Checksum.GetChecksums(cmdBuf).ToArray() } } } ; DateTime chkEnd = DateTime.UtcNow; totalChkDuration = (chkEnd - chkStart).TotalMilliseconds; UpdateStatus?.Invoke($"Sidecar created in {(chkEnd - chkStart).TotalSeconds} seconds."); UpdateStatus?. Invoke($"Average checksum speed {((double)blockSize * (double)(blocks + 1)) / 1024 / (totalChkDuration / 1000):F3} KiB/sec."); _dumpLog.WriteLine("Sidecar created in {0} seconds.", (chkEnd - chkStart).TotalSeconds); _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", ((double)blockSize * (double)(blocks + 1)) / 1024 / (totalChkDuration / 1000)); List <(ulong start, string type)> filesystems = new List <(ulong start, string type)>(); if (sidecar.BlockMedia[0].FileSystemInformation != null) { filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation where partition.FileSystems != null from fileSystem in partition.FileSystems select(partition.StartSector, fileSystem.Type)); } if (filesystems.Count > 0) { foreach (var filesystem in filesystems.Select(o => new { o.start, o.type }).Distinct()) { UpdateStatus?. Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}"); _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); } } (string type, string subType) = CommonTypes.Metadata.MediaType.MediaTypeToString(mediaType); sidecar.BlockMedia[0].DiskType = type; sidecar.BlockMedia[0].DiskSubType = subType; sidecar.BlockMedia[0].Interface = "ATA"; sidecar.BlockMedia[0].LogicalBlocks = blocks; sidecar.BlockMedia[0].PhysicalBlockSize = physicalSectorSize; sidecar.BlockMedia[0].LogicalBlockSize = blockSize; sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer; sidecar.BlockMedia[0].Model = _dev.Model; if (!_private) { sidecar.BlockMedia[0].Serial = _dev.Serial; } sidecar.BlockMedia[0].Size = blocks * blockSize; if (cylinders > 0 && heads > 0 && sectors > 0) { sidecar.BlockMedia[0].Cylinders = cylinders; sidecar.BlockMedia[0].CylindersSpecified = true; sidecar.BlockMedia[0].Heads = heads; sidecar.BlockMedia[0].HeadsSpecified = true; sidecar.BlockMedia[0].SectorsPerTrack = sectors; sidecar.BlockMedia[0].SectorsPerTrackSpecified = true; } UpdateStatus?.Invoke("Writing metadata sidecar"); var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); } UpdateStatus?.Invoke(""); UpdateStatus?. Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); UpdateStatus?. Invoke($"Average speed: {((double)blockSize * (double)(blocks + 1)) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); if (maxSpeed > 0) { UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); } if (minSpeed > 0 && minSpeed < double.MaxValue) { UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); } UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); if (_resume.BadBlocks.Count > 0) { _resume.BadBlocks.Sort(); } UpdateStatus?.Invoke(""); } Statistics.AddMedia(mediaType, true); } else { StoppingErrorMessage?.Invoke("Unable to communicate with ATA device."); } } } }
public static int Invoke(bool verbose, bool debug, string cicmXml, string comments, int count, string creator, string driveFirmwareRevision, string driveManufacturer, string driveModel, string driveSerialNumber, bool force, string inputPath, int lastMediaSequence, string mediaBarcode, string mediaManufacturer, string mediaModel, string mediaPartNumber, int mediaSequence, string mediaSerialNumber, string mediaTitle, string outputPath, string outputOptions, string resumeFile, string format) { MainClass.PrintCopyright(); if (debug) { AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("convert-image"); AaruConsole.DebugWriteLine("Analyze command", "--cicm-xml={0}", cicmXml); AaruConsole.DebugWriteLine("Analyze command", "--comments={0}", comments); AaruConsole.DebugWriteLine("Analyze command", "--count={0}", count); AaruConsole.DebugWriteLine("Analyze command", "--creator={0}", creator); AaruConsole.DebugWriteLine("Analyze command", "--debug={0}", debug); AaruConsole.DebugWriteLine("Analyze command", "--drive-manufacturer={0}", driveManufacturer); AaruConsole.DebugWriteLine("Analyze command", "--drive-model={0}", driveModel); AaruConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", driveFirmwareRevision); AaruConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", driveSerialNumber); AaruConsole.DebugWriteLine("Analyze command", "--force={0}", force); AaruConsole.DebugWriteLine("Analyze command", "--format={0}", format); AaruConsole.DebugWriteLine("Analyze command", "--input={0}", inputPath); AaruConsole.DebugWriteLine("Analyze command", "--media-barcode={0}", mediaBarcode); AaruConsole.DebugWriteLine("Analyze command", "--media-lastsequence={0}", lastMediaSequence); AaruConsole.DebugWriteLine("Analyze command", "--media-manufacturer={0}", mediaManufacturer); AaruConsole.DebugWriteLine("Analyze command", "--media-model={0}", mediaModel); AaruConsole.DebugWriteLine("Analyze command", "--media-partnumber={0}", mediaPartNumber); AaruConsole.DebugWriteLine("Analyze command", "--media-sequence={0}", mediaSequence); AaruConsole.DebugWriteLine("Analyze command", "--media-serial={0}", mediaSerialNumber); AaruConsole.DebugWriteLine("Analyze command", "--media-title={0}", mediaTitle); AaruConsole.DebugWriteLine("Analyze command", "--options={0}", outputOptions); AaruConsole.DebugWriteLine("Analyze command", "--output={0}", outputPath); AaruConsole.DebugWriteLine("Analyze command", "--resume-file={0}", resumeFile); AaruConsole.DebugWriteLine("Analyze command", "--verbose={0}", verbose); Dictionary <string, string> parsedOptions = Core.Options.Parse(outputOptions); AaruConsole.DebugWriteLine("Analyze command", "Parsed options:"); foreach (KeyValuePair <string, string> parsedOption in parsedOptions) { AaruConsole.DebugWriteLine("Analyze command", "{0} = {1}", parsedOption.Key, parsedOption.Value); } if (count == 0) { AaruConsole.ErrorWriteLine("Need to specify more than 0 sectors to copy at once"); return((int)ErrorNumber.InvalidArgument); } Resume resume = null; CICMMetadataType sidecar = null; MediaType mediaType; var xs = new XmlSerializer(typeof(CICMMetadataType)); if (cicmXml != null) { if (File.Exists(cicmXml)) { try { var sr = new StreamReader(cicmXml); sidecar = (CICMMetadataType)xs.Deserialize(sr); sr.Close(); } catch (Exception ex) { AaruConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing..."); AaruConsole.DebugWriteLine("Image conversion", $"{ex}"); return((int)ErrorNumber.InvalidSidecar); } } else { AaruConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing..."); return((int)ErrorNumber.FileNotFound); } } xs = new XmlSerializer(typeof(Resume)); if (resumeFile != null) { if (File.Exists(resumeFile)) { try { var sr = new StreamReader(resumeFile); resume = (Resume)xs.Deserialize(sr); sr.Close(); } catch (Exception ex) { AaruConsole.ErrorWriteLine("Incorrect resume file, not continuing..."); AaruConsole.DebugWriteLine("Image conversion", $"{ex}"); return((int)ErrorNumber.InvalidResume); } } else { AaruConsole.ErrorWriteLine("Could not find resume file, not continuing..."); return((int)ErrorNumber.FileNotFound); } } var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(inputPath); if (inputFilter == null) { AaruConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } if (File.Exists(outputPath)) { AaruConsole.ErrorWriteLine("Output file already exists, not continuing."); return((int)ErrorNumber.DestinationExists); } PluginBase plugins = GetPluginBase.Instance; IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { AaruConsole.WriteLine("Input image format not identified, not proceeding with conversion."); return((int)ErrorNumber.UnrecognizedFormat); } if (verbose) { AaruConsole.VerboseWriteLine("Input image format identified by {0} ({1}).", inputFormat.Name, inputFormat.Id); } else { AaruConsole.WriteLine("Input image format identified by {0}.", inputFormat.Name); } try { if (!inputFormat.Open(inputFilter)) { AaruConsole.WriteLine("Unable to open image format"); AaruConsole.WriteLine("No error given"); return((int)ErrorNumber.CannotOpenFormat); } mediaType = inputFormat.Info.MediaType; // Obsolete types #pragma warning disable 612 switch (mediaType) { case MediaType.SQ1500: mediaType = MediaType.SyJet; break; case MediaType.Bernoulli: mediaType = MediaType.Bernoulli10; break; case MediaType.Bernoulli2: mediaType = MediaType.BernoulliBox2_20; break; } #pragma warning restore 612 AaruConsole.DebugWriteLine("Convert-image command", "Correctly opened image file."); AaruConsole.DebugWriteLine("Convert-image command", "Image without headers is {0} bytes.", inputFormat.Info.ImageSize); AaruConsole.DebugWriteLine("Convert-image command", "Image has {0} sectors.", inputFormat.Info.Sectors); AaruConsole.DebugWriteLine("Convert-image command", "Image identifies media type as {0}.", mediaType); Statistics.AddMediaFormat(inputFormat.Format); Statistics.AddMedia(mediaType, false); Statistics.AddFilter(inputFilter.Name); } catch (Exception ex) { AaruConsole.ErrorWriteLine("Unable to open image format"); AaruConsole.ErrorWriteLine("Error: {0}", ex.Message); AaruConsole.DebugWriteLine("Convert-image command", "Stack trace: {0}", ex.StackTrace); return((int)ErrorNumber.CannotOpenFormat); } List <IWritableImage> candidates = new List <IWritableImage>(); // Try extension if (string.IsNullOrEmpty(format)) { candidates.AddRange(plugins.WritableImages.Values.Where(t => t.KnownExtensions. Contains(Path.GetExtension(outputPath)))); } // Try Id else if (Guid.TryParse(format, out Guid outId)) { candidates.AddRange(plugins.WritableImages.Values.Where(t => t.Id.Equals(outId))); } // Try name else { candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, format, StringComparison. InvariantCultureIgnoreCase))); } if (candidates.Count == 0) { AaruConsole.WriteLine("No plugin supports requested extension."); return((int)ErrorNumber.FormatNotFound); } if (candidates.Count > 1) { AaruConsole.WriteLine("More than one plugin supports requested extension."); return((int)ErrorNumber.TooManyFormats); } IWritableImage outputFormat = candidates[0]; if (verbose) { AaruConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); } else { AaruConsole.WriteLine("Output image format: {0}.", outputFormat.Name); } if (!outputFormat.SupportedMediaTypes.Contains(mediaType)) { AaruConsole.ErrorWriteLine("Output format does not support media type, cannot continue..."); return((int)ErrorNumber.UnsupportedMedia); } foreach (MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags) { if (outputFormat.SupportedMediaTags.Contains(mediaTag) || force) { continue; } AaruConsole.ErrorWriteLine("Converting image will lose media tag {0}, not continuing...", mediaTag); AaruConsole.ErrorWriteLine("If you don't care, use force option."); return((int)ErrorNumber.DataWillBeLost); } bool useLong = inputFormat.Info.ReadableSectorTags.Count != 0; foreach (SectorTagType sectorTag in inputFormat.Info.ReadableSectorTags) { if (outputFormat.SupportedSectorTags.Contains(sectorTag)) { continue; } if (force) { if (sectorTag != SectorTagType.CdTrackFlags && sectorTag != SectorTagType.CdTrackIsrc && sectorTag != SectorTagType.CdSectorSubchannel) { useLong = false; } continue; } AaruConsole.ErrorWriteLine("Converting image will lose sector tag {0}, not continuing...", sectorTag); AaruConsole. ErrorWriteLine("If you don't care, use force option. This will skip all sector tags converting only user data."); return((int)ErrorNumber.DataWillBeLost); } if (!outputFormat.Create(outputPath, mediaType, parsedOptions, inputFormat.Info.Sectors, inputFormat.Info.SectorSize)) { AaruConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage); return((int)ErrorNumber.CannotCreateFormat); } var metadata = new ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion(), Comments = comments ?? inputFormat.Info.Comments, Creator = creator ?? inputFormat.Info.Creator, DriveFirmwareRevision = driveFirmwareRevision ?? inputFormat.Info.DriveFirmwareRevision, DriveManufacturer = driveManufacturer ?? inputFormat.Info.DriveManufacturer, DriveModel = driveModel ?? inputFormat.Info.DriveModel, DriveSerialNumber = driveSerialNumber ?? inputFormat.Info.DriveSerialNumber, LastMediaSequence = lastMediaSequence != 0 ? lastMediaSequence : inputFormat.Info.LastMediaSequence, MediaBarcode = mediaBarcode ?? inputFormat.Info.MediaBarcode, MediaManufacturer = mediaManufacturer ?? inputFormat.Info.MediaManufacturer, MediaModel = mediaModel ?? inputFormat.Info.MediaModel, MediaPartNumber = mediaPartNumber ?? inputFormat.Info.MediaPartNumber, MediaSequence = mediaSequence != 0 ? mediaSequence : inputFormat.Info.MediaSequence, MediaSerialNumber = mediaSerialNumber ?? inputFormat.Info.MediaSerialNumber, MediaTitle = mediaTitle ?? inputFormat.Info.MediaTitle }; if (!outputFormat.SetMetadata(metadata)) { AaruConsole.ErrorWrite("Error {0} setting metadata, ", outputFormat.ErrorMessage); if (!force) { AaruConsole.ErrorWriteLine("not continuing..."); return((int)ErrorNumber.WriteError); } AaruConsole.ErrorWriteLine("continuing..."); } CICMMetadataType cicmMetadata = inputFormat.CicmMetadata; List <DumpHardwareType> dumpHardware = inputFormat.DumpHardware; foreach (MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags) { if (force && !outputFormat.SupportedMediaTags.Contains(mediaTag)) { continue; } AaruConsole.WriteLine("Converting media tag {0}", mediaTag); byte[] tag = inputFormat.ReadDiskTag(mediaTag); if (outputFormat.WriteMediaTag(tag, mediaTag)) { continue; } if (force) { AaruConsole.ErrorWriteLine("Error {0} writing media tag, continuing...", outputFormat.ErrorMessage); } else { AaruConsole.ErrorWriteLine("Error {0} writing media tag, not continuing...", outputFormat.ErrorMessage); return((int)ErrorNumber.WriteError); } } AaruConsole.WriteLine("{0} sectors to convert", inputFormat.Info.Sectors); ulong doneSectors = 0; if (inputFormat is IOpticalMediaImage inputOptical && outputFormat is IWritableOpticalImage outputOptical && inputOptical.Tracks != null) { if (!outputOptical.SetTracks(inputOptical.Tracks)) { AaruConsole.ErrorWriteLine("Error {0} sending tracks list to output image.", outputFormat.ErrorMessage); return((int)ErrorNumber.WriteError); } foreach (Track track in inputOptical.Tracks) { doneSectors = 0; ulong trackSectors = (track.TrackEndSector - track.TrackStartSector) + 1; while (doneSectors < trackSectors) { byte[] sector; uint sectorsToDo; if (trackSectors - doneSectors >= (ulong)count) { sectorsToDo = (uint)count; } else { sectorsToDo = (uint)(trackSectors - doneSectors); } AaruConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)", doneSectors + track.TrackStartSector, doneSectors + sectorsToDo + track.TrackStartSector, (doneSectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors, track.TrackSequence); bool useNotLong = false; bool result = false; if (useLong) { if (sectorsToDo == 1) { sector = inputFormat.ReadSectorLong(doneSectors + track.TrackStartSector); result = outputFormat.WriteSectorLong(sector, doneSectors + track.TrackStartSector); } else { sector = inputFormat.ReadSectorsLong(doneSectors + track.TrackStartSector, sectorsToDo); result = outputFormat.WriteSectorsLong(sector, doneSectors + track.TrackStartSector, sectorsToDo); } if (!result && sector.Length % 2352 != 0) { if (!force) { AaruConsole.ErrorWriteLine("Input image is not returning raw sectors, use force if you want to continue..."); return((int)Errno.InOutError); } useNotLong = true; } } if (!useLong || useNotLong) { if (sectorsToDo == 1) { sector = inputFormat.ReadSector(doneSectors + track.TrackStartSector); result = outputFormat.WriteSector(sector, doneSectors + track.TrackStartSector); } else { sector = inputFormat.ReadSectors(doneSectors + track.TrackStartSector, sectorsToDo); result = outputFormat.WriteSectors(sector, doneSectors + track.TrackStartSector, sectorsToDo); } } if (!result) { if (force) { AaruConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors + track.TrackStartSector); } else { AaruConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors + track.TrackStartSector); return((int)ErrorNumber.WriteError); } } doneSectors += sectorsToDo; } } AaruConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)", inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, inputOptical.Tracks.Count); AaruConsole.WriteLine(); foreach (SectorTagType tag in inputFormat.Info.ReadableSectorTags.OrderBy(t => t)) { if (!useLong) { break; } switch (tag) { case SectorTagType.AppleSectorTag: case SectorTagType.CdSectorSync: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSubHeader: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEcc: // This tags are inline in long sector continue; } if (force && !outputFormat.SupportedSectorTags.Contains(tag)) { continue; } foreach (Track track in inputOptical.Tracks) { doneSectors = 0; ulong trackSectors = (track.TrackEndSector - track.TrackStartSector) + 1; byte[] sector; bool result; switch (tag) { case SectorTagType.CdTrackFlags: case SectorTagType.CdTrackIsrc: AaruConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag, track.TrackSequence, track.TrackSequence / (double)inputOptical.Tracks.Count); sector = inputFormat.ReadSectorTag(track.TrackStartSector, tag); result = outputFormat.WriteSectorTag(sector, track.TrackStartSector, tag); if (!result) { if (force) { AaruConsole.ErrorWriteLine("Error {0} writing tag, continuing...", outputFormat.ErrorMessage); } else { AaruConsole.ErrorWriteLine("Error {0} writing tag, not continuing...", outputFormat.ErrorMessage); return((int)ErrorNumber.WriteError); } } continue; } while (doneSectors < trackSectors) { uint sectorsToDo; if (trackSectors - doneSectors >= (ulong)count) { sectorsToDo = (uint)count; } else { sectorsToDo = (uint)(trackSectors - doneSectors); } AaruConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)", doneSectors + track.TrackStartSector, doneSectors + sectorsToDo + track.TrackStartSector, (doneSectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors, track.TrackSequence, tag); if (sectorsToDo == 1) { sector = inputFormat.ReadSectorTag(doneSectors + track.TrackStartSector, tag); result = outputFormat.WriteSectorTag(sector, doneSectors + track.TrackStartSector, tag); } else { sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo, tag); result = outputFormat.WriteSectorsTag(sector, doneSectors + track.TrackStartSector, sectorsToDo, tag); } if (!result) { if (force) { AaruConsole.ErrorWriteLine("Error {0} writing tag for sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors + track.TrackStartSector); } else { AaruConsole. ErrorWriteLine("Error {0} writing tag for sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors + track.TrackStartSector); return((int)ErrorNumber.WriteError); } } doneSectors += sectorsToDo; } } switch (tag) { case SectorTagType.CdTrackFlags: case SectorTagType.CdTrackIsrc: AaruConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag, inputOptical.Tracks.Count, 1.0); break; default: AaruConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)", inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, inputOptical.Tracks.Count, tag); break; } AaruConsole.WriteLine(); } }
void DumpMs() { const ushort SBC_PROFILE = 0x0001; const uint BLOCK_SIZE = 512; double totalDuration = 0; double currentSpeed = 0; double maxSpeed = double.MinValue; double minSpeed = double.MaxValue; uint blocksToRead = 64; DateTime start; DateTime end; MediaType dskType; bool sense; sense = _dev.ReadCapacity(out byte[] readBuffer, out _, _dev.Timeout, out _); if (sense) { _dumpLog.WriteLine("Could not detect capacity..."); StoppingErrorMessage?.Invoke("Could not detect capacity..."); return; } uint blocks = (uint)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + readBuffer[3]); blocks++; UpdateStatus?. Invoke($"Media has {blocks} blocks of {BLOCK_SIZE} bytes/each. (for a total of {blocks * (ulong)BLOCK_SIZE} bytes)"); if (blocks == 0) { _dumpLog.WriteLine("ERROR: Unable to read medium or empty medium present..."); StoppingErrorMessage?.Invoke("Unable to read medium or empty medium present..."); return; } UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * BLOCK_SIZE} bytes)."); UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time."); UpdateStatus?.Invoke($"Device reports {BLOCK_SIZE} bytes per logical block."); UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}."); if (blocks > 262144) { dskType = MediaType.MemoryStickProDuo; _dumpLog.WriteLine("Media detected as MemoryStick Pro Duo..."); UpdateStatus?.Invoke("Media detected as MemoryStick Pro Duo..."); } else { dskType = MediaType.MemoryStickDuo; _dumpLog.WriteLine("Media detected as MemoryStick Duo..."); UpdateStatus?.Invoke("Media detected as MemoryStick Duo..."); } bool ret; var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, BLOCK_SIZE, blocksToRead, _private); var ibgLog = new IbgLog(_outputPrefix + ".ibg", SBC_PROFILE); ret = _outputPlugin.Create(_outputPath, dskType, _formatOptions, blocks, BLOCK_SIZE); // Cannot create image if (!ret) { _dumpLog.WriteLine("Error creating output image, not continuing."); _dumpLog.WriteLine(_outputPlugin.ErrorMessage); StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine + _outputPlugin.ErrorMessage); return; } start = DateTime.UtcNow; double imageWriteDuration = 0; 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, _dev.FirmwareRevision, _private); if (currentTry == null || extents == null) { StoppingErrorMessage?.Invoke("Could not process resume file, not continuing..."); return; } if (_resume.NextBlock > 0) { _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock); } bool newTrim = false; DateTime timeSpeedStart = DateTime.UtcNow; ulong sectorSpeedStart = 0; InitProgress?.Invoke(); for (ulong i = _resume.NextBlock; i < blocks; i += blocksToRead) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); break; } 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; } #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, blocks); sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)i, BLOCK_SIZE, 0, blocksToRead, false, _dev.Timeout, out double cmdDuration); totalDuration += cmdDuration; if (!sense && !_dev.Error) { mhddLog.Write(i, cmdDuration); ibgLog.Write(i, currentSpeed * 1024); DateTime writeStart = DateTime.Now; _outputPlugin.WriteSectors(readBuffer, i, blocksToRead); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; extents.Add(i, blocksToRead, true); } else { // TODO: Reset device after X errors if (_stopOnError) { return; // TODO: Return more cleanly } if (i + _skip > blocks) { _skip = (uint)(blocks - i); } // Write empty data DateTime writeStart = DateTime.Now; _outputPlugin.WriteSectors(new byte[BLOCK_SIZE * _skip], i, _skip); imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds; for (ulong b = i; b < i + _skip; b++) { _resume.BadBlocks.Add(b); } mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration); ibgLog.Write(i, 0); _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i); i += _skip - blocksToRead; newTrim = true; } sectorSpeedStart += blocksToRead; _resume.NextBlock = i + blocksToRead; double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds; if (elapsed < 1) { continue; } currentSpeed = (sectorSpeedStart * BLOCK_SIZE) / (1048576 * elapsed); sectorSpeedStart = 0; timeSpeedStart = DateTime.UtcNow; } end = DateTime.UtcNow; EndProgress?.Invoke(); mhddLog.Close(); ibgLog.Close(_dev, blocks, BLOCK_SIZE, (end - start).TotalSeconds, currentSpeed * 1024, (BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalDuration / 1000), _devicePath); UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds."); UpdateStatus?. Invoke($"Average dump speed {((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalDuration / 1000):F3} KiB/sec."); UpdateStatus?. Invoke($"Average write speed {((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / imageWriteDuration:F3} KiB/sec."); _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds); _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.", ((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalDuration / 1000)); _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.", ((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / imageWriteDuration); #region Trimming if (_resume.BadBlocks.Count > 0 && !_aborted && _trim && newTrim) { start = DateTime.UtcNow; UpdateStatus?.Invoke("Trimming skipped sectors"); _dumpLog.WriteLine("Trimming skipped sectors"); ulong[] tmpArray = _resume.BadBlocks.ToArray(); InitProgress?.Invoke(); foreach (ulong badSector in tmpArray) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); break; } PulseProgress?.Invoke($"Trimming sector {badSector}"); sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)badSector, BLOCK_SIZE, 0, 1, false, _dev.Timeout, out double cmdDuration); if (sense || _dev.Error) { continue; } _resume.BadBlocks.Remove(badSector); extents.Add(badSector); _outputPlugin.WriteSector(readBuffer, badSector); } EndProgress?.Invoke(); end = DateTime.UtcNow; _dumpLog.WriteLine("Trimmming finished in {0} seconds.", (end - start).TotalSeconds); } #endregion Trimming #region Error handling if (_resume.BadBlocks.Count > 0 && !_aborted && _retryPasses > 0) { int pass = 1; bool forward = true; bool runningPersistent = false; Modes.ModePage?currentModePage = null; byte[] md6; if (_persistent) { Modes.ModePage_01 pg; sense = _dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, _dev.Timeout, out _); if (sense) { sense = _dev.ModeSense10(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01, _dev.Timeout, out _); if (!sense) { Modes.DecodedMode?dcMode10 = Modes.DecodeMode10(readBuffer, _dev.ScsiType); if (dcMode10.HasValue) { foreach (Modes.ModePage modePage in dcMode10.Value.Pages) { if (modePage.Page == 0x01 && modePage.Subpage == 0x00) { currentModePage = modePage; } } } } } else { Modes.DecodedMode?dcMode6 = Modes.DecodeMode6(readBuffer, _dev.ScsiType); if (dcMode6.HasValue) { foreach (Modes.ModePage modePage in dcMode6.Value.Pages) { if (modePage.Page == 0x01 && modePage.Subpage == 0x00) { currentModePage = modePage; } } } } if (currentModePage == null) { pg = new Modes.ModePage_01 { PS = false, AWRE = true, ARRE = true, TB = false, RC = false, EER = true, PER = false, DTE = true, DCR = false, ReadRetryCount = 32 }; currentModePage = new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01(pg) }; } pg = new Modes.ModePage_01 { PS = false, AWRE = false, ARRE = false, TB = true, RC = false, EER = true, PER = false, DTE = false, DCR = false, ReadRetryCount = 255 }; var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), Pages = new[] { new Modes.ModePage { Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01(pg) } } }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks)."); _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks)."); sense = _dev.ModeSelect(md6, out byte[] senseBuf, true, false, _dev.Timeout, out _); if (sense) { UpdateStatus?. Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); AaruConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf)); _dumpLog. WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive."); } else { runningPersistent = true; } } InitProgress?.Invoke(); repeatRetry: ulong[] tmpArray = _resume.BadBlocks.ToArray(); foreach (ulong badSector in tmpArray) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); _dumpLog.WriteLine("Aborted!"); break; } PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : "")); sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)badSector, BLOCK_SIZE, 0, 1, false, _dev.Timeout, out double cmdDuration); totalDuration += cmdDuration; if (!sense && !_dev.Error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); _outputPlugin.WriteSector(readBuffer, badSector); UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}."); _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass); } else if (runningPersistent) { _outputPlugin.WriteSector(readBuffer, badSector); } } if (pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); if (!forward) { _resume.BadBlocks.Reverse(); } goto repeatRetry; } if (runningPersistent && currentModePage.HasValue) { var md = new Modes.DecodedMode { Header = new Modes.ModeHeader(), Pages = new[] { currentModePage.Value } }; md6 = Modes.EncodeMode6(md, _dev.ScsiType); UpdateStatus?.Invoke("Sending MODE SELECT to drive (return device to previous status)."); _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status)."); sense = _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _); } EndProgress?.Invoke(); } #endregion Error handling _resume.BadBlocks.Sort(); foreach (ulong bad in _resume.BadBlocks) { _dumpLog.WriteLine("Sector {0} could not be read.", bad); } currentTry.Extents = ExtentsConverter.ToMetadata(extents); var metadata = new CommonTypes.Structs.ImageInfo { Application = "Aaru", ApplicationVersion = Version.GetVersion() }; if (!_outputPlugin.SetMetadata(metadata)) { ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine + _outputPlugin.ErrorMessage); } _outputPlugin.SetDumpHardware(_resume.Tries); if (_preSidecar != null) { _outputPlugin.SetCicmMetadata(_preSidecar); } _dumpLog.WriteLine("Closing output file."); UpdateStatus?.Invoke("Closing output file."); DateTime closeStart = DateTime.Now; _outputPlugin.Close(); DateTime closeEnd = DateTime.Now; UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds."); _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds); if (_aborted) { UpdateStatus?.Invoke("Aborted!"); _dumpLog.WriteLine("Aborted!"); return; } double totalChkDuration = 0; if (_metadata) { UpdateStatus?.Invoke("Creating sidecar."); _dumpLog.WriteLine("Creating sidecar."); var filters = new FiltersList(); IFilter filter = filters.GetFilter(_outputPath); IMediaImage inputPlugin = ImageFormat.Detect(filter); if (!inputPlugin.Open(filter)) { StoppingErrorMessage?.Invoke("Could not open created image."); return; } DateTime chkStart = DateTime.UtcNow; _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding); _sidecarClass.InitProgressEvent += InitProgress; _sidecarClass.UpdateProgressEvent += UpdateProgress; _sidecarClass.EndProgressEvent += EndProgress; _sidecarClass.InitProgressEvent2 += InitProgress2; _sidecarClass.UpdateProgressEvent2 += UpdateProgress2; _sidecarClass.EndProgressEvent2 += EndProgress2; _sidecarClass.UpdateStatusEvent += UpdateStatus; CICMMetadataType sidecar = _sidecarClass.Create(); end = DateTime.UtcNow; totalChkDuration = (end - chkStart).TotalMilliseconds; UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds."); UpdateStatus?. Invoke($"Average checksum speed {((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalChkDuration / 1000):F3} KiB/sec."); _dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds); _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.", ((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalChkDuration / 1000)); if (_preSidecar != null) { _preSidecar.BlockMedia = sidecar.BlockMedia; sidecar = _preSidecar; } List <(ulong start, string type)> filesystems = new List <(ulong start, string type)>(); if (sidecar.BlockMedia[0].FileSystemInformation != null) { filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation where partition.FileSystems != null from fileSystem in partition.FileSystems select(partition.StartSector, fileSystem.Type)); } if (filesystems.Count > 0) { foreach (var filesystem in filesystems.Select(o => new { o.start, o.type }).Distinct()) { UpdateStatus?.Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}"); _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start); } } sidecar.BlockMedia[0].Dimensions = Dimensions.DimensionsFromMediaType(dskType); (string type, string subType)xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType); sidecar.BlockMedia[0].DiskType = xmlType.type; sidecar.BlockMedia[0].DiskSubType = xmlType.subType; sidecar.BlockMedia[0].Interface = "USB"; sidecar.BlockMedia[0].LogicalBlocks = blocks; sidecar.BlockMedia[0].PhysicalBlockSize = (int)BLOCK_SIZE; sidecar.BlockMedia[0].LogicalBlockSize = (int)BLOCK_SIZE; sidecar.BlockMedia[0].Manufacturer = _dev.Manufacturer; sidecar.BlockMedia[0].Model = _dev.Model; if (!_private) { sidecar.BlockMedia[0].Serial = _dev.Serial; } sidecar.BlockMedia[0].Size = blocks * BLOCK_SIZE; if (_dev.IsRemovable) { sidecar.BlockMedia[0].DumpHardwareArray = _resume.Tries.ToArray(); } UpdateStatus?.Invoke("Writing metadata sidecar"); var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create); var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); } UpdateStatus?.Invoke(""); UpdateStatus?. Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing)."); UpdateStatus?. Invoke($"Average speed: {((double)BLOCK_SIZE * (double)(blocks + 1)) / 1048576 / (totalDuration / 1000):F3} MiB/sec."); if (maxSpeed > 0) { UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec."); } if (minSpeed > 0 && minSpeed < double.MaxValue) { UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec."); } UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read."); UpdateStatus?.Invoke(""); Statistics.AddMedia(dskType, true); }
public static int Invoke(bool debug, bool verbose, uint blockSize, string encodingName, string imagePath, bool tape) { MainClass.PrintCopyright(); if (debug) { AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("create-sidecar"); AaruConsole.DebugWriteLine("Create sidecar command", "--block-size={0}", blockSize); AaruConsole.DebugWriteLine("Create sidecar command", "--debug={0}", debug); AaruConsole.DebugWriteLine("Create sidecar command", "--encoding={0}", encodingName); AaruConsole.DebugWriteLine("Create sidecar command", "--input={0}", imagePath); AaruConsole.DebugWriteLine("Create sidecar command", "--tape={0}", tape); AaruConsole.DebugWriteLine("Create sidecar command", "--verbose={0}", verbose); Encoding encodingClass = null; if (encodingName != null) { try { encodingClass = Claunia.Encoding.Encoding.GetEncoding(encodingName); if (verbose) { AaruConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName); } } catch (ArgumentException) { AaruConsole.ErrorWriteLine("Specified encoding is not supported."); return((int)ErrorNumber.EncodingUnknown); } } if (File.Exists(imagePath)) { if (tape) { AaruConsole.ErrorWriteLine("You cannot use --tape option when input is a file."); return((int)ErrorNumber.ExpectedDirectory); } var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(imagePath); if (inputFilter == null) { AaruConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } try { IMediaImage imageFormat = ImageFormat.Detect(inputFilter); if (imageFormat == null) { AaruConsole.WriteLine("Image format not identified, not proceeding with analysis."); return((int)ErrorNumber.UnrecognizedFormat); } if (verbose) { AaruConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); } else { AaruConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); } try { if (!imageFormat.Open(inputFilter)) { AaruConsole.WriteLine("Unable to open image format"); AaruConsole.WriteLine("No error given"); return((int)ErrorNumber.CannotOpenFormat); } AaruConsole.DebugWriteLine("Analyze command", "Correctly opened image file."); } catch (Exception ex) { AaruConsole.ErrorWriteLine("Unable to open image format"); AaruConsole.ErrorWriteLine("Error: {0}", ex.Message); return((int)ErrorNumber.CannotOpenFormat); } Statistics.AddMediaFormat(imageFormat.Format); Statistics.AddFilter(inputFilter.Name); var sidecarClass = new Sidecar(imageFormat, imagePath, inputFilter.Id, encodingClass); sidecarClass.InitProgressEvent += Progress.InitProgress; sidecarClass.UpdateProgressEvent += Progress.UpdateProgress; sidecarClass.EndProgressEvent += Progress.EndProgress; sidecarClass.InitProgressEvent2 += Progress.InitProgress2; sidecarClass.UpdateProgressEvent2 += Progress.UpdateProgress2; sidecarClass.EndProgressEvent2 += Progress.EndProgress2; sidecarClass.UpdateStatusEvent += Progress.UpdateStatus; System.Console.CancelKeyPress += (sender, e) => { e.Cancel = true; sidecarClass.Abort(); }; CICMMetadataType sidecar = sidecarClass.Create(); AaruConsole.WriteLine("Writing metadata sidecar"); var xmlFs = new FileStream(Path.Combine(Path.GetDirectoryName(imagePath) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(imagePath) + ".cicm.xml"), FileMode.CreateNew); var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); } catch (Exception ex) { AaruConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); AaruConsole.DebugWriteLine("Analyze command", ex.StackTrace); return((int)ErrorNumber.UnexpectedException); } } else if (Directory.Exists(imagePath)) { if (!tape) { AaruConsole.ErrorWriteLine("Cannot create a sidecar from a directory."); return((int)ErrorNumber.ExpectedFile); } string[] contents = Directory.GetFiles(imagePath, "*", SearchOption.TopDirectoryOnly); List <string> files = contents.Where(file => new FileInfo(file).Length % blockSize == 0).ToList(); files.Sort(StringComparer.CurrentCultureIgnoreCase); var sidecarClass = new Sidecar(); sidecarClass.InitProgressEvent += Progress.InitProgress; sidecarClass.UpdateProgressEvent += Progress.UpdateProgress; sidecarClass.EndProgressEvent += Progress.EndProgress; sidecarClass.InitProgressEvent2 += Progress.InitProgress2; sidecarClass.UpdateProgressEvent2 += Progress.UpdateProgress2; sidecarClass.EndProgressEvent2 += Progress.EndProgress2; sidecarClass.UpdateStatusEvent += Progress.UpdateStatus; CICMMetadataType sidecar = sidecarClass.BlockTape(Path.GetFileName(imagePath), files, blockSize); AaruConsole.WriteLine("Writing metadata sidecar"); var xmlFs = new FileStream(Path.Combine(Path.GetDirectoryName(imagePath) ?? throw new InvalidOperationException(), Path.GetFileNameWithoutExtension(imagePath) + ".cicm.xml"), FileMode.CreateNew); var xmlSer = new XmlSerializer(typeof(CICMMetadataType)); xmlSer.Serialize(xmlFs, sidecar); xmlFs.Close(); } else { AaruConsole.ErrorWriteLine("The specified input file cannot be found."); } return((int)ErrorNumber.NoError); }
public static int Invoke(bool debug, bool verbose, string encoding, bool xattrs, string imagePath, string @namespace, string outputDir, string options) { MainClass.PrintCopyright(); if (debug) { AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("extract-files"); AaruConsole.DebugWriteLine("Extract-Files command", "--debug={0}", debug); AaruConsole.DebugWriteLine("Extract-Files command", "--encoding={0}", encoding); AaruConsole.DebugWriteLine("Extract-Files command", "--input={0}", imagePath); AaruConsole.DebugWriteLine("Extract-Files command", "--options={0}", options); AaruConsole.DebugWriteLine("Extract-Files command", "--output={0}", outputDir); AaruConsole.DebugWriteLine("Extract-Files command", "--verbose={0}", verbose); AaruConsole.DebugWriteLine("Extract-Files command", "--xattrs={0}", xattrs); var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(imagePath); Dictionary <string, string> parsedOptions = Core.Options.Parse(options); AaruConsole.DebugWriteLine("Extract-Files command", "Parsed options:"); foreach (KeyValuePair <string, string> parsedOption in parsedOptions) { AaruConsole.DebugWriteLine("Extract-Files command", "{0} = {1}", parsedOption.Key, parsedOption.Value); } parsedOptions.Add("debug", debug.ToString()); if (inputFilter == null) { AaruConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } Encoding encodingClass = null; if (encoding != null) { try { encodingClass = Claunia.Encoding.Encoding.GetEncoding(encoding); if (verbose) { AaruConsole.VerboseWriteLine("Using encoding for {0}.", encodingClass.EncodingName); } } catch (ArgumentException) { AaruConsole.ErrorWriteLine("Specified encoding is not supported."); return((int)ErrorNumber.EncodingUnknown); } } PluginBase plugins = GetPluginBase.Instance; try { IMediaImage imageFormat = ImageFormat.Detect(inputFilter); if (imageFormat == null) { AaruConsole.WriteLine("Image format not identified, not proceeding with analysis."); return((int)ErrorNumber.UnrecognizedFormat); } if (verbose) { AaruConsole.VerboseWriteLine("Image format identified by {0} ({1}).", imageFormat.Name, imageFormat.Id); } else { AaruConsole.WriteLine("Image format identified by {0}.", imageFormat.Name); } if (outputDir == null) { AaruConsole.WriteLine("Output directory missing."); return((int)ErrorNumber.MissingArgument); } if (Directory.Exists(outputDir) || File.Exists(outputDir)) { AaruConsole.ErrorWriteLine("Destination exists, aborting."); return((int)ErrorNumber.DestinationExists); } Directory.CreateDirectory(outputDir); try { if (!imageFormat.Open(inputFilter)) { AaruConsole.WriteLine("Unable to open image format"); AaruConsole.WriteLine("No error given"); return((int)ErrorNumber.CannotOpenFormat); } AaruConsole.DebugWriteLine("Extract-Files command", "Correctly opened image file."); AaruConsole.DebugWriteLine("Extract-Files command", "Image without headers is {0} bytes.", imageFormat.Info.ImageSize); AaruConsole.DebugWriteLine("Extract-Files command", "Image has {0} sectors.", imageFormat.Info.Sectors); AaruConsole.DebugWriteLine("Extract-Files command", "Image identifies disk type as {0}.", imageFormat.Info.MediaType); Statistics.AddMediaFormat(imageFormat.Format); Statistics.AddMedia(imageFormat.Info.MediaType, false); Statistics.AddFilter(inputFilter.Name); } catch (Exception ex) { AaruConsole.ErrorWriteLine("Unable to open image format"); AaruConsole.ErrorWriteLine("Error: {0}", ex.Message); return((int)ErrorNumber.CannotOpenFormat); } List <Partition> partitions = Core.Partitions.GetAll(imageFormat); Core.Partitions.AddSchemesToStats(partitions); if (partitions.Count == 0) { AaruConsole.DebugWriteLine("Ls command", "No partitions found"); partitions.Add(new Partition { Description = "Whole device", Length = imageFormat.Info.Sectors, Offset = 0, Size = imageFormat.Info.SectorSize * imageFormat.Info.Sectors, Sequence = 1, Start = 0 }); } AaruConsole.WriteLine("{0} partitions found.", partitions.Count); for (int i = 0; i < partitions.Count; i++) { AaruConsole.WriteLine(); AaruConsole.WriteLine("Partition {0}:", partitions[i].Sequence); AaruConsole.WriteLine("Identifying filesystem on partition"); Core.Filesystems.Identify(imageFormat, out List <string> idPlugins, partitions[i]); if (idPlugins.Count == 0) { AaruConsole.WriteLine("Filesystem not identified"); } else { IReadOnlyFilesystem plugin; Errno error; if (idPlugins.Count > 1) { AaruConsole.WriteLine($"Identified by {idPlugins.Count} plugins"); foreach (string pluginName in idPlugins) { if (plugins.ReadOnlyFilesystems.TryGetValue(pluginName, out plugin)) { AaruConsole.WriteLine($"As identified by {plugin.Name}."); var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?. Invoke(new object[] {}); error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions, @namespace); if (error == Errno.NoError) { string volumeName = string.IsNullOrEmpty(fs.XmlFsType.VolumeName) ? "NO NAME" : fs.XmlFsType.VolumeName; ExtractFilesInDir("/", fs, volumeName, outputDir, xattrs); Statistics.AddFilesystem(fs.XmlFsType.Type); } else { AaruConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } else { plugins.ReadOnlyFilesystems.TryGetValue(idPlugins[0], out plugin); if (plugin == null) { continue; } AaruConsole.WriteLine($"Identified by {plugin.Name}."); var fs = (IReadOnlyFilesystem)plugin.GetType().GetConstructor(Type.EmptyTypes)?. Invoke(new object[] {}); error = fs.Mount(imageFormat, partitions[i], encodingClass, parsedOptions, @namespace); if (error == Errno.NoError) { string volumeName = string.IsNullOrEmpty(fs.XmlFsType.VolumeName) ? "NO NAME" : fs.XmlFsType.VolumeName; ExtractFilesInDir("/", fs, volumeName, outputDir, xattrs); Statistics.AddFilesystem(fs.XmlFsType.Type); } else { AaruConsole.ErrorWriteLine("Unable to mount device, error {0}", error.ToString()); } } } } } catch (Exception ex) { AaruConsole.ErrorWriteLine($"Error reading file: {ex.Message}"); AaruConsole.DebugWriteLine("Extract-Files command", ex.StackTrace); return((int)ErrorNumber.UnexpectedException); } return((int)ErrorNumber.NoError); }
public static int Invoke(bool debug, bool verbose, string imagePath, ulong length, bool longSectors, ulong start, ushort width) { MainClass.PrintCopyright(); if (debug) { DicConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { DicConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("print-hex"); DicConsole.DebugWriteLine("PrintHex command", "--debug={0}", debug); DicConsole.DebugWriteLine("PrintHex command", "--input={0}", imagePath); DicConsole.DebugWriteLine("PrintHex command", "--length={0}", length); DicConsole.DebugWriteLine("PrintHex command", "--long-sectors={0}", longSectors); DicConsole.DebugWriteLine("PrintHex command", "--start={0}", start); DicConsole.DebugWriteLine("PrintHex command", "--verbose={0}", verbose); DicConsole.DebugWriteLine("PrintHex command", "--width={0}", width); var filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(imagePath); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return((int)ErrorNumber.CannotOpenFile); } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not verifying"); return((int)ErrorNumber.UnrecognizedFormat); } inputFormat.Open(inputFilter); for (ulong i = 0; i < length; i++) { DicConsole.WriteLine("Sector {0}", start + i); if (inputFormat.Info.ReadableSectorTags == null) { DicConsole. WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data."); longSectors = false; } else { if (inputFormat.Info.ReadableSectorTags.Count == 0) { DicConsole. WriteLine("Requested sectors with tags, unsupported by underlying image format, printing only user data."); longSectors = false; } } byte[] sector = longSectors ? inputFormat.ReadSectorLong(start + i) : inputFormat.ReadSector(start + i); PrintHex.PrintHexArray(sector, width); } return((int)ErrorNumber.NoError); }
public static int Invoke(bool debug, bool verbose, string imagePath1, string imagePath2) { MainClass.PrintCopyright(); if (debug) { AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; } if (verbose) { AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; } Statistics.AddCommand("compare"); AaruConsole.DebugWriteLine("Compare command", "--debug={0}", debug); AaruConsole.DebugWriteLine("Compare command", "--input1={0}", imagePath1); AaruConsole.DebugWriteLine("Compare command", "--input2={0}", imagePath2); AaruConsole.DebugWriteLine("Compare command", "--verbose={0}", verbose); var filtersList = new FiltersList(); IFilter inputFilter1 = filtersList.GetFilter(imagePath1); filtersList = new FiltersList(); IFilter inputFilter2 = filtersList.GetFilter(imagePath2); if (inputFilter1 == null) { AaruConsole.ErrorWriteLine("Cannot open input file 1"); return((int)ErrorNumber.CannotOpenFile); } if (inputFilter2 == null) { AaruConsole.ErrorWriteLine("Cannot open input file 2"); return((int)ErrorNumber.CannotOpenFile); } IMediaImage input1Format = ImageFormat.Detect(inputFilter1); IMediaImage input2Format = ImageFormat.Detect(inputFilter2); if (input1Format == null) { AaruConsole.ErrorWriteLine("Input file 1 format not identified, not proceeding with comparison."); return((int)ErrorNumber.UnrecognizedFormat); } if (verbose) { AaruConsole.VerboseWriteLine("Input file 1 format identified by {0} ({1}).", input1Format.Name, input1Format.Id); } else { AaruConsole.WriteLine("Input file 1 format identified by {0}.", input1Format.Name); } if (input2Format == null) { AaruConsole.ErrorWriteLine("Input file 2 format not identified, not proceeding with comparison."); return((int)ErrorNumber.UnrecognizedFormat); } if (verbose) { AaruConsole.VerboseWriteLine("Input file 2 format identified by {0} ({1}).", input2Format.Name, input2Format.Id); } else { AaruConsole.WriteLine("Input file 2 format identified by {0}.", input2Format.Name); } input1Format.Open(inputFilter1); input2Format.Open(inputFilter2); Statistics.AddMediaFormat(input1Format.Format); Statistics.AddMediaFormat(input2Format.Format); Statistics.AddMedia(input1Format.Info.MediaType, false); Statistics.AddMedia(input2Format.Info.MediaType, false); Statistics.AddFilter(inputFilter1.Name); Statistics.AddFilter(inputFilter2.Name); var sb = new StringBuilder(); if (verbose) { sb.AppendFormat("{0,50}{1,20}", "Disc image 1", "Disc image 2").AppendLine(); sb.AppendLine("================================================================================================"); sb.AppendFormat("{0,-38}{1}", "File", imagePath1).AppendLine(); sb.AppendFormat(" {0}", imagePath2). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Disc image format", input1Format.Name, input2Format.Name). AppendLine(); } else { sb.AppendFormat("Disc image 1: {0}", imagePath1).AppendLine(); sb.AppendFormat("Disc image 2: {0}", imagePath2).AppendLine(); } bool imagesDiffer = false; ImageInfo image1Info = input1Format.Info; ImageInfo image2Info = input2Format.Info; Dictionary <MediaTagType, byte[]> image1DiskTags = new Dictionary <MediaTagType, byte[]>(); Dictionary <MediaTagType, byte[]> image2DiskTags = new Dictionary <MediaTagType, byte[]>(); foreach (MediaTagType diskTag in Enum.GetValues(typeof(MediaTagType))) { try { byte[] tempArray = input1Format.ReadDiskTag(diskTag); image1DiskTags.Add(diskTag, tempArray); } #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch { // ignored } #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body } foreach (MediaTagType diskTag in Enum.GetValues(typeof(MediaTagType))) { try { byte[] tempArray = input2Format.ReadDiskTag(diskTag); image2DiskTags.Add(diskTag, tempArray); } #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch { // ignored } #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body } if (verbose) { sb.AppendFormat("{0,-38}{1,-20}{2}", "Has partitions?", image1Info.HasPartitions, image2Info.HasPartitions).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Has sessions?", image1Info.HasSessions, image2Info.HasSessions). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Image size", image1Info.ImageSize, image2Info.ImageSize). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Sectors", image1Info.Sectors, image2Info.Sectors).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Sector size", image1Info.SectorSize, image2Info.SectorSize). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Creation time", image1Info.CreationTime, image2Info.CreationTime). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Last modification time", image1Info.LastModificationTime, image2Info.LastModificationTime).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk type", image1Info.MediaType, image2Info.MediaType). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Image version", image1Info.Version, image2Info.Version). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Image application", image1Info.Application, image2Info.Application).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Image application version", image1Info.ApplicationVersion, image2Info.ApplicationVersion).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Image creator", image1Info.Creator, image2Info.Creator). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Image name", image1Info.MediaTitle, image2Info.MediaTitle). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Image comments", image1Info.Comments, image2Info.Comments). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Image comments", image1Info.Comments, image2Info.Comments). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk manufacturer", image1Info.MediaManufacturer, image2Info.MediaManufacturer).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk model", image1Info.MediaModel, image2Info.MediaModel). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk serial number", image1Info.MediaSerialNumber, image2Info.MediaSerialNumber).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk barcode", image1Info.MediaBarcode, image2Info.MediaBarcode). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk part no.", image1Info.MediaPartNumber, image2Info.MediaPartNumber).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Disk sequence", image1Info.MediaSequence, image2Info.MediaSequence).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Last disk on sequence", image1Info.LastMediaSequence, image2Info.LastMediaSequence).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Drive manufacturer", image1Info.DriveManufacturer, image2Info.DriveManufacturer).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Drive firmware revision", image1Info.DriveFirmwareRevision, image2Info.DriveFirmwareRevision).AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Drive model", image1Info.DriveModel, image2Info.DriveModel). AppendLine(); sb.AppendFormat("{0,-38}{1,-20}{2}", "Drive serial number", image1Info.DriveSerialNumber, image2Info.DriveSerialNumber).AppendLine(); foreach (MediaTagType diskTag in (Enum.GetValues(typeof(MediaTagType)) as MediaTagType[]).OrderBy(e => e.ToString())) { sb.AppendFormat("{0,-38}{1,-20}{2}", $"Has {diskTag}?", image1DiskTags.ContainsKey(diskTag), image2DiskTags.ContainsKey(diskTag)).AppendLine(); } } AaruConsole.WriteLine("Comparing disk image characteristics"); if (image1Info.HasPartitions != image2Info.HasPartitions) { imagesDiffer = true; if (!verbose) { sb.AppendLine("Image partitioned status differ"); } } if (image1Info.HasSessions != image2Info.HasSessions) { imagesDiffer = true; if (!verbose) { sb.AppendLine("Image session status differ"); } } if (image1Info.Sectors != image2Info.Sectors) { imagesDiffer = true; if (!verbose) { sb.AppendLine("Image sectors differ"); } } if (image1Info.SectorSize != image2Info.SectorSize) { imagesDiffer = true; if (!verbose) { sb.AppendLine("Image sector size differ"); } } if (image1Info.MediaType != image2Info.MediaType) { imagesDiffer = true; if (!verbose) { sb.AppendLine("Disk type differ"); } } ulong leastSectors; if (image1Info.Sectors < image2Info.Sectors) { imagesDiffer = true; leastSectors = image1Info.Sectors; if (!verbose) { sb.AppendLine("Image 2 has more sectors"); } } else if (image1Info.Sectors > image2Info.Sectors) { imagesDiffer = true; leastSectors = image2Info.Sectors; if (!verbose) { sb.AppendLine("Image 1 has more sectors"); } } else { leastSectors = image1Info.Sectors; } AaruConsole.WriteLine("Comparing sectors..."); for (ulong sector = 0; sector < leastSectors; sector++) { AaruConsole.Write("\rComparing sector {0} of {1}...", sector + 1, leastSectors); try { byte[] image1Sector = input1Format.ReadSector(sector); byte[] image2Sector = input2Format.ReadSector(sector); ArrayHelpers.CompareBytes(out bool different, out bool sameSize, image1Sector, image2Sector); if (different) { imagesDiffer = true; sb.AppendFormat("Sector {0} is different", sector).AppendLine(); } else if (!sameSize) { imagesDiffer = true; sb. AppendFormat("Sector {0} has different sizes ({1} bytes in image 1, {2} in image 2) but are otherwise identical", sector, image1Sector.LongLength, image2Sector.LongLength).AppendLine(); } } #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body catch { // ignored } #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body } AaruConsole.WriteLine(); sb.AppendLine(imagesDiffer ? "Images differ" : "Images do not differ"); AaruConsole.WriteLine(sb.ToString()); return((int)ErrorNumber.NoError); }
public static void DoConvert(ConvertImageOptions options) { DicConsole.DebugWriteLine("Analyze command", "--debug={0}", options.Debug); DicConsole.DebugWriteLine("Analyze command", "--verbose={0}", options.Verbose); DicConsole.DebugWriteLine("Analyze command", "--input={0}", options.InputFile); DicConsole.DebugWriteLine("Analyze command", "--output={0}", options.OutputFile); DicConsole.DebugWriteLine("Analyze command", "--format={0}", options.OutputFormat); DicConsole.DebugWriteLine("Analyze command", "--count={0}", options.Count); DicConsole.DebugWriteLine("Analyze command", "--force={0}", options.Force); DicConsole.DebugWriteLine("Analyze command", "--creator={0}", options.Creator); DicConsole.DebugWriteLine("Analyze command", "--media-title={0}", options.MediaTitle); DicConsole.DebugWriteLine("Analyze command", "--comments={0}", options.Comments); DicConsole.DebugWriteLine("Analyze command", "--media-manufacturer={0}", options.MediaManufacturer); DicConsole.DebugWriteLine("Analyze command", "--media-model={0}", options.MediaModel); DicConsole.DebugWriteLine("Analyze command", "--media-serial={0}", options.MediaSerialNumber); DicConsole.DebugWriteLine("Analyze command", "--media-barcode={0}", options.MediaBarcode); DicConsole.DebugWriteLine("Analyze command", "--media-partnumber={0}", options.MediaPartNumber); DicConsole.DebugWriteLine("Analyze command", "--media-sequence={0}", options.MediaSequence); DicConsole.DebugWriteLine("Analyze command", "--media-lastsequence={0}", options.LastMediaSequence); DicConsole.DebugWriteLine("Analyze command", "--drive-manufacturer={0}", options.DriveManufacturer); DicConsole.DebugWriteLine("Analyze command", "--drive-model={0}", options.DriveModel); DicConsole.DebugWriteLine("Analyze command", "--drive-serial={0}", options.DriveSerialNumber); DicConsole.DebugWriteLine("Analyze command", "--drive-revision={0}", options.DriveFirmwareRevision); DicConsole.DebugWriteLine("Analyze command", "--cicm-xml={0}", options.CicmXml); DicConsole.DebugWriteLine("Analyze command", "--resume-file={0}", options.ResumeFile); DicConsole.DebugWriteLine("Analyze command", "--options={0}", options.Options); Dictionary <string, string> parsedOptions = Options.Parse(options.Options); DicConsole.DebugWriteLine("Analyze command", "Parsed options:"); foreach (KeyValuePair <string, string> parsedOption in parsedOptions) { DicConsole.DebugWriteLine("Analyze command", "{0} = {1}", parsedOption.Key, parsedOption.Value); } if (options.Count == 0) { DicConsole.ErrorWriteLine("Need to specify more than 0 sectors to copy at once"); return; } Resume resume = null; CICMMetadataType sidecar = null; XmlSerializer xs = new XmlSerializer(typeof(CICMMetadataType)); if (options.CicmXml != null) { if (File.Exists(options.CicmXml)) { try { StreamReader sr = new StreamReader(options.CicmXml); sidecar = (CICMMetadataType)xs.Deserialize(sr); sr.Close(); } catch { DicConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing..."); return; } } else { DicConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing..."); return; } } xs = new XmlSerializer(typeof(Resume)); if (options.ResumeFile != null) { if (File.Exists(options.ResumeFile)) { try { StreamReader sr = new StreamReader(options.ResumeFile); resume = (Resume)xs.Deserialize(sr); sr.Close(); } catch { DicConsole.ErrorWriteLine("Incorrect resume file, not continuing..."); return; } } else { DicConsole.ErrorWriteLine("Could not find resume file, not continuing..."); return; } } FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(options.InputFile); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return; } if (File.Exists(options.OutputFile)) { DicConsole.ErrorWriteLine("Output file already exists, not continuing."); return; } PluginBase plugins = GetPluginBase.Instance; IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { DicConsole.WriteLine("Input image format not identified, not proceeding with conversion."); return; } if (options.Verbose) { DicConsole.VerboseWriteLine("Input image format identified by {0} ({1}).", inputFormat.Name, inputFormat.Id); } else { DicConsole.WriteLine("Input image format identified by {0}.", inputFormat.Name); } try { if (!inputFormat.Open(inputFilter)) { DicConsole.WriteLine("Unable to open image format"); DicConsole.WriteLine("No error given"); return; } DicConsole.DebugWriteLine("Convert-image command", "Correctly opened image file."); DicConsole.DebugWriteLine("Convert-image command", "Image without headers is {0} bytes.", inputFormat.Info.ImageSize); DicConsole.DebugWriteLine("Convert-image command", "Image has {0} sectors.", inputFormat.Info.Sectors); DicConsole.DebugWriteLine("Convert-image command", "Image identifies media type as {0}.", inputFormat.Info.MediaType); Core.Statistics.AddMediaFormat(inputFormat.Format); Core.Statistics.AddMedia(inputFormat.Info.MediaType, false); Core.Statistics.AddFilter(inputFilter.Name); } catch (Exception ex) { DicConsole.ErrorWriteLine("Unable to open image format"); DicConsole.ErrorWriteLine("Error: {0}", ex.Message); DicConsole.DebugWriteLine("Convert-image command", "Stack trace: {0}", ex.StackTrace); return; } List <IWritableImage> candidates = new List <IWritableImage>(); // Try extension if (string.IsNullOrEmpty(options.OutputFormat)) { candidates.AddRange(plugins.WritableImages.Values.Where(t => t.KnownExtensions .Contains(Path.GetExtension(options .OutputFile)))); } // Try Id else if (Guid.TryParse(options.OutputFormat, out Guid outId)) { candidates.AddRange(plugins.WritableImages.Values.Where(t => t.Id.Equals(outId))); } // Try name else { candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, options.OutputFormat, StringComparison .InvariantCultureIgnoreCase))); } if (candidates.Count == 0) { DicConsole.WriteLine("No plugin supports requested extension."); return; } if (candidates.Count > 1) { DicConsole.WriteLine("More than one plugin supports requested extension."); return; } IWritableImage outputFormat = candidates[0]; if (options.Verbose) { DicConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); } else { DicConsole.WriteLine("Output image format: {0}.", outputFormat.Name); } if (!outputFormat.SupportedMediaTypes.Contains(inputFormat.Info.MediaType)) { DicConsole.ErrorWriteLine("Output format does not support media type, cannot continue..."); return; } foreach (MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags) { if (outputFormat.SupportedMediaTags.Contains(mediaTag) || options.Force) { continue; } DicConsole.ErrorWriteLine("Converting image will lose media tag {0}, not continuing...", mediaTag); DicConsole.ErrorWriteLine("If you don't care, use force option."); return; } bool useLong = inputFormat.Info.ReadableSectorTags.Count != 0; foreach (SectorTagType sectorTag in inputFormat.Info.ReadableSectorTags) { if (outputFormat.SupportedSectorTags.Contains(sectorTag)) { continue; } if (options.Force) { if (sectorTag != SectorTagType.CdTrackFlags && sectorTag != SectorTagType.CdTrackIsrc && sectorTag != SectorTagType.CdSectorSubchannel) { useLong = false; } continue; } DicConsole.ErrorWriteLine("Converting image will lose sector tag {0}, not continuing...", sectorTag); DicConsole .ErrorWriteLine("If you don't care, use force option. This will skip all sector tags converting only user data."); return; } if (!outputFormat.Create(options.OutputFile, inputFormat.Info.MediaType, parsedOptions, inputFormat.Info.Sectors, inputFormat.Info.SectorSize)) { DicConsole.ErrorWriteLine("Error {0} creating output image.", outputFormat.ErrorMessage); return; } CommonTypes.Structs.ImageInfo metadata = new CommonTypes.Structs.ImageInfo { Application = "DiscImageChef", ApplicationVersion = Version.GetVersion(), Comments = options.Comments ?? inputFormat.Info.Comments, Creator = options.Creator ?? inputFormat.Info.Creator, DriveFirmwareRevision = options.DriveFirmwareRevision ?? inputFormat.Info.DriveFirmwareRevision, DriveManufacturer = options.DriveManufacturer ?? inputFormat.Info.DriveManufacturer, DriveModel = options.DriveModel ?? inputFormat.Info.DriveModel, DriveSerialNumber = options.DriveSerialNumber ?? inputFormat.Info.DriveSerialNumber, LastMediaSequence = options.LastMediaSequence != 0 ? options.LastMediaSequence : inputFormat.Info.LastMediaSequence, MediaBarcode = options.MediaBarcode ?? inputFormat.Info.MediaBarcode, MediaManufacturer = options.MediaManufacturer ?? inputFormat.Info.MediaManufacturer, MediaModel = options.MediaModel ?? inputFormat.Info.MediaModel, MediaPartNumber = options.MediaPartNumber ?? inputFormat.Info.MediaPartNumber, MediaSequence = options.MediaSequence != 0 ? options.MediaSequence : inputFormat.Info.MediaSequence, MediaSerialNumber = options.MediaSerialNumber ?? inputFormat.Info.MediaSerialNumber, MediaTitle = options.MediaTitle ?? inputFormat.Info.MediaTitle }; if (!outputFormat.SetMetadata(metadata)) { DicConsole.ErrorWrite("Error {0} setting metadata, ", outputFormat.ErrorMessage); if (!options.Force) { DicConsole.ErrorWriteLine("not continuing..."); return; } DicConsole.ErrorWriteLine("continuing..."); } List <Track> tracks; try { tracks = inputFormat.Tracks; } catch (Exception) { tracks = null; } CICMMetadataType cicmMetadata = inputFormat.CicmMetadata; List <DumpHardwareType> dumpHardware = inputFormat.DumpHardware; if (tracks != null) { if (!outputFormat.SetTracks(tracks)) { DicConsole.ErrorWriteLine("Error {0} sending tracks list to output image.", outputFormat.ErrorMessage); return; } } foreach (MediaTagType mediaTag in inputFormat.Info.ReadableMediaTags) { if (options.Force && !outputFormat.SupportedMediaTags.Contains(mediaTag)) { continue; } DicConsole.WriteLine("Converting media tag {0}", mediaTag); byte[] tag = inputFormat.ReadDiskTag(mediaTag); if (outputFormat.WriteMediaTag(tag, mediaTag)) { continue; } if (options.Force) { DicConsole.ErrorWriteLine("Error {0} writing media tag, continuing...", outputFormat.ErrorMessage); } else { DicConsole.ErrorWriteLine("Error {0} writing media tag, not continuing...", outputFormat.ErrorMessage); return; } } DicConsole.WriteLine("{0} sectors to convert", inputFormat.Info.Sectors); ulong doneSectors = 0; if (tracks == null) { DicConsole.WriteLine("Setting geometry to {0} cylinders, {1} heads and {2} sectors per track", inputFormat.Info.Cylinders, inputFormat.Info.Heads, inputFormat.Info.SectorsPerTrack); if (!outputFormat.SetGeometry(inputFormat.Info.Cylinders, inputFormat.Info.Heads, inputFormat.Info.SectorsPerTrack)) { DicConsole.ErrorWriteLine("Error {0} setting geometry, image may be incorrect, continuing...", outputFormat.ErrorMessage); } while (doneSectors < inputFormat.Info.Sectors) { byte[] sector; uint sectorsToDo; if (inputFormat.Info.Sectors - doneSectors >= (ulong)options.Count) { sectorsToDo = (uint)options.Count; } else { sectorsToDo = (uint)(inputFormat.Info.Sectors - doneSectors); } DicConsole.Write("\rConverting sectors {0} to {1} ({2:P2} done)", doneSectors, doneSectors + sectorsToDo, doneSectors / (double)inputFormat.Info.Sectors); bool result; if (useLong) { if (sectorsToDo == 1) { sector = inputFormat.ReadSectorLong(doneSectors); result = outputFormat.WriteSectorLong(sector, doneSectors); } else { sector = inputFormat.ReadSectorsLong(doneSectors, sectorsToDo); result = outputFormat.WriteSectorsLong(sector, doneSectors, sectorsToDo); } } else { if (sectorsToDo == 1) { sector = inputFormat.ReadSector(doneSectors); result = outputFormat.WriteSector(sector, doneSectors); } else { sector = inputFormat.ReadSectors(doneSectors, sectorsToDo); result = outputFormat.WriteSectors(sector, doneSectors, sectorsToDo); } } if (!result) { if (options.Force) { DicConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors); } else { DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors); return; } } doneSectors += sectorsToDo; } DicConsole.Write("\rConverting sectors {0} to {1} ({2:P2} done)", inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0); DicConsole.WriteLine(); foreach (SectorTagType tag in inputFormat.Info.ReadableSectorTags) { if (!useLong) { break; } switch (tag) { case SectorTagType.AppleSectorTag: case SectorTagType.CdSectorSync: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSubHeader: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEcc: // This tags are inline in long sector continue; } if (options.Force && !outputFormat.SupportedSectorTags.Contains(tag)) { continue; } doneSectors = 0; while (doneSectors < inputFormat.Info.Sectors) { byte[] sector; uint sectorsToDo; if (inputFormat.Info.Sectors - doneSectors >= (ulong)options.Count) { sectorsToDo = (uint)options.Count; } else { sectorsToDo = (uint)(inputFormat.Info.Sectors - doneSectors); } DicConsole.Write("\rConverting tag {2} for sectors {0} to {1} ({2:P2} done)", doneSectors, doneSectors + sectorsToDo, doneSectors / (double)inputFormat.Info.Sectors, tag); bool result; if (sectorsToDo == 1) { sector = inputFormat.ReadSectorTag(doneSectors, tag); result = outputFormat.WriteSectorTag(sector, doneSectors, tag); } else { sector = inputFormat.ReadSectorsTag(doneSectors, sectorsToDo, tag); result = outputFormat.WriteSectorsTag(sector, doneSectors, sectorsToDo, tag); } if (!result) { if (options.Force) { DicConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors); } else { DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors); return; } } doneSectors += sectorsToDo; } DicConsole.Write("\rConverting tag {2} for sectors {0} to {1} ({2:P2} done)", inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, tag); DicConsole.WriteLine(); } } else { foreach (Track track in tracks) { doneSectors = 0; ulong trackSectors = track.TrackEndSector - track.TrackStartSector + 1; while (doneSectors < trackSectors) { byte[] sector; uint sectorsToDo; if (trackSectors - doneSectors >= (ulong)options.Count) { sectorsToDo = (uint)options.Count; } else { sectorsToDo = (uint)(trackSectors - doneSectors); } DicConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)", doneSectors + track.TrackStartSector, doneSectors + sectorsToDo + track.TrackStartSector, (doneSectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors, track.TrackSequence); bool result; if (useLong) { if (sectorsToDo == 1) { sector = inputFormat.ReadSectorLong(doneSectors + track.TrackStartSector); result = outputFormat.WriteSectorLong(sector, doneSectors + track.TrackStartSector); } else { sector = inputFormat.ReadSectorsLong(doneSectors + track.TrackStartSector, sectorsToDo); result = outputFormat.WriteSectorsLong(sector, doneSectors + track.TrackStartSector, sectorsToDo); } } else { if (sectorsToDo == 1) { sector = inputFormat.ReadSector(doneSectors + track.TrackStartSector); result = outputFormat.WriteSector(sector, doneSectors + track.TrackStartSector); } else { sector = inputFormat.ReadSectors(doneSectors + track.TrackStartSector, sectorsToDo); result = outputFormat.WriteSectors(sector, doneSectors + track.TrackStartSector, sectorsToDo); } } if (!result) { if (options.Force) { DicConsole.ErrorWriteLine("Error {0} writing sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors); } else { DicConsole.ErrorWriteLine("Error {0} writing sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors); return; } } doneSectors += sectorsToDo; } } DicConsole.Write("\rConverting sectors {0} to {1} in track {3} ({2:P2} done)", inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, tracks.Count); DicConsole.WriteLine(); foreach (SectorTagType tag in inputFormat.Info.ReadableSectorTags.OrderBy(t => t)) { if (!useLong) { break; } switch (tag) { case SectorTagType.AppleSectorTag: case SectorTagType.CdSectorSync: case SectorTagType.CdSectorHeader: case SectorTagType.CdSectorSubHeader: case SectorTagType.CdSectorEdc: case SectorTagType.CdSectorEccP: case SectorTagType.CdSectorEccQ: case SectorTagType.CdSectorEcc: // This tags are inline in long sector continue; } if (options.Force && !outputFormat.SupportedSectorTags.Contains(tag)) { continue; } foreach (Track track in tracks) { doneSectors = 0; ulong trackSectors = track.TrackEndSector - track.TrackStartSector + 1; byte[] sector; bool result; switch (tag) { case SectorTagType.CdTrackFlags: case SectorTagType.CdTrackIsrc: DicConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag, track.TrackSequence, track.TrackSequence / (double)tracks.Count); sector = inputFormat.ReadSectorTag(track.TrackStartSector, tag); result = outputFormat.WriteSectorTag(sector, track.TrackStartSector, tag); if (!result) { if (options.Force) { DicConsole.ErrorWriteLine("Error {0} writing tag, continuing...", outputFormat.ErrorMessage); } else { DicConsole.ErrorWriteLine("Error {0} writing tag, not continuing...", outputFormat.ErrorMessage); return; } } continue; } while (doneSectors < trackSectors) { uint sectorsToDo; if (trackSectors - doneSectors >= (ulong)options.Count) { sectorsToDo = (uint)options.Count; } else { sectorsToDo = (uint)(trackSectors - doneSectors); } DicConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)", doneSectors + track.TrackStartSector, doneSectors + sectorsToDo + track.TrackStartSector, (doneSectors + track.TrackStartSector) / (double)inputFormat.Info.Sectors, track.TrackSequence, tag); if (sectorsToDo == 1) { sector = inputFormat.ReadSectorTag(doneSectors + track.TrackStartSector, tag); result = outputFormat.WriteSectorTag(sector, doneSectors + track.TrackStartSector, tag); } else { sector = inputFormat.ReadSectorsTag(doneSectors + track.TrackStartSector, sectorsToDo, tag); result = outputFormat.WriteSectorsTag(sector, doneSectors + track.TrackStartSector, sectorsToDo, tag); } if (!result) { if (options.Force) { DicConsole.ErrorWriteLine("Error {0} writing tag for sector {1}, continuing...", outputFormat.ErrorMessage, doneSectors); } else { DicConsole.ErrorWriteLine("Error {0} writing tag for sector {1}, not continuing...", outputFormat.ErrorMessage, doneSectors); return; } } doneSectors += sectorsToDo; } } switch (tag) { case SectorTagType.CdTrackFlags: case SectorTagType.CdTrackIsrc: DicConsole.Write("\rConverting tag {0} in track {1} ({2:P2} done).", tag, tracks.Count, 1.0); break; default: DicConsole.Write("\rConverting tag {4} for sectors {0} to {1} in track {3} ({2:P2} done)", inputFormat.Info.Sectors, inputFormat.Info.Sectors, 1.0, tracks.Count, tag); break; } DicConsole.WriteLine(); } } bool ret = false; if (resume != null || dumpHardware != null) { if (resume != null) { ret = outputFormat.SetDumpHardware(resume.Tries); } else if (dumpHardware != null) { ret = outputFormat.SetDumpHardware(dumpHardware); } if (ret) { DicConsole.WriteLine("Written dump hardware list to output image."); } } ret = false; if (sidecar != null || cicmMetadata != null) { if (sidecar != null) { ret = outputFormat.SetCicmMetadata(sidecar); } else if (cicmMetadata != null) { ret = outputFormat.SetCicmMetadata(cicmMetadata); } if (ret) { DicConsole.WriteLine("Written CICM XML metadata to output image."); } } DicConsole.WriteLine("Closing output image."); if (!outputFormat.Close()) { DicConsole.ErrorWriteLine("Error {0} closing output image... Contents are not correct.", outputFormat.ErrorMessage); } DicConsole.WriteLine(); DicConsole.WriteLine("Conversion done."); Core.Statistics.AddCommand("convert-image"); }
internal static void DoDecode(DecodeOptions options) { DicConsole.DebugWriteLine("Decode command", "--debug={0}", options.Debug); DicConsole.DebugWriteLine("Decode command", "--verbose={0}", options.Verbose); DicConsole.DebugWriteLine("Decode command", "--input={0}", options.InputFile); DicConsole.DebugWriteLine("Decode command", "--start={0}", options.StartSector); DicConsole.DebugWriteLine("Decode command", "--length={0}", options.Length); DicConsole.DebugWriteLine("Decode command", "--disk-tags={0}", options.DiskTags); DicConsole.DebugWriteLine("Decode command", "--sector-tags={0}", options.SectorTags); FiltersList filtersList = new FiltersList(); IFilter inputFilter = filtersList.GetFilter(options.InputFile); if (inputFilter == null) { DicConsole.ErrorWriteLine("Cannot open specified file."); return; } IMediaImage inputFormat = ImageFormat.Detect(inputFilter); if (inputFormat == null) { DicConsole.ErrorWriteLine("Unable to recognize image format, not decoding"); return; } inputFormat.Open(inputFilter); Core.Statistics.AddMediaFormat(inputFormat.Format); Core.Statistics.AddMedia(inputFormat.Info.MediaType, false); Core.Statistics.AddFilter(inputFilter.Name); if (options.DiskTags) { if (inputFormat.Info.ReadableMediaTags.Count == 0) { DicConsole.WriteLine("There are no disk tags in chosen disc image."); } else { foreach (MediaTagType tag in inputFormat.Info.ReadableMediaTags) { switch (tag) { case MediaTagType.SCSI_INQUIRY: { byte[] inquiry = inputFormat.ReadDiskTag(MediaTagType.SCSI_INQUIRY); if (inquiry == null) { DicConsole.WriteLine("Error reading SCSI INQUIRY response from disc image"); } else { DicConsole.WriteLine("SCSI INQUIRY command response:"); DicConsole .WriteLine("================================================================================"); DicConsole.WriteLine(Inquiry.Prettify(inquiry)); DicConsole .WriteLine("================================================================================"); } break; } case MediaTagType.ATA_IDENTIFY: { byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATA_IDENTIFY); if (identify == null) { DicConsole.WriteLine("Error reading ATA IDENTIFY DEVICE response from disc image"); } else { DicConsole.WriteLine("ATA IDENTIFY DEVICE command response:"); DicConsole .WriteLine("================================================================================"); DicConsole.WriteLine(Identify.Prettify(identify)); DicConsole .WriteLine("================================================================================"); } break; } case MediaTagType.ATAPI_IDENTIFY: { byte[] identify = inputFormat.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY); if (identify == null) { DicConsole .WriteLine("Error reading ATA IDENTIFY PACKET DEVICE response from disc image"); } else { DicConsole.WriteLine("ATA IDENTIFY PACKET DEVICE command response:"); DicConsole .WriteLine("================================================================================"); DicConsole.WriteLine(Identify.Prettify(identify)); DicConsole .WriteLine("================================================================================"); } break; } case MediaTagType.CD_ATIP: { byte[] atip = inputFormat.ReadDiskTag(MediaTagType.CD_ATIP); if (atip == null) { DicConsole.WriteLine("Error reading CD ATIP from disc image"); } else { DicConsole.WriteLine("CD ATIP:"); DicConsole .WriteLine("================================================================================"); DicConsole.WriteLine(ATIP.Prettify(atip)); DicConsole .WriteLine("================================================================================"); } break; } case MediaTagType.CD_FullTOC: { byte[] fulltoc = inputFormat.ReadDiskTag(MediaTagType.CD_FullTOC); if (fulltoc == null) { DicConsole.WriteLine("Error reading CD full TOC from disc image"); } else { DicConsole.WriteLine("CD full TOC:"); DicConsole .WriteLine("================================================================================"); DicConsole.WriteLine(FullTOC.Prettify(fulltoc)); DicConsole .WriteLine("================================================================================"); } break; } case MediaTagType.CD_PMA: { byte[] pma = inputFormat.ReadDiskTag(MediaTagType.CD_PMA); if (pma == null) { DicConsole.WriteLine("Error reading CD PMA from disc image"); } else { DicConsole.WriteLine("CD PMA:"); DicConsole .WriteLine("================================================================================"); DicConsole.WriteLine(PMA.Prettify(pma)); DicConsole .WriteLine("================================================================================"); } break; } case MediaTagType.CD_SessionInfo: { byte[] sessioninfo = inputFormat.ReadDiskTag(MediaTagType.CD_SessionInfo); if (sessioninfo == null) { DicConsole.WriteLine("Error reading CD session information from disc image"); } else { DicConsole.WriteLine("CD session information:"); DicConsole .WriteLine("================================================================================"); DicConsole.WriteLine(Session.Prettify(sessioninfo)); DicConsole .WriteLine("================================================================================"); } break; } case MediaTagType.CD_TEXT: { byte[] cdtext = inputFormat.ReadDiskTag(MediaTagType.CD_TEXT); if (cdtext == null) { DicConsole.WriteLine("Error reading CD-TEXT from disc image"); } else { DicConsole.WriteLine("CD-TEXT:"); DicConsole .WriteLine("================================================================================"); DicConsole.WriteLine(CDTextOnLeadIn.Prettify(cdtext)); DicConsole .WriteLine("================================================================================"); } break; } case MediaTagType.CD_TOC: { byte[] toc = inputFormat.ReadDiskTag(MediaTagType.CD_TOC); if (toc == null) { DicConsole.WriteLine("Error reading CD TOC from disc image"); } else { DicConsole.WriteLine("CD TOC:"); DicConsole .WriteLine("================================================================================"); DicConsole.WriteLine(TOC.Prettify(toc)); DicConsole .WriteLine("================================================================================"); } break; } default: DicConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.", tag); break; } } } } if (options.SectorTags) { ulong length; if (options.Length.ToLowerInvariant() == "all") { length = inputFormat.Info.Sectors - 1; } else { if (!ulong.TryParse(options.Length, out length)) { DicConsole.WriteLine("Value \"{0}\" is not a valid number for length.", options.Length); DicConsole.WriteLine("Not decoding sectors tags"); return; } } if (inputFormat.Info.ReadableSectorTags.Count == 0) { DicConsole.WriteLine("There are no sector tags in chosen disc image."); } else { foreach (SectorTagType tag in inputFormat.Info.ReadableSectorTags) { switch (tag) { default: DicConsole.WriteLine("Decoder for disk tag type \"{0}\" not yet implemented, sorry.", tag); break; } } } // TODO: Not implemented } Core.Statistics.AddCommand("decode"); }