From d6b7d10b3faa972790b3b74e38d74dfaed5ac77c Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 18 Jul 2020 21:11:09 +0100 Subject: [PATCH] Undo commit 672ccb7e441c85f3e844d9a71586e07c076fd7de. --- Aaru/Commands/Media/Dump.cs | 421 ++++++++++++++++++++++-------------- 1 file changed, 256 insertions(+), 165 deletions(-) diff --git a/Aaru/Commands/Media/Dump.cs b/Aaru/Commands/Media/Dump.cs index 7d8a892f6..8f11b600f 100644 --- a/Aaru/Commands/Media/Dump.cs +++ b/Aaru/Commands/Media/Dump.cs @@ -37,10 +37,12 @@ using System.CommandLine.Invocation; using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Xml.Serialization; using Aaru.CommonTypes; using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; +using Aaru.CommonTypes.Interop; using Aaru.CommonTypes.Metadata; using Aaru.CommonTypes.Structs.Devices.SCSI; using Aaru.Console; @@ -173,7 +175,10 @@ namespace Aaru.Commands.Media AddArgument(new Argument { - Arity = ArgumentArity.ExactlyOne, Description = "Output image path", Name = "output-path" + Arity = ArgumentArity.ExactlyOne, + Description = + "Output image path. If filename starts with # and exists, it will be read as a list of output images, its extension will be used to detect the image output format, each media will be ejected and confirmation for the next one will be asked.", + Name = "output-path" }); Add(new Option(new[] @@ -351,103 +356,30 @@ namespace Aaru.Commands.Media break; } - if(devicePath.Length == 2 && - devicePath[1] == ':' && - devicePath[0] != '/' && - char.IsLetter(devicePath[0])) - devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':'; + string filename = Path.GetFileNameWithoutExtension(outputPath); - Devices.Device dev; + bool isResponse = filename.StartsWith("#", StringComparison.OrdinalIgnoreCase) && + File.Exists(Path.Combine(Path.GetDirectoryName(outputPath), + Path.GetFileNameWithoutExtension(outputPath))); - try - { - dev = new Devices.Device(devicePath); + TextReader resReader; - if(dev.IsRemote) - Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, - dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + if(isResponse) + resReader = new StreamReader(Path.Combine(Path.GetDirectoryName(outputPath), + Path.GetFileNameWithoutExtension(outputPath))); + else + resReader = new StringReader(Path.GetFileNameWithoutExtension(outputPath)); - if(dev.Error) - { - AaruConsole.ErrorWriteLine(Error.Print(dev.LastError)); - - return (int)ErrorNumber.CannotOpenDevice; - } - } - catch(DeviceException e) - { - AaruConsole.ErrorWriteLine(e.Message ?? Error.Print(e.LastError)); - - return (int)ErrorNumber.CannotOpenDevice; - } - - Statistics.AddDevice(dev); - - string outputPrefix = Path.Combine(Path.GetDirectoryName(outputPath), - Path.GetFileNameWithoutExtension(outputPath)); - - Resume resumeClass = null; - var xs = new XmlSerializer(typeof(Resume)); - - if(File.Exists(outputPrefix + ".resume.xml") && resume) - try - { - var sr = new StreamReader(outputPrefix + ".resume.xml"); - resumeClass = (Resume)xs.Deserialize(sr); - sr.Close(); - } - catch - { - AaruConsole.ErrorWriteLine("Incorrect resume file, not continuing..."); - - return (int)ErrorNumber.InvalidResume; - } - - if(resumeClass != null && - resumeClass.NextBlock > resumeClass.LastBlock && - resumeClass.BadBlocks.Count == 0 && - !resumeClass.Tape && - (resumeClass.BadSubchannels is null || resumeClass.BadSubchannels.Count == 0)) - { - AaruConsole.WriteLine("Media already dumped correctly, not continuing..."); - - return (int)ErrorNumber.AlreadyDumped; - } - - CICMMetadataType sidecar = null; - var sidecarXs = new XmlSerializer(typeof(CICMMetadataType)); - - if(cicmXml != null) - if(File.Exists(cicmXml)) - { - try - { - var sr = new StreamReader(cicmXml); - sidecar = (CICMMetadataType)sidecarXs.Deserialize(sr); - sr.Close(); - } - catch - { - AaruConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing..."); - - return (int)ErrorNumber.InvalidSidecar; - } - } - else - { - AaruConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing..."); - - return (int)ErrorNumber.FileNotFound; - } + if(isResponse) + eject = true; PluginBase plugins = GetPluginBase.Instance; List candidates = new List(); + string extension = Path.GetExtension(outputPath); // Try extension if(string.IsNullOrEmpty(format)) - candidates.AddRange(plugins.WritableImages.Values.Where(t => - t.KnownExtensions. - Contains(Path.GetExtension(outputPath)))); + candidates.AddRange(plugins.WritableImages.Values.Where(t => t.KnownExtensions.Contains(extension))); // Try Id else if(Guid.TryParse(format, out Guid outId)) @@ -456,8 +388,8 @@ namespace Aaru.Commands.Media // Try name else candidates.AddRange(plugins.WritableImages.Values.Where(t => string.Equals(t.Name, format, - StringComparison. - InvariantCultureIgnoreCase))); + StringComparison. + InvariantCultureIgnoreCase))); if(candidates.Count == 0) { @@ -473,88 +405,247 @@ namespace Aaru.Commands.Media return (int)ErrorNumber.TooManyFormats; } - IWritableImage outputFormat = candidates[0]; - - var dumpLog = new DumpLog(outputPrefix + ".log", dev, @private); - - if(verbose) + while(true) { - dumpLog.WriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); - AaruConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); - } - else - { - dumpLog.WriteLine("Output image format: {0}.", outputFormat.Name); - AaruConsole.WriteLine("Output image format: {0}.", outputFormat.Name); - } + string responseLine = resReader.ReadLine(); - var errorLog = new ErrorLog(outputPrefix + ".error.log"); + if(responseLine is null) + break; - var dumper = new Dump(resume, dev, devicePath, outputFormat, retryPasses, force, false, persistent, - stopOnError, resumeClass, dumpLog, encodingClass, outputPrefix, outputPath, - parsedOptions, sidecar, skip, metadata, trim, firstPregap, fixOffset, debug, - wantedSubchannel, speed, @private, fixSubchannelPosition, retrySubchannel, - fixSubchannel, fixSubchannelCrc, skipCdireadyHole, errorLog, generateSubchannels); - - dumper.UpdateStatus += Progress.UpdateStatus; - dumper.ErrorMessage += Progress.ErrorMessage; - dumper.StoppingErrorMessage += Progress.ErrorMessage; - dumper.UpdateProgress += Progress.UpdateProgress; - dumper.PulseProgress += Progress.PulseProgress; - dumper.InitProgress += Progress.InitProgress; - dumper.EndProgress += Progress.EndProgress; - dumper.InitProgress2 += Progress.InitProgress2; - dumper.EndProgress2 += Progress.EndProgress2; - dumper.UpdateProgress2 += Progress.UpdateProgress2; - - System.Console.CancelKeyPress += (sender, e) => - { - e.Cancel = true; - dumper.Abort(); - }; - - dumper.Start(); - - if(eject && dev.IsRemovable) - { - switch(dev.Type) + if(responseLine.Any(c => c < 0x20)) { - case DeviceType.ATA: - dev.DoorUnlock(out _, dev.Timeout, out _); - dev.MediaEject(out _, dev.Timeout, out _); + AaruConsole.ErrorWriteLine("Invalid characters found in list of files, exiting..."); - break; - case DeviceType.ATAPI: - case DeviceType.SCSI: - switch(dev.ScsiType) - { - case PeripheralDeviceTypes.DirectAccess: - case PeripheralDeviceTypes.SimplifiedDevice: - case PeripheralDeviceTypes.SCSIZonedBlockDevice: - case PeripheralDeviceTypes.WriteOnceDevice: - case PeripheralDeviceTypes.OpticalDevice: - case PeripheralDeviceTypes.OCRWDevice: - dev.SpcAllowMediumRemoval(out _, dev.Timeout, out _); - dev.EjectTray(out _, dev.Timeout, out _); - - break; - case PeripheralDeviceTypes.MultiMediaDevice: - dev.AllowMediumRemoval(out _, dev.Timeout, out _); - dev.EjectTray(out _, dev.Timeout, out _); - - break; - case PeripheralDeviceTypes.SequentialAccess: - dev.SpcAllowMediumRemoval(out _, dev.Timeout, out _); - dev.LoadUnload(out _, true, false, false, false, false, dev.Timeout, out _); - - break; - } - - break; + return (int)ErrorNumber.InvalidArgument; } - } - dev.Close(); + if(isResponse) + { + AaruConsole.WriteLine("Please insert media with title {0} and press any key to continue...", + responseLine); + + System.Console.ReadKey(); + Thread.Sleep(1000); + } + + responseLine = responseLine.Replace('/', '/'); + + // Replace Windows forbidden filename characters with Japanese equivalents that are visually the same, but bigger. + if(DetectOS.IsWindows) + responseLine = responseLine.Replace('<', '\uFF1C').Replace('>', '\uFF1E').Replace(':', '\uFF1A'). + Replace('"', '\u2033').Replace('\\', '\').Replace('|', '|'). + Replace('?', '?').Replace('*', '*'); + + if(devicePath.Length == 2 && + devicePath[1] == ':' && + devicePath[0] != '/' && + char.IsLetter(devicePath[0])) + devicePath = "\\\\.\\" + char.ToUpper(devicePath[0]) + ':'; + + Devices.Device dev; + + try + { + dev = new Devices.Device(devicePath); + + if(dev.IsRemote) + Statistics.AddRemote(dev.RemoteApplication, dev.RemoteVersion, dev.RemoteOperatingSystem, + dev.RemoteOperatingSystemVersion, dev.RemoteArchitecture); + + if(dev.Error) + { + AaruConsole.ErrorWriteLine(Error.Print(dev.LastError)); + + if(isResponse) + continue; + + return (int)ErrorNumber.CannotOpenDevice; + } + } + catch(DeviceException e) + { + AaruConsole.ErrorWriteLine(e.Message ?? Error.Print(e.LastError)); + + if(isResponse) + continue; + + return (int)ErrorNumber.CannotOpenDevice; + } + + Statistics.AddDevice(dev); + + string outputPrefix = Path.Combine(Path.GetDirectoryName(outputPath), responseLine); + + Resume resumeClass = null; + var xs = new XmlSerializer(typeof(Resume)); + + if(File.Exists(outputPrefix + ".resume.xml") && resume) + try + { + var sr = new StreamReader(outputPrefix + ".resume.xml"); + resumeClass = (Resume)xs.Deserialize(sr); + sr.Close(); + } + catch + { + AaruConsole.ErrorWriteLine("Incorrect resume file, not continuing..."); + + if(isResponse) + continue; + + return (int)ErrorNumber.InvalidResume; + } + + if(resumeClass != null && + resumeClass.NextBlock > resumeClass.LastBlock && + resumeClass.BadBlocks.Count == 0 && + !resumeClass.Tape && + (resumeClass.BadSubchannels is null || resumeClass.BadSubchannels.Count == 0)) + { + AaruConsole.WriteLine("Media already dumped correctly, not continuing..."); + + if(isResponse) + continue; + + return (int)ErrorNumber.AlreadyDumped; + } + + CICMMetadataType sidecar = null; + var sidecarXs = new XmlSerializer(typeof(CICMMetadataType)); + + if(cicmXml != null) + if(File.Exists(cicmXml)) + { + try + { + var sr = new StreamReader(cicmXml); + sidecar = (CICMMetadataType)sidecarXs.Deserialize(sr); + sr.Close(); + } + catch + { + AaruConsole.ErrorWriteLine("Incorrect metadata sidecar file, not continuing..."); + + if(isResponse) + continue; + + return (int)ErrorNumber.InvalidSidecar; + } + } + else + { + AaruConsole.ErrorWriteLine("Could not find metadata sidecar, not continuing..."); + + if(isResponse) + continue; + + return (int)ErrorNumber.FileNotFound; + } + + plugins = GetPluginBase.Instance; + candidates = new List(); + + // 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))); + + IWritableImage outputFormat = candidates[0]; + + var dumpLog = new DumpLog(outputPrefix + ".log", dev, @private); + + if(verbose) + { + dumpLog.WriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); + AaruConsole.VerboseWriteLine("Output image format: {0} ({1}).", outputFormat.Name, outputFormat.Id); + } + else + { + dumpLog.WriteLine("Output image format: {0}.", outputFormat.Name); + AaruConsole.WriteLine("Output image format: {0}.", outputFormat.Name); + } + + var errorLog = new ErrorLog(outputPrefix + ".error.log"); + + var dumper = new Dump(resume, dev, devicePath, outputFormat, retryPasses, force, false, persistent, + stopOnError, resumeClass, dumpLog, encodingClass, outputPrefix, + outputPrefix + extension, parsedOptions, sidecar, skip, metadata, trim, + firstPregap, fixOffset, debug, wantedSubchannel, speed, @private, + fixSubchannelPosition, retrySubchannel, fixSubchannel, fixSubchannelCrc, + skipCdireadyHole, errorLog, generateSubchannels); + + dumper.UpdateStatus += Progress.UpdateStatus; + dumper.ErrorMessage += Progress.ErrorMessage; + dumper.StoppingErrorMessage += Progress.ErrorMessage; + dumper.UpdateProgress += Progress.UpdateProgress; + dumper.PulseProgress += Progress.PulseProgress; + dumper.InitProgress += Progress.InitProgress; + dumper.EndProgress += Progress.EndProgress; + dumper.InitProgress2 += Progress.InitProgress2; + dumper.EndProgress2 += Progress.EndProgress2; + dumper.UpdateProgress2 += Progress.UpdateProgress2; + + System.Console.CancelKeyPress += (sender, e) => + { + e.Cancel = true; + dumper.Abort(); + }; + + dumper.Start(); + + if(eject && dev.IsRemovable) + { + switch(dev.Type) + { + case DeviceType.ATA: + dev.DoorUnlock(out _, dev.Timeout, out _); + dev.MediaEject(out _, dev.Timeout, out _); + + break; + case DeviceType.ATAPI: + case DeviceType.SCSI: + switch(dev.ScsiType) + { + case PeripheralDeviceTypes.DirectAccess: + case PeripheralDeviceTypes.SimplifiedDevice: + case PeripheralDeviceTypes.SCSIZonedBlockDevice: + case PeripheralDeviceTypes.WriteOnceDevice: + case PeripheralDeviceTypes.OpticalDevice: + case PeripheralDeviceTypes.OCRWDevice: + dev.SpcAllowMediumRemoval(out _, dev.Timeout, out _); + dev.EjectTray(out _, dev.Timeout, out _); + + break; + case PeripheralDeviceTypes.MultiMediaDevice: + dev.AllowMediumRemoval(out _, dev.Timeout, out _); + dev.EjectTray(out _, dev.Timeout, out _); + + break; + case PeripheralDeviceTypes.SequentialAccess: + dev.SpcAllowMediumRemoval(out _, dev.Timeout, out _); + dev.LoadUnload(out _, true, false, false, false, false, dev.Timeout, out _); + + break; + } + + break; + } + } + + dev.Close(); + } return (int)ErrorNumber.NoError; }