public bool Open(IFilter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); if ((stream.Length - Marshal.SizeOf <Footer>()) % 512 != 0) { return(false); } byte[] buffer = new byte[Marshal.SizeOf <Footer>()]; stream.Seek(-buffer.Length, SeekOrigin.End); stream.Read(buffer, 0, buffer.Length); _footer = Marshal.ByteArrayToStructureLittleEndian <Footer>(buffer); string sig = StringHandlers.CToString(_footer.signature); var regexSignature = new Regex(REGEX_DRI); Match matchSignature = regexSignature.Match(sig); if (!matchSignature.Success) { return(false); } if (_footer.bpb.sptrack * _footer.bpb.cylinders * _footer.bpb.heads != _footer.bpb.sectors) { return(false); } if ((_footer.bpb.sectors * _footer.bpb.bps) + Marshal.SizeOf <Footer>() != stream.Length) { return(false); } _imageInfo.Cylinders = _footer.bpb.cylinders; _imageInfo.Heads = _footer.bpb.heads; _imageInfo.SectorsPerTrack = _footer.bpb.sptrack; _imageInfo.Sectors = _footer.bpb.sectors; _imageInfo.SectorSize = _footer.bpb.bps; _imageInfo.ApplicationVersion = matchSignature.Groups["version"].Value; _driImageFilter = imageFilter; _imageInfo.ImageSize = (ulong)(stream.Length - Marshal.SizeOf <Footer>()); _imageInfo.CreationTime = imageFilter.GetCreationTime(); _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime(); AaruConsole.DebugWriteLine("DRI DiskCopy plugin", "Image application = {0} version {1}", _imageInfo.Application, _imageInfo.ApplicationVersion); // Correct some incorrect data in images of NEC 2HD disks if (_imageInfo.Cylinders == 77 && _imageInfo.Heads == 2 && _imageInfo.SectorsPerTrack == 16 && _imageInfo.SectorSize == 512 && (_footer.bpb._driveCode == DriveCode.md2hd || _footer.bpb._driveCode == DriveCode.mf2hd)) { _imageInfo.SectorsPerTrack = 8; _imageInfo.SectorSize = 1024; } _imageInfo.MediaType = Geometry.GetMediaType(((ushort)_imageInfo.Cylinders, (byte)_imageInfo.Heads, (ushort)_imageInfo.SectorsPerTrack, _imageInfo.SectorSize, MediaEncoding.MFM, false)); switch (_imageInfo.MediaType) { case MediaType.NEC_525_HD when _footer.bpb._driveCode == DriveCode.mf2hd || _footer.bpb._driveCode == DriveCode.mf2ed: _imageInfo.MediaType = MediaType.NEC_35_HD_8; break; case MediaType.DOS_525_HD when _footer.bpb._driveCode == DriveCode.mf2hd || _footer.bpb._driveCode == DriveCode.mf2ed: _imageInfo.MediaType = MediaType.NEC_35_HD_15; break; case MediaType.RX50 when _footer.bpb._driveCode == DriveCode.md2dd || _footer.bpb._driveCode == DriveCode.md2hd: _imageInfo.MediaType = MediaType.ATARI_35_SS_DD; break; } _imageInfo.XmlMediaType = XmlMediaType.BlockMedia; AaruConsole.VerboseWriteLine("Digital Research DiskCopy image contains a disk of type {0}", _imageInfo.MediaType); return(true); }
static void Read(string devPath, Device dev, bool multiple) { uint address = 0; uint blockSize = 512; ushort count = 1; bool byteAddr = false; string strDev; int item; parameters: while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Parameters for READ_{0}_BLOCK command:", multiple ? "MULTIPLE" : "SINGLE"); AaruConsole.WriteLine("Read from {1}: {0}", address, byteAddr ? "byte" : "block"); AaruConsole.WriteLine("Expected block size: {0} bytes", blockSize); if (multiple) { AaruConsole.WriteLine("Will read {0} blocks", count); } AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Change parameters."); AaruConsole.WriteLine("2.- Send command with these parameters."); AaruConsole.WriteLine("0.- Return to MultiMediaCard commands menu."); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to MultiMediaCard commands menu..."); return; case 1: AaruConsole.Write("Use byte addressing?: "); strDev = System.Console.ReadLine(); if (!bool.TryParse(strDev, out byteAddr)) { AaruConsole.WriteLine("Not a boolean. Press any key to continue..."); byteAddr = false; System.Console.ReadKey(); continue; } AaruConsole.Write("Read from {0}?: ", byteAddr ? "byte" : "block"); strDev = System.Console.ReadLine(); if (!uint.TryParse(strDev, out address)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); address = 0; System.Console.ReadKey(); continue; } if (multiple) { AaruConsole.Write("How many blocks to read?"); strDev = System.Console.ReadLine(); if (!ushort.TryParse(strDev, out count)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); count = 1; System.Console.ReadKey(); continue; } } AaruConsole.Write("How many bytes to expect in a block?"); strDev = System.Console.ReadLine(); if (!uint.TryParse(strDev, out blockSize)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); blockSize = 512; System.Console.ReadKey(); } break; case 2: goto start; } } start: System.Console.Clear(); bool sense = dev.Read(out byte[] buffer, out uint[] response, address, blockSize, multiple ? count : (ushort)1, byteAddr, dev.Timeout, out double duration); menu: AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Sending READ_{0}_BLOCK to the device:", multiple ? "MULTIPLE" : "SINGLE"); AaruConsole.WriteLine("Command took {0} ms.", duration); AaruConsole.WriteLine("Sense is {0}.", sense); AaruConsole.WriteLine("Buffer is {0} bytes.", buffer?.Length.ToString() ?? "null"); AaruConsole.WriteLine("Buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(buffer)); AaruConsole.WriteLine("Response has {0} elements.", response?.Length.ToString() ?? "null"); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Print buffer."); AaruConsole.WriteLine("2.- Print response buffer."); AaruConsole.WriteLine("3.- Send command again."); AaruConsole.WriteLine("4.- Change parameters."); AaruConsole.WriteLine("0.- Return to MultiMediaCard commands menu."); AaruConsole.Write("Choose: "); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to MultiMediaCard commands menu..."); return; case 1: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("READ_{0}_BLOCK buffer:", multiple ? "MULTIPLE" : "SINGLE"); if (buffer != null) { PrintHex.PrintHexArray(buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 2: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("READ_{0}_BLOCK response:", multiple ? "MULTIPLE" : "SINGLE"); if (response != null) { foreach (uint res in response) { AaruConsole.Write("0x{0:x8} ", res); } AaruConsole.WriteLine(); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 3: goto start; case 4: goto parameters; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
static void SendExtendedCsd(string devPath, Device dev) { start: System.Console.Clear(); bool sense = dev.ReadExtendedCsd(out byte[] buffer, out uint[] response, dev.Timeout, out double duration); menu: AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Sending SEND_EXT_CSD to the device:"); AaruConsole.WriteLine("Command took {0} ms.", duration); AaruConsole.WriteLine("Sense is {0}.", sense); AaruConsole.WriteLine("Buffer is {0} bytes.", buffer?.Length.ToString() ?? "null"); AaruConsole.WriteLine("Buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(buffer)); AaruConsole.WriteLine("Response has {0} elements.", response?.Length.ToString() ?? "null"); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Print buffer."); AaruConsole.WriteLine("2.- Decode buffer."); AaruConsole.WriteLine("3.- Print response buffer."); AaruConsole.WriteLine("4.- Send command again."); AaruConsole.WriteLine("0.- Return to MultiMediaCard commands menu."); AaruConsole.Write("Choose: "); string strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out int item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to MultiMediaCard commands menu..."); return; case 1: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("SEND_EXT_CSD buffer:"); if (buffer != null) { PrintHex.PrintHexArray(buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 2: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("SEND_EXT_CSD decoded buffer:"); if (buffer != null) { AaruConsole.WriteLine("{0}", Decoders.MMC.Decoders.PrettifyExtendedCSD(buffer)); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 3: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("SEND_EXT_CSD response:"); if (response != null) { foreach (uint res in response) { AaruConsole.Write("0x{0:x8} ", res); } AaruConsole.WriteLine(); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 4: goto start; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
static void ReadSectors(string devPath, Device dev, bool retries) { ushort cylinder = 0; byte head = 0; byte sector = 1; byte count = 1; string strDev; int item; parameters: while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Parameters for READ SECTORS {0}command:", retries ? "WITH RETRIES " : ""); AaruConsole.WriteLine("Cylinder: {0}", cylinder); AaruConsole.WriteLine("Head: {0}", head); AaruConsole.WriteLine("Sector: {0}", sector); AaruConsole.WriteLine("Count: {0}", count); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Change parameters."); AaruConsole.WriteLine("2.- Send command with these parameters."); AaruConsole.WriteLine("0.- Return to CHS ATA commands menu."); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to CHS ATA commands menu..."); return; case 1: AaruConsole.Write("What cylinder?: "); strDev = System.Console.ReadLine(); if (!ushort.TryParse(strDev, out cylinder)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); cylinder = 0; System.Console.ReadKey(); continue; } AaruConsole.Write("What head?: "); strDev = System.Console.ReadLine(); if (!byte.TryParse(strDev, out head)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); head = 0; System.Console.ReadKey(); continue; } if (head > 15) { AaruConsole.WriteLine("Head cannot be bigger than 15. Setting it to 15..."); head = 15; } AaruConsole.Write("What sector?: "); strDev = System.Console.ReadLine(); if (!byte.TryParse(strDev, out sector)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); sector = 0; System.Console.ReadKey(); continue; } AaruConsole.Write("How many sectors?: "); strDev = System.Console.ReadLine(); if (!byte.TryParse(strDev, out count)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); count = 0; System.Console.ReadKey(); } break; case 2: goto start; } } start: System.Console.Clear(); bool sense = dev.Read(out byte[] buffer, out AtaErrorRegistersChs errorRegisters, retries, cylinder, head, sector, count, dev.Timeout, out double duration); menu: AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Sending READ SECTORS {0}to the device:", retries ? "WITH RETRIES " : ""); AaruConsole.WriteLine("Command took {0} ms.", duration); AaruConsole.WriteLine("Sense is {0}.", sense); AaruConsole.WriteLine("Buffer is {0} bytes.", buffer?.Length.ToString() ?? "null"); AaruConsole.WriteLine("Buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(buffer)); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Print buffer."); AaruConsole.WriteLine("2.- Decode error registers."); AaruConsole.WriteLine("3.- Send command again."); AaruConsole.WriteLine("4.- Change parameters."); AaruConsole.WriteLine("0.- Return to CHS ATA commands menu."); AaruConsole.Write("Choose: "); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to CHS ATA commands menu..."); return; case 1: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("READ SECTORS {0}response:", retries ? "WITH RETRIES " : ""); if (buffer != null) { PrintHex.PrintHexArray(buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 2: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("READ SECTORS {0}status registers:", retries ? "WITH RETRIES " : ""); AaruConsole.Write("{0}", MainClass.DecodeAtaRegisters(errorRegisters)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 3: goto start; case 4: goto parameters; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
bool ScsiFindReadCommand() { if (Blocks == 0) { GetDeviceBlocks(); } if (Blocks == 0) { return(true); } byte[] senseBuf; int tries = 0; uint lba = 0; bool mediumScan = false; if (_dev.ScsiType == PeripheralDeviceTypes.OpticalDevice) { mediumScan = !_dev.MediumScan(out _, true, false, false, false, false, lba, 1, (uint)Blocks, out uint foundLba, out _, _timeout, out _); if (mediumScan) { lba = foundLba; } } var rnd = new Random(); while (tries < 10) { _read6 = !_dev.Read6(out _, out senseBuf, lba, LogicalBlockSize, _timeout, out _); _read10 = !_dev.Read10(out _, out senseBuf, 0, false, false, false, false, lba, LogicalBlockSize, 0, 1, _timeout, out _); _read12 = !_dev.Read12(out _, out senseBuf, 0, false, false, false, false, lba, LogicalBlockSize, 0, 1, false, _timeout, out _); _read16 = !_dev.Read16(out _, out senseBuf, 0, false, false, false, lba, LogicalBlockSize, 0, 1, false, _timeout, out _); if (_read6 || _read10 || _read12 || _read16) { break; } lba = (uint)rnd.Next(1, (int)Blocks); if (mediumScan) { mediumScan = !_dev.MediumScan(out _, true, false, false, false, false, lba, 1, (uint)Blocks, out uint foundLba, out _, _timeout, out _); if (mediumScan) { lba = foundLba; } } tries++; } if (!_read6 && !_read10 && !_read12 && !_read16) { // Magneto-opticals may have empty LBA 0 but we know they work with READ(12) if (_dev.ScsiType == PeripheralDeviceTypes.OpticalDevice) { ErrorMessage = "Cannot read medium, aborting scan..."; return(true); } _read12 = true; } if (_read6 && !_read10 && !_read12 && !_read16 && Blocks > 0x001FFFFF + 1) { ErrorMessage = $"Device only supports SCSI READ (6) but has more than {0x001FFFFF + 1} blocks ({Blocks} blocks total)"; return(true); } if (Blocks > 0x001FFFFF + 1) { _read6 = false; } if (_read10) { _read12 = false; } if (!_read16 && Blocks > 0xFFFFFFFF + (long)1) { ErrorMessage = $"Device only supports SCSI READ (10) but has more than {0xFFFFFFFF + (long)1} blocks ({Blocks} blocks total)"; return(true); } if (Blocks > 0xFFFFFFFF + (long)1) { _read10 = false; _read12 = false; } _seek6 = !_dev.Seek6(out senseBuf, lba, _timeout, out _); _seek10 = !_dev.Seek10(out senseBuf, lba, _timeout, out _); if (CanReadRaw) { bool testSense; CanReadRaw = false; if (_dev.ScsiType != PeripheralDeviceTypes.MultiMediaDevice) { /*testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 0xFFFF, timeout, out duration); * if (testSense && !dev.Error) * { * decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); * if (decSense.HasValue) * { * if (decSense.Value.SenseKey == Aaru.Decoders.SCSI.SenseKeys.IllegalRequest && * decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) * { * readRaw = true; * if (decSense.Value.InformationValid && decSense.Value.ILI) * { * longBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); * readLong16 = !dev.ReadLong16(out readBuffer, out senseBuf, false, 0, longBlockSize, timeout, out duration); * } * } * } * }*/ testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, 0xFFFF, _timeout, out _); FixedSense?decSense; if (testSense && !_dev.Error) { decSense = Sense.DecodeFixed(senseBuf); if (decSense?.SenseKey == SenseKeys.IllegalRequest && decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) { CanReadRaw = true; if (decSense.Value.InformationValid && decSense.Value.ILI) { LongBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); _readLong10 = !_dev.ReadLong10(out _, out senseBuf, false, false, 0, (ushort)LongBlockSize, _timeout, out _); } } } if (CanReadRaw && LongBlockSize == LogicalBlockSize) { switch (LogicalBlockSize) { case 512: { foreach (ushort testSize in new ushort[] { // Long sector sizes for floppies 514, // Long sector sizes for SuperDisk 536, 558, // Long sector sizes for 512-byte magneto-opticals 600, 610, 630 }) { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, testSize, _timeout, out _); if (!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = testSize; CanReadRaw = true; break; } testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, testSize, _timeout, out _); if (testSense || _dev.Error) { continue; } _readLong10 = true; LongBlockSize = testSize; CanReadRaw = true; break; } break; } case 1024: { foreach (ushort testSize in new ushort[] { // Long sector sizes for floppies 1026, // Long sector sizes for 1024-byte magneto-opticals 1200 }) { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, testSize, _timeout, out _); if (!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = testSize; CanReadRaw = true; break; } testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, testSize, _timeout, out _); if (testSense || _dev.Error) { continue; } _readLong10 = true; LongBlockSize = testSize; CanReadRaw = true; break; } break; } case 2048: { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, 2380, _timeout, out _); if (!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = 2380; CanReadRaw = true; } else { testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, 2380, _timeout, out _); if (!testSense && !_dev.Error) { _readLong10 = true; LongBlockSize = 2380; CanReadRaw = true; } } break; } case 4096: { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, 4760, _timeout, out _); if (!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = 4760; CanReadRaw = true; } else { testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, 4760, _timeout, out _); if (!testSense && !_dev.Error) { _readLong10 = true; LongBlockSize = 4760; CanReadRaw = true; } } break; } case 8192: { testSense = _dev.ReadLong16(out _, out senseBuf, false, 0, 9424, _timeout, out _); if (!testSense && !_dev.Error) { _readLong16 = true; LongBlockSize = 9424; CanReadRaw = true; } else { testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, 9424, _timeout, out _); if (!testSense && !_dev.Error) { _readLong10 = true; LongBlockSize = 9424; CanReadRaw = true; } } break; } } } if (!CanReadRaw && _dev.Manufacturer == "SYQUEST") { testSense = _dev.SyQuestReadLong10(out _, out senseBuf, 0, 0xFFFF, _timeout, out _); if (testSense) { decSense = Sense.DecodeFixed(senseBuf); if (decSense.HasValue) { if (decSense.Value.SenseKey == SenseKeys.IllegalRequest && decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) { CanReadRaw = true; if (decSense.Value.InformationValid && decSense.Value.ILI) { LongBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); _syqReadLong10 = !_dev.SyQuestReadLong10(out _, out senseBuf, 0, LongBlockSize, _timeout, out _); } } else { testSense = _dev.SyQuestReadLong6(out _, out senseBuf, 0, 0xFFFF, _timeout, out _); if (testSense) { decSense = Sense.DecodeFixed(senseBuf); if (decSense?.SenseKey == SenseKeys.IllegalRequest && decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) { CanReadRaw = true; if (decSense.Value.InformationValid && decSense.Value.ILI) { LongBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); _syqReadLong6 = !_dev.SyQuestReadLong6(out _, out senseBuf, 0, LongBlockSize, _timeout, out _); } } } } } } if (!CanReadRaw && LogicalBlockSize == 256) { testSense = _dev.SyQuestReadLong6(out _, out senseBuf, 0, 262, _timeout, out _); if (!testSense && !_dev.Error) { _syqReadLong6 = true; LongBlockSize = 262; CanReadRaw = true; } } } } else { switch (_dev.Manufacturer) { case "HL-DT-ST": _hldtstReadRaw = !_dev.HlDtStReadRawDvd(out _, out senseBuf, 0, 1, _timeout, out _); break; case "PLEXTOR": _plextorReadRaw = !_dev.PlextorReadRawDvd(out _, out senseBuf, 0, 1, _timeout, out _); break; } if (_hldtstReadRaw || _plextorReadRaw) { CanReadRaw = true; LongBlockSize = 2064; } // READ LONG (10) for some DVD drives if (!CanReadRaw && _dev.Manufacturer == "MATSHITA") { testSense = _dev.ReadLong10(out _, out senseBuf, false, false, 0, 37856, _timeout, out _); if (!testSense && !_dev.Error) { _readLongDvd = true; LongBlockSize = 37856; CanReadRaw = true; } } } } if (CanReadRaw) { if (_readLong16) { AaruConsole.WriteLine("Using SCSI READ LONG (16) command."); } else if (_readLong10 || _readLongDvd) { AaruConsole.WriteLine("Using SCSI READ LONG (10) command."); } else if (_syqReadLong10) { AaruConsole.WriteLine("Using SyQuest READ LONG (10) command."); } else if (_syqReadLong6) { AaruConsole.WriteLine("Using SyQuest READ LONG (6) command."); } else if (_hldtstReadRaw) { AaruConsole.WriteLine("Using HL-DT-ST raw DVD reading."); } else if (_plextorReadRaw) { AaruConsole.WriteLine("Using Plextor raw DVD reading."); } } else if (_read6) { AaruConsole.WriteLine("Using SCSI READ (6) command."); } else if (_read10) { AaruConsole.WriteLine("Using SCSI READ (10) command."); } else if (_read12) { AaruConsole.WriteLine("Using SCSI READ (12) command."); } else if (_read16) { AaruConsole.WriteLine("Using SCSI READ (16) command."); } return(false); }
public bool Open(IFilter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); stream.Seek(0, SeekOrigin.Begin); byte[] hdr = new byte[133]; stream.Read(hdr, 0, 133); _header = Marshal.ByteArrayToStructureLittleEndian <Header>(hdr); AaruConsole.DebugWriteLine("CopyQM plugin", "header.magic = 0x{0:X4}", _header.magic); AaruConsole.DebugWriteLine("CopyQM plugin", "header.mark = 0x{0:X2}", _header.mark); AaruConsole.DebugWriteLine("CopyQM plugin", "header.sectorSize = {0}", _header.sectorSize); AaruConsole.DebugWriteLine("CopyQM plugin", "header.sectorPerCluster = {0}", _header.sectorPerCluster); AaruConsole.DebugWriteLine("CopyQM plugin", "header.reservedSectors = {0}", _header.reservedSectors); AaruConsole.DebugWriteLine("CopyQM plugin", "header.fatCopy = {0}", _header.fatCopy); AaruConsole.DebugWriteLine("CopyQM plugin", "header.rootEntries = {0}", _header.rootEntries); AaruConsole.DebugWriteLine("CopyQM plugin", "header.sectors = {0}", _header.sectors); AaruConsole.DebugWriteLine("CopyQM plugin", "header.mediaType = 0x{0:X2}", _header.mediaType); AaruConsole.DebugWriteLine("CopyQM plugin", "header.sectorsPerFat = {0}", _header.sectorsPerFat); AaruConsole.DebugWriteLine("CopyQM plugin", "header.sectorsPerTrack = {0}", _header.sectorsPerTrack); AaruConsole.DebugWriteLine("CopyQM plugin", "header.heads = {0}", _header.heads); AaruConsole.DebugWriteLine("CopyQM plugin", "header.hidden = {0}", _header.hidden); AaruConsole.DebugWriteLine("CopyQM plugin", "header.sectorsBig = {0}", _header.sectorsBig); AaruConsole.DebugWriteLine("CopyQM plugin", "header.description = {0}", _header.description); AaruConsole.DebugWriteLine("CopyQM plugin", "header.blind = {0}", _header.blind); AaruConsole.DebugWriteLine("CopyQM plugin", "header.density = {0}", _header.density); AaruConsole.DebugWriteLine("CopyQM plugin", "header.imageCylinders = {0}", _header.imageCylinders); AaruConsole.DebugWriteLine("CopyQM plugin", "header.totalCylinders = {0}", _header.totalCylinders); AaruConsole.DebugWriteLine("CopyQM plugin", "header.crc = 0x{0:X8}", _header.crc); AaruConsole.DebugWriteLine("CopyQM plugin", "header.volumeLabel = {0}", _header.volumeLabel); AaruConsole.DebugWriteLine("CopyQM plugin", "header.time = 0x{0:X4}", _header.time); AaruConsole.DebugWriteLine("CopyQM plugin", "header.date = 0x{0:X4}", _header.date); AaruConsole.DebugWriteLine("CopyQM plugin", "header.commentLength = {0}", _header.commentLength); AaruConsole.DebugWriteLine("CopyQM plugin", "header.secbs = {0}", _header.secbs); AaruConsole.DebugWriteLine("CopyQM plugin", "header.unknown = 0x{0:X4}", _header.unknown); AaruConsole.DebugWriteLine("CopyQM plugin", "header.interleave = {0}", _header.interleave); AaruConsole.DebugWriteLine("CopyQM plugin", "header.skew = {0}", _header.skew); AaruConsole.DebugWriteLine("CopyQM plugin", "header.drive = {0}", _header.drive); byte[] cmt = new byte[_header.commentLength]; stream.Read(cmt, 0, _header.commentLength); _imageInfo.Comments = StringHandlers.CToString(cmt); _decodedImage = new MemoryStream(); _calculatedDataCrc = 0; while (stream.Position + 2 < stream.Length) { byte[] runLengthBytes = new byte[2]; if (stream.Read(runLengthBytes, 0, 2) != 2) { break; } short runLength = BitConverter.ToInt16(runLengthBytes, 0); if (runLength < 0) { byte repeatedByte = (byte)stream.ReadByte(); byte[] repeatedArray = new byte[runLength * -1]; ArrayHelpers.ArrayFill(repeatedArray, repeatedByte); for (int i = 0; i < runLength * -1; i++) { _decodedImage.WriteByte(repeatedByte); _calculatedDataCrc = _copyQmCrcTable[(repeatedByte ^ _calculatedDataCrc) & 0x3F] ^ (_calculatedDataCrc >> 8); } } else if (runLength > 0) { byte[] nonRepeated = new byte[runLength]; stream.Read(nonRepeated, 0, runLength); _decodedImage.Write(nonRepeated, 0, runLength); foreach (byte c in nonRepeated) { _calculatedDataCrc = _copyQmCrcTable[(c ^ _calculatedDataCrc) & 0x3F] ^ (_calculatedDataCrc >> 8); } } } // In case there is omitted data long sectors = _header.sectorsPerTrack * _header.heads * _header.totalCylinders; long fillingLen = (sectors * _header.sectorSize) - _decodedImage.Length; if (fillingLen > 0) { byte[] filling = new byte[fillingLen]; ArrayHelpers.ArrayFill(filling, (byte)0xF6); _decodedImage.Write(filling, 0, filling.Length); } int sum = 0; for (int i = 0; i < hdr.Length - 1; i++) { sum += hdr[i]; } _headerChecksumOk = ((-1 * sum) & 0xFF) == _header.headerChecksum; AaruConsole.DebugWriteLine("CopyQM plugin", "Calculated header checksum = 0x{0:X2}, {1}", (-1 * sum) & 0xFF, _headerChecksumOk); AaruConsole.DebugWriteLine("CopyQM plugin", "Calculated data CRC = 0x{0:X8}, {1}", _calculatedDataCrc, _calculatedDataCrc == _header.crc); _imageInfo.Application = "CopyQM"; _imageInfo.CreationTime = DateHandlers.DosToDateTime(_header.date, _header.time); _imageInfo.LastModificationTime = _imageInfo.CreationTime; _imageInfo.MediaTitle = _header.volumeLabel; _imageInfo.ImageSize = (ulong)(stream.Length - 133 - _header.commentLength); _imageInfo.Sectors = (ulong)sectors; _imageInfo.SectorSize = _header.sectorSize; _imageInfo.MediaType = Geometry.GetMediaType(((ushort)_header.totalCylinders, (byte)_header.heads, _header.sectorsPerTrack, (uint)_header.sectorSize, MediaEncoding.MFM, false)); switch (_imageInfo.MediaType) { case MediaType.NEC_525_HD when _header.drive == COPYQM_35_HD || _header.drive == COPYQM_35_ED: _imageInfo.MediaType = MediaType.NEC_35_HD_8; break; case MediaType.DOS_525_HD when _header.drive == COPYQM_35_HD || _header.drive == COPYQM_35_ED: _imageInfo.MediaType = MediaType.NEC_35_HD_15; break; case MediaType.RX50 when _header.drive == COPYQM_525_DD || _header.drive == COPYQM_525_HD: _imageInfo.MediaType = MediaType.ATARI_35_SS_DD; break; } _imageInfo.XmlMediaType = XmlMediaType.BlockMedia; _decodedDisk = _decodedImage.ToArray(); _decodedImage.Close(); AaruConsole.VerboseWriteLine("CopyQM image contains a disk of type {0}", _imageInfo.MediaType); if (!string.IsNullOrEmpty(_imageInfo.Comments)) { AaruConsole.VerboseWriteLine("CopyQM comments: {0}", _imageInfo.Comments); } _imageInfo.Heads = _header.heads; _imageInfo.Cylinders = _header.totalCylinders; _imageInfo.SectorsPerTrack = _header.sectorsPerTrack; return(true); }
static void Identify(string devPath, Device dev) { start: System.Console.Clear(); bool sense = dev.AtaIdentify(out byte[] buffer, out AtaErrorRegistersChs errorRegisters, out double duration); menu: AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Sending IDENTIFY DEVICE to the device:"); AaruConsole.WriteLine("Command took {0} ms.", duration); AaruConsole.WriteLine("Sense is {0}.", sense); AaruConsole.WriteLine("Buffer is {0} bytes.", buffer?.Length.ToString() ?? "null"); AaruConsole.WriteLine("Buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(buffer)); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Print buffer."); AaruConsole.WriteLine("2.- Decode buffer."); AaruConsole.WriteLine("3.- Decode error registers."); AaruConsole.WriteLine("4.- Send command again."); AaruConsole.WriteLine("0.- Return to CHS ATA commands menu."); AaruConsole.Write("Choose: "); string strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out int item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to CHS ATA commands menu..."); return; case 1: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("IDENTIFY DEVICE response:"); if (buffer != null) { PrintHex.PrintHexArray(buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 2: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("IDENTIFY DEVICE decoded response:"); if (buffer != null) { AaruConsole.WriteLine("{0}", Decoders.ATA.Identify.Prettify(buffer)); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 3: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("IDENTIFY DEVICE status registers:"); AaruConsole.Write("{0}", MainClass.DecodeAtaRegisters(errorRegisters)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 4: goto start; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
public void GetInformation(IMediaImage imagePlugin, Partition partition, out string information, Encoding encoding) { Encoding = encoding ?? Encoding.ASCII; information = ""; var isoMetadata = new StringBuilder(); byte[] vdMagic = new byte[5]; // Volume Descriptor magic "CD001" byte[] hsMagic = new byte[5]; // Volume Descriptor magic "CDROM" string bootSpec = ""; PrimaryVolumeDescriptor?pvd = null; PrimaryVolumeDescriptor?jolietvd = null; BootRecord?bvd = null; HighSierraPrimaryVolumeDescriptor?hsvd = null; FileStructureVolumeDescriptor? fsvd = null; ElToritoBootRecord?torito = null; // ISO9660 is designed for 2048 bytes/sector devices if (imagePlugin.Info.SectorSize < 2048) { return; } // ISO9660 Primary Volume Descriptor starts at sector 16, so that's minimal size. if (partition.End < 16) { return; } ulong counter = 0; byte[] vdSector = imagePlugin.ReadSector(16 + counter + partition.Start); int xaOff = vdSector.Length == 2336 ? 8 : 0; Array.Copy(vdSector, 0x009 + xaOff, hsMagic, 0, 5); bool highSierraInfo = Encoding.GetString(hsMagic) == HIGH_SIERRA_MAGIC; int hsOff = 0; if (highSierraInfo) { hsOff = 8; } bool cdiInfo = false; bool evd = false; bool vpd = false; while (true) { AaruConsole.DebugWriteLine("ISO9660 plugin", "Processing VD loop no. {0}", counter); // Seek to Volume Descriptor AaruConsole.DebugWriteLine("ISO9660 plugin", "Reading sector {0}", 16 + counter + partition.Start); byte[] vdSectorTmp = imagePlugin.ReadSector(16 + counter + partition.Start); vdSector = new byte[vdSectorTmp.Length - xaOff]; Array.Copy(vdSectorTmp, xaOff, vdSector, 0, vdSector.Length); byte vdType = vdSector[0 + hsOff]; // Volume Descriptor Type, should be 1 or 2. AaruConsole.DebugWriteLine("ISO9660 plugin", "VDType = {0}", vdType); if (vdType == 255) // Supposedly we are in the PVD. { if (counter == 0) { return; } break; } Array.Copy(vdSector, 0x001, vdMagic, 0, 5); Array.Copy(vdSector, 0x009, hsMagic, 0, 5); if (Encoding.GetString(vdMagic) != ISO_MAGIC && Encoding.GetString(hsMagic) != HIGH_SIERRA_MAGIC && Encoding.GetString(vdMagic) != CDI_MAGIC ) // Recognized, it is an ISO9660, now check for rest of data. { if (counter == 0) { return; } break; } cdiInfo |= Encoding.GetString(vdMagic) == CDI_MAGIC; switch (vdType) { case 0: { bvd = Marshal.ByteArrayToStructureLittleEndian <BootRecord>(vdSector, hsOff, 2048 - hsOff); bootSpec = "Unknown"; if (Encoding.GetString(bvd.Value.system_id).Substring(0, 23) == "EL TORITO SPECIFICATION") { bootSpec = "El Torito"; torito = Marshal.ByteArrayToStructureLittleEndian <ElToritoBootRecord>(vdSector, hsOff, 2048 - hsOff); } break; } case 1: { if (highSierraInfo) { hsvd = Marshal. ByteArrayToStructureLittleEndian <HighSierraPrimaryVolumeDescriptor>(vdSector); } else if (cdiInfo) { fsvd = Marshal.ByteArrayToStructureBigEndian <FileStructureVolumeDescriptor>(vdSector); } else { pvd = Marshal.ByteArrayToStructureLittleEndian <PrimaryVolumeDescriptor>(vdSector); } break; } case 2: { PrimaryVolumeDescriptor svd = Marshal.ByteArrayToStructureLittleEndian <PrimaryVolumeDescriptor>(vdSector); // Check if this is Joliet if (svd.version == 1) { if (svd.escape_sequences[0] == '%' && svd.escape_sequences[1] == '/') { if (svd.escape_sequences[2] == '@' || svd.escape_sequences[2] == 'C' || svd.escape_sequences[2] == 'E') { jolietvd = svd; } else { AaruConsole.WriteLine("ISO9660 plugin", "Found unknown supplementary volume descriptor"); } } } else { evd = true; } break; } case 3: { vpd = true; break; } } counter++; } DecodedVolumeDescriptor decodedVd; var decodedJolietVd = new DecodedVolumeDescriptor(); XmlFsType = new FileSystemType(); if (pvd == null && hsvd == null && fsvd == null) { information = "ERROR: Could not find primary volume descriptor"; return; } if (highSierraInfo) { decodedVd = DecodeVolumeDescriptor(hsvd.Value); } else if (cdiInfo) { decodedVd = DecodeVolumeDescriptor(fsvd.Value); } else { decodedVd = DecodeVolumeDescriptor(pvd.Value); } if (jolietvd != null) { decodedJolietVd = DecodeJolietDescriptor(jolietvd.Value); } uint rootLocation = 0; uint rootSize = 0; // No need to read root on CD-i, as extensions are not supported... if (!cdiInfo) { rootLocation = highSierraInfo ? hsvd.Value.root_directory_record.extent : pvd.Value.root_directory_record.extent; if (highSierraInfo) { rootSize = hsvd.Value.root_directory_record.size / hsvd.Value.logical_block_size; if (hsvd.Value.root_directory_record.size % hsvd.Value.logical_block_size > 0) { rootSize++; } } else { rootSize = pvd.Value.root_directory_record.size / pvd.Value.logical_block_size; if (pvd.Value.root_directory_record.size % pvd.Value.logical_block_size > 0) { rootSize++; } } } byte[] rootDir = new byte[0]; int rootOff = 0; bool xaExtensions = false; bool apple = false; bool susp = false; bool rrip = false; bool ziso = false; bool amiga = false; bool aaip = false; List <ContinuationArea> contareas = new List <ContinuationArea>(); List <byte[]> refareas = new List <byte[]>(); var suspInformation = new StringBuilder(); if (rootLocation + rootSize < imagePlugin.Info.Sectors) { rootDir = imagePlugin.ReadSectors(rootLocation, rootSize); } // Walk thru root directory to see system area extensions in use while (rootOff + Marshal.SizeOf <DirectoryRecord>() < rootDir.Length && !cdiInfo) { DirectoryRecord record = Marshal.ByteArrayToStructureLittleEndian <DirectoryRecord>(rootDir, rootOff, Marshal.SizeOf <DirectoryRecord>()); int saOff = Marshal.SizeOf <DirectoryRecord>() + record.name_len; saOff += saOff % 2; int saLen = record.length - saOff; if (saLen > 0 && rootOff + saOff + saLen <= rootDir.Length) { byte[] sa = new byte[saLen]; Array.Copy(rootDir, rootOff + saOff, sa, 0, saLen); saOff = 0; while (saOff < saLen) { bool noneFound = true; if (Marshal.SizeOf <CdromXa>() + saOff <= saLen) { CdromXa xa = Marshal.ByteArrayToStructureBigEndian <CdromXa>(sa); if (xa.signature == XA_MAGIC) { xaExtensions = true; saOff += Marshal.SizeOf <CdromXa>(); noneFound = false; } } if (saOff + 2 >= saLen) { break; } ushort nextSignature = BigEndianBitConverter.ToUInt16(sa, saOff); switch (nextSignature) { // Easy, contains size field case APPLE_MAGIC: apple = true; saOff += sa[saOff + 2]; noneFound = false; break; // Not easy, contains size field case APPLE_MAGIC_OLD: apple = true; var appleId = (AppleOldId)sa[saOff + 2]; noneFound = false; switch (appleId) { case AppleOldId.ProDOS: saOff += Marshal.SizeOf <AppleProDOSOldSystemUse>(); break; case AppleOldId.TypeCreator: case AppleOldId.TypeCreatorBundle: saOff += Marshal.SizeOf <AppleHFSTypeCreatorSystemUse>(); break; case AppleOldId.TypeCreatorIcon: case AppleOldId.TypeCreatorIconBundle: saOff += Marshal.SizeOf <AppleHFSIconSystemUse>(); break; case AppleOldId.HFS: saOff += Marshal.SizeOf <AppleHFSOldSystemUse>(); break; } break; // IEEE-P1281 aka SUSP 1.12 case SUSP_INDICATOR: susp = true; saOff += sa[saOff + 2]; noneFound = false; while (saOff + 2 < saLen) { nextSignature = BigEndianBitConverter.ToUInt16(sa, saOff); switch (nextSignature) { case APPLE_MAGIC: if (sa[saOff + 3] == 1 && sa[saOff + 2] == 7) { apple = true; } else { apple |= sa[saOff + 3] != 1; } break; case SUSP_CONTINUATION when saOff + sa[saOff + 2] <= saLen: byte[] ce = new byte[sa[saOff + 2]]; Array.Copy(sa, saOff, ce, 0, ce.Length); ContinuationArea ca = Marshal.ByteArrayToStructureBigEndian <ContinuationArea>(ce); contareas.Add(ca); break; case SUSP_REFERENCE when saOff + sa[saOff + 2] <= saLen: byte[] er = new byte[sa[saOff + 2]]; Array.Copy(sa, saOff, er, 0, er.Length); refareas.Add(er); break; } rrip |= nextSignature == RRIP_MAGIC || nextSignature == RRIP_POSIX_ATTRIBUTES || nextSignature == RRIP_POSIX_DEV_NO || nextSignature == RRIP_SYMLINK || nextSignature == RRIP_NAME || nextSignature == RRIP_CHILDLINK || nextSignature == RRIP_PARENTLINK || nextSignature == RRIP_RELOCATED_DIR || nextSignature == RRIP_TIMESTAMPS || nextSignature == RRIP_SPARSE; ziso |= nextSignature == ZISO_MAGIC; amiga |= nextSignature == AMIGA_MAGIC; aaip |= nextSignature == AAIP_MAGIC || (nextSignature == AAIP_MAGIC_OLD && sa[saOff + 3] == 1 && sa[saOff + 2] >= 9); saOff += sa[saOff + 2]; if (nextSignature == SUSP_TERMINATOR) { break; } } break; } if (noneFound) { break; } } } rootOff += record.length; if (record.length == 0) { break; } } foreach (ContinuationArea ca in contareas) { uint caLen = (ca.ca_length_be + ca.offset_be) / (highSierraInfo ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size); if ((ca.ca_length_be + ca.offset_be) % (highSierraInfo ? hsvd.Value.logical_block_size : pvd.Value.logical_block_size) > 0) { caLen++; } byte[] caSectors = imagePlugin.ReadSectors(ca.block_be, caLen); byte[] caData = new byte[ca.ca_length_be]; Array.Copy(caSectors, ca.offset_be, caData, 0, ca.ca_length_be); int caOff = 0; while (caOff < ca.ca_length_be) { ushort nextSignature = BigEndianBitConverter.ToUInt16(caData, caOff); switch (nextSignature) { // Apple never said to include its extensions inside a continuation area, but just in case case APPLE_MAGIC: if (caData[caOff + 3] == 1 && caData[caOff + 2] == 7) { apple = true; } else { apple |= caData[caOff + 3] != 1; } break; case SUSP_REFERENCE when caOff + caData[caOff + 2] <= ca.ca_length_be: byte[] er = new byte[caData[caOff + 2]]; Array.Copy(caData, caOff, er, 0, er.Length); refareas.Add(er); break; } rrip |= nextSignature == RRIP_MAGIC || nextSignature == RRIP_POSIX_ATTRIBUTES || nextSignature == RRIP_POSIX_DEV_NO || nextSignature == RRIP_SYMLINK || nextSignature == RRIP_NAME || nextSignature == RRIP_CHILDLINK || nextSignature == RRIP_PARENTLINK || nextSignature == RRIP_RELOCATED_DIR || nextSignature == RRIP_TIMESTAMPS || nextSignature == RRIP_SPARSE; ziso |= nextSignature == ZISO_MAGIC; amiga |= nextSignature == AMIGA_MAGIC; aaip |= nextSignature == AAIP_MAGIC || (nextSignature == AAIP_MAGIC_OLD && caData[caOff + 3] == 1 && caData[caOff + 2] >= 9); caOff += caData[caOff + 2]; } } if (refareas.Count > 0) { suspInformation.AppendLine("----------------------------------------"); suspInformation.AppendLine("SYSTEM USE SHARING PROTOCOL INFORMATION:"); suspInformation.AppendLine("----------------------------------------"); counter = 1; foreach (byte[] erb in refareas) { ReferenceArea er = Marshal.ByteArrayToStructureBigEndian <ReferenceArea>(erb); string extId = Encoding.GetString(erb, Marshal.SizeOf <ReferenceArea>(), er.id_len); string extDes = Encoding.GetString(erb, Marshal.SizeOf <ReferenceArea>() + er.id_len, er.des_len); string extSrc = Encoding.GetString(erb, Marshal.SizeOf <ReferenceArea>() + er.id_len + er.des_len, er.src_len); suspInformation.AppendFormat("Extension: {0}", counter).AppendLine(); suspInformation.AppendFormat("\tID: {0}, version {1}", extId, er.ext_ver).AppendLine(); suspInformation.AppendFormat("\tDescription: {0}", extDes).AppendLine(); suspInformation.AppendFormat("\tSource: {0}", extSrc).AppendLine(); counter++; } } byte[] ipbinSector = imagePlugin.ReadSector(0 + partition.Start); CD.IPBin? segaCd = CD.DecodeIPBin(ipbinSector); Saturn.IPBin? saturn = Saturn.DecodeIPBin(ipbinSector); Dreamcast.IPBin?dreamcast = Dreamcast.DecodeIPBin(ipbinSector); string fsFormat; if (highSierraInfo) { fsFormat = "High Sierra Format"; } else if (cdiInfo) { fsFormat = "CD-i"; } else { fsFormat = "ISO9660"; } isoMetadata.AppendFormat("{0} file system", fsFormat).AppendLine(); if (xaExtensions) { isoMetadata.AppendLine("CD-ROM XA extensions present."); } if (amiga) { isoMetadata.AppendLine("Amiga extensions present."); } if (apple) { isoMetadata.AppendLine("Apple extensions present."); } if (jolietvd != null) { isoMetadata.AppendLine("Joliet extensions present."); } if (susp) { isoMetadata.AppendLine("System Use Sharing Protocol present."); } if (rrip) { isoMetadata.AppendLine("Rock Ridge Interchange Protocol present."); } if (aaip) { isoMetadata.AppendLine("Arbitrary Attribute Interchange Protocol present."); } if (ziso) { isoMetadata.AppendLine("zisofs compression present."); } if (evd) { isoMetadata.AppendLine("Contains Enhanved Volume Descriptor."); } if (vpd) { isoMetadata.AppendLine("Contains Volume Partition Descriptor."); } if (bvd != null) { isoMetadata.AppendFormat("Disc bootable following {0} specifications.", bootSpec).AppendLine(); } if (segaCd != null) { isoMetadata.AppendLine("This is a SegaCD / MegaCD disc."); isoMetadata.AppendLine(CD.Prettify(segaCd)); } if (saturn != null) { isoMetadata.AppendLine("This is a Sega Saturn disc."); isoMetadata.AppendLine(Saturn.Prettify(saturn)); } if (dreamcast != null) { isoMetadata.AppendLine("This is a Sega Dreamcast disc."); isoMetadata.AppendLine(Dreamcast.Prettify(dreamcast)); } isoMetadata.AppendFormat("{0}------------------------------", cdiInfo ? "---------------" : ""). AppendLine(); isoMetadata.AppendFormat("{0}VOLUME DESCRIPTOR INFORMATION:", cdiInfo ? "FILE STRUCTURE " : ""). AppendLine(); isoMetadata.AppendFormat("{0}------------------------------", cdiInfo ? "---------------" : ""). AppendLine(); isoMetadata.AppendFormat("System identifier: {0}", decodedVd.SystemIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume identifier: {0}", decodedVd.VolumeIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume set identifier: {0}", decodedVd.VolumeSetIdentifier).AppendLine(); isoMetadata.AppendFormat("Publisher identifier: {0}", decodedVd.PublisherIdentifier).AppendLine(); isoMetadata.AppendFormat("Data preparer identifier: {0}", decodedVd.DataPreparerIdentifier).AppendLine(); isoMetadata.AppendFormat("Application identifier: {0}", decodedVd.ApplicationIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume creation date: {0}", decodedVd.CreationTime).AppendLine(); if (decodedVd.HasModificationTime) { isoMetadata.AppendFormat("Volume modification date: {0}", decodedVd.ModificationTime).AppendLine(); } else { isoMetadata.AppendFormat("Volume has not been modified.").AppendLine(); } if (decodedVd.HasExpirationTime) { isoMetadata.AppendFormat("Volume expiration date: {0}", decodedVd.ExpirationTime).AppendLine(); } else { isoMetadata.AppendFormat("Volume does not expire.").AppendLine(); } if (decodedVd.HasEffectiveTime) { isoMetadata.AppendFormat("Volume effective date: {0}", decodedVd.EffectiveTime).AppendLine(); } else { isoMetadata.AppendFormat("Volume has always been effective.").AppendLine(); } isoMetadata.AppendFormat("Volume has {0} blocks of {1} bytes each", decodedVd.Blocks, decodedVd.BlockSize). AppendLine(); if (jolietvd != null) { isoMetadata.AppendLine("-------------------------------------"); isoMetadata.AppendLine("JOLIET VOLUME DESCRIPTOR INFORMATION:"); isoMetadata.AppendLine("-------------------------------------"); isoMetadata.AppendFormat("System identifier: {0}", decodedJolietVd.SystemIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume identifier: {0}", decodedJolietVd.VolumeIdentifier).AppendLine(); isoMetadata.AppendFormat("Volume set identifier: {0}", decodedJolietVd.VolumeSetIdentifier). AppendLine(); isoMetadata.AppendFormat("Publisher identifier: {0}", decodedJolietVd.PublisherIdentifier).AppendLine(); isoMetadata.AppendFormat("Data preparer identifier: {0}", decodedJolietVd.DataPreparerIdentifier). AppendLine(); isoMetadata.AppendFormat("Application identifier: {0}", decodedJolietVd.ApplicationIdentifier). AppendLine(); isoMetadata.AppendFormat("Volume creation date: {0}", decodedJolietVd.CreationTime).AppendLine(); if (decodedJolietVd.HasModificationTime) { isoMetadata.AppendFormat("Volume modification date: {0}", decodedJolietVd.ModificationTime). AppendLine(); } else { isoMetadata.AppendFormat("Volume has not been modified.").AppendLine(); } if (decodedJolietVd.HasExpirationTime) { isoMetadata.AppendFormat("Volume expiration date: {0}", decodedJolietVd.ExpirationTime). AppendLine(); } else { isoMetadata.AppendFormat("Volume does not expire.").AppendLine(); } if (decodedJolietVd.HasEffectiveTime) { isoMetadata.AppendFormat("Volume effective date: {0}", decodedJolietVd.EffectiveTime).AppendLine(); } else { isoMetadata.AppendFormat("Volume has always been effective.").AppendLine(); } } if (torito != null) { vdSector = imagePlugin.ReadSector(torito.Value.catalog_sector + partition.Start); int toritoOff = 0; if (vdSector[toritoOff] != 1) { goto exit_torito; } ElToritoValidationEntry valentry = Marshal.ByteArrayToStructureLittleEndian <ElToritoValidationEntry>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); if (valentry.signature != EL_TORITO_MAGIC) { goto exit_torito; } toritoOff += EL_TORITO_ENTRY_SIZE; ElToritoInitialEntry initialEntry = Marshal.ByteArrayToStructureLittleEndian <ElToritoInitialEntry>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); initialEntry.boot_type = (ElToritoEmulation)((byte)initialEntry.boot_type & 0xF); AaruConsole.DebugWriteLine("DEBUG (ISO9660 plugin)", "initialEntry.load_rba = {0}", initialEntry.load_rba); AaruConsole.DebugWriteLine("DEBUG (ISO9660 plugin)", "initialEntry.sector_count = {0}", initialEntry.sector_count); byte[] bootImage = (initialEntry.load_rba + partition.Start + initialEntry.sector_count) - 1 <= partition.End ? imagePlugin.ReadSectors(initialEntry.load_rba + partition.Start, initialEntry.sector_count) : null; isoMetadata.AppendLine("----------------------"); isoMetadata.AppendLine("EL TORITO INFORMATION:"); isoMetadata.AppendLine("----------------------"); isoMetadata.AppendLine("Initial entry:"); isoMetadata.AppendFormat("\tDeveloper ID: {0}", Encoding.GetString(valentry.developer_id)).AppendLine(); if (initialEntry.bootable == ElToritoIndicator.Bootable) { isoMetadata.AppendFormat("\tBootable on {0}", valentry.platform_id).AppendLine(); isoMetadata.AppendFormat("\tBootable image starts at sector {0} and runs for {1} sectors", initialEntry.load_rba, initialEntry.sector_count).AppendLine(); if (valentry.platform_id == ElToritoPlatform.x86) { isoMetadata.AppendFormat("\tBootable image will be loaded at segment {0:X4}h", initialEntry.load_seg == 0 ? 0x7C0 : initialEntry.load_seg). AppendLine(); } else { isoMetadata.AppendFormat("\tBootable image will be loaded at 0x{0:X8}", (uint)initialEntry.load_seg * 10).AppendLine(); } switch (initialEntry.boot_type) { case ElToritoEmulation.None: isoMetadata.AppendLine("\tImage uses no emulation"); break; case ElToritoEmulation.Md2hd: isoMetadata.AppendLine("\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy"); break; case ElToritoEmulation.Mf2hd: isoMetadata.AppendLine("\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy"); break; case ElToritoEmulation.Mf2ed: isoMetadata.AppendLine("\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy"); break; default: isoMetadata.AppendFormat("\tImage uses unknown emulation type {0}", (byte)initialEntry.boot_type).AppendLine(); break; } isoMetadata.AppendFormat("\tSystem type: 0x{0:X2}", initialEntry.system_type).AppendLine(); if (bootImage != null) { isoMetadata.AppendFormat("\tBootable image's SHA1: {0}", Sha1Context.Data(bootImage, out _)). AppendLine(); } } else { isoMetadata.AppendLine("\tNot bootable"); } toritoOff += EL_TORITO_ENTRY_SIZE; const int SECTION_COUNTER = 2; while (toritoOff < vdSector.Length && (vdSector[toritoOff] == (byte)ElToritoIndicator.Header || vdSector[toritoOff] == (byte)ElToritoIndicator.LastHeader)) { ElToritoSectionHeaderEntry sectionHeader = Marshal.ByteArrayToStructureLittleEndian <ElToritoSectionHeaderEntry>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); toritoOff += EL_TORITO_ENTRY_SIZE; isoMetadata.AppendFormat("Boot section {0}:", SECTION_COUNTER); isoMetadata.AppendFormat("\tSection ID: {0}", Encoding.GetString(sectionHeader.identifier)). AppendLine(); for (int entryCounter = 1; entryCounter <= sectionHeader.entries && toritoOff < vdSector.Length; entryCounter++) { ElToritoSectionEntry sectionEntry = Marshal.ByteArrayToStructureLittleEndian <ElToritoSectionEntry>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); toritoOff += EL_TORITO_ENTRY_SIZE; isoMetadata.AppendFormat("\tEntry {0}:", entryCounter); if (sectionEntry.bootable == ElToritoIndicator.Bootable) { bootImage = (sectionEntry.load_rba + partition.Start + sectionEntry.sector_count) - 1 <= partition.End ? imagePlugin.ReadSectors(sectionEntry.load_rba + partition.Start, sectionEntry.sector_count) : null; isoMetadata.AppendFormat("\t\tBootable on {0}", sectionHeader.platform_id).AppendLine(); isoMetadata.AppendFormat("\t\tBootable image starts at sector {0} and runs for {1} sectors", sectionEntry.load_rba, sectionEntry.sector_count).AppendLine(); if (valentry.platform_id == ElToritoPlatform.x86) { isoMetadata.AppendFormat("\t\tBootable image will be loaded at segment {0:X4}h", sectionEntry.load_seg == 0 ? 0x7C0 : sectionEntry.load_seg). AppendLine(); } else { isoMetadata.AppendFormat("\t\tBootable image will be loaded at 0x{0:X8}", (uint)sectionEntry.load_seg * 10).AppendLine(); } switch ((ElToritoEmulation)((byte)sectionEntry.boot_type & 0xF)) { case ElToritoEmulation.None: isoMetadata.AppendLine("\t\tImage uses no emulation"); break; case ElToritoEmulation.Md2hd: isoMetadata. AppendLine("\t\tImage emulates a 5.25\" high-density (MD2HD, 1.2Mb) floppy"); break; case ElToritoEmulation.Mf2hd: isoMetadata. AppendLine("\t\tImage emulates a 3.5\" high-density (MF2HD, 1.44Mb) floppy"); break; case ElToritoEmulation.Mf2ed: isoMetadata. AppendLine("\t\tImage emulates a 3.5\" extra-density (MF2ED, 2.88Mb) floppy"); break; default: isoMetadata.AppendFormat("\t\tImage uses unknown emulation type {0}", (byte)initialEntry.boot_type).AppendLine(); break; } isoMetadata.AppendFormat("\t\tSelection criteria type: {0}", sectionEntry.selection_criteria_type).AppendLine(); isoMetadata.AppendFormat("\t\tSystem type: 0x{0:X2}", sectionEntry.system_type). AppendLine(); if (bootImage != null) { isoMetadata.AppendFormat("\t\tBootable image's SHA1: {0}", Sha1Context.Data(bootImage, out _)).AppendLine(); } } else { isoMetadata.AppendLine("\t\tNot bootable"); } var flags = (ElToritoFlags)((byte)sectionEntry.boot_type & 0xF0); if (flags.HasFlag(ElToritoFlags.ATAPI)) { isoMetadata.AppendLine("\t\tImage contains ATAPI drivers"); } if (flags.HasFlag(ElToritoFlags.SCSI)) { isoMetadata.AppendLine("\t\tImage contains SCSI drivers"); } if (!flags.HasFlag(ElToritoFlags.Continued)) { continue; } while (toritoOff < vdSector.Length) { ElToritoSectionEntryExtension sectionExtension = Marshal.ByteArrayToStructureLittleEndian <ElToritoSectionEntryExtension>(vdSector, toritoOff, EL_TORITO_ENTRY_SIZE); toritoOff += EL_TORITO_ENTRY_SIZE; if (!sectionExtension.extension_flags.HasFlag(ElToritoFlags.Continued)) { break; } } } if (sectionHeader.header_id == ElToritoIndicator.LastHeader) { break; } } } exit_torito: if (refareas.Count > 0) { isoMetadata.Append(suspInformation); } XmlFsType.Type = fsFormat; if (jolietvd != null) { XmlFsType.VolumeName = decodedJolietVd.VolumeIdentifier; if (string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) || decodedVd.SystemIdentifier.Length > decodedJolietVd.SystemIdentifier.Length) { XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier; } else { XmlFsType.SystemIdentifier = string.IsNullOrEmpty(decodedJolietVd.SystemIdentifier) ? null : decodedJolietVd.SystemIdentifier; } if (string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) || decodedVd.VolumeSetIdentifier.Length > decodedJolietVd.VolumeSetIdentifier.Length) { XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; } else { XmlFsType.VolumeSetIdentifier = string.IsNullOrEmpty(decodedJolietVd.VolumeSetIdentifier) ? null : decodedJolietVd.VolumeSetIdentifier; } if (string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) || decodedVd.PublisherIdentifier.Length > decodedJolietVd.PublisherIdentifier.Length) { XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier; } else { XmlFsType.PublisherIdentifier = string.IsNullOrEmpty(decodedJolietVd.PublisherIdentifier) ? null : decodedJolietVd.PublisherIdentifier; } if (string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) || decodedVd.DataPreparerIdentifier.Length > decodedJolietVd.DataPreparerIdentifier.Length) { XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; } else { XmlFsType.DataPreparerIdentifier = string.IsNullOrEmpty(decodedJolietVd.DataPreparerIdentifier) ? null : decodedJolietVd.DataPreparerIdentifier; } if (string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) || decodedVd.ApplicationIdentifier.Length > decodedJolietVd.ApplicationIdentifier.Length) { XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier; } else { XmlFsType.ApplicationIdentifier = string.IsNullOrEmpty(decodedJolietVd.ApplicationIdentifier) ? null : decodedJolietVd.ApplicationIdentifier; } XmlFsType.CreationDate = decodedJolietVd.CreationTime; XmlFsType.CreationDateSpecified = true; if (decodedJolietVd.HasModificationTime) { XmlFsType.ModificationDate = decodedJolietVd.ModificationTime; XmlFsType.ModificationDateSpecified = true; } if (decodedJolietVd.HasExpirationTime) { XmlFsType.ExpirationDate = decodedJolietVd.ExpirationTime; XmlFsType.ExpirationDateSpecified = true; } if (decodedJolietVd.HasEffectiveTime) { XmlFsType.EffectiveDate = decodedJolietVd.EffectiveTime; XmlFsType.EffectiveDateSpecified = true; } } else { XmlFsType.SystemIdentifier = decodedVd.SystemIdentifier; XmlFsType.VolumeName = decodedVd.VolumeIdentifier; XmlFsType.VolumeSetIdentifier = decodedVd.VolumeSetIdentifier; XmlFsType.PublisherIdentifier = decodedVd.PublisherIdentifier; XmlFsType.DataPreparerIdentifier = decodedVd.DataPreparerIdentifier; XmlFsType.ApplicationIdentifier = decodedVd.ApplicationIdentifier; XmlFsType.CreationDate = decodedVd.CreationTime; XmlFsType.CreationDateSpecified = true; if (decodedVd.HasModificationTime) { XmlFsType.ModificationDate = decodedVd.ModificationTime; XmlFsType.ModificationDateSpecified = true; } if (decodedVd.HasExpirationTime) { XmlFsType.ExpirationDate = decodedVd.ExpirationTime; XmlFsType.ExpirationDateSpecified = true; } if (decodedVd.HasEffectiveTime) { XmlFsType.EffectiveDate = decodedVd.EffectiveTime; XmlFsType.EffectiveDateSpecified = true; } } XmlFsType.Bootable |= bvd != null || segaCd != null || saturn != null || dreamcast != null; XmlFsType.Clusters = decodedVd.Blocks; XmlFsType.ClusterSize = decodedVd.BlockSize; information = isoMetadata.ToString(); }
public bool Open(IFilter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); stream.Seek(0, SeekOrigin.Begin); if (stream.Length < 512) { return(false); } byte[] headerB = new byte[256]; stream.Read(headerB, 0, 256); CpcDiskInfo header = Marshal.ByteArrayToStructureLittleEndian <CpcDiskInfo>(headerB); if (!cpcdskId.SequenceEqual(header.magic.Take(cpcdskId.Length)) && !edskId.SequenceEqual(header.magic) && !du54Id.SequenceEqual(header.magic)) { return(false); } extended = edskId.SequenceEqual(header.magic); AaruConsole.DebugWriteLine("CPCDSK plugin", "Extended = {0}", extended); AaruConsole.DebugWriteLine("CPCDSK plugin", "header.magic = \"{0}\"", StringHandlers.CToString(header.magic)); AaruConsole.DebugWriteLine("CPCDSK plugin", "header.magic2 = \"{0}\"", StringHandlers.CToString(header.magic2)); AaruConsole.DebugWriteLine("CPCDSK plugin", "header.creator = \"{0}\"", StringHandlers.CToString(header.creator)); AaruConsole.DebugWriteLine("CPCDSK plugin", "header.tracks = {0}", header.tracks); AaruConsole.DebugWriteLine("CPCDSK plugin", "header.sides = {0}", header.sides); if (!extended) { AaruConsole.DebugWriteLine("CPCDSK plugin", "header.tracksize = {0}", header.tracksize); } else { for (int i = 0; i < header.tracks; i++) { for (int j = 0; j < header.sides; j++) { AaruConsole.DebugWriteLine("CPCDSK plugin", "Track {0} Side {1} size = {2}", i, j, header.tracksizeTable[(i * header.sides) + j] * 256); } } } ulong currentSector = 0; sectors = new Dictionary <ulong, byte[]>(); addressMarks = new Dictionary <ulong, byte[]>(); ulong readtracks = 0; bool allTracksSameSize = true; ulong sectorsPerTrack = 0; // Seek to first track descriptor stream.Seek(256, SeekOrigin.Begin); for (int i = 0; i < header.tracks; i++) { for (int j = 0; j < header.sides; j++) { // Track not stored in image if (extended && header.tracksizeTable[(i * header.sides) + j] == 0) { continue; } long trackPos = stream.Position; byte[] trackB = new byte[256]; stream.Read(trackB, 0, 256); CpcTrackInfo trackInfo = Marshal.ByteArrayToStructureLittleEndian <CpcTrackInfo>(trackB); if (!trackId.SequenceEqual(trackInfo.magic)) { AaruConsole.ErrorWriteLine("Not the expected track info."); return(false); } AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].magic = \"{0}\"", StringHandlers.CToString(trackInfo.magic), i, j); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].bps = {0}", SizeCodeToBytes(trackInfo.bps), i, j); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].dataRate = {0}", trackInfo.dataRate, i, j); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].filler = 0x{0:X2}", trackInfo.filler, i, j); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].gap3 = 0x{0:X2}", trackInfo.gap3, i, j); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].padding = {0}", trackInfo.padding, i, j); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].recordingMode = {0}", trackInfo.recordingMode, i, j); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].sectors = {0}", trackInfo.sectors, i, j); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].side = {0}", trackInfo.side, i, j); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].track = {0}", trackInfo.track, i, j); if (trackInfo.sectors != sectorsPerTrack) { if (sectorsPerTrack == 0) { sectorsPerTrack = trackInfo.sectors; } else { allTracksSameSize = false; } } byte[][] thisTrackSectors = new byte[trackInfo.sectors][]; byte[][] thisTrackAddressMarks = new byte[trackInfo.sectors][]; for (int k = 1; k <= trackInfo.sectors; k++) { AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].sector[{3}].id = 0x{0:X2}", trackInfo.sectorsInfo[k - 1].id, i, j, k); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].sector[{3}].len = {0}", trackInfo.sectorsInfo[k - 1].len, i, j, k); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].sector[{3}].side = {0}", trackInfo.sectorsInfo[k - 1].side, i, j, k); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].sector[{3}].size = {0}", SizeCodeToBytes(trackInfo.sectorsInfo[k - 1].size), i, j, k); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].sector[{3}].st1 = 0x{0:X2}", trackInfo.sectorsInfo[k - 1].st1, i, j, k); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].sector[{3}].st2 = 0x{0:X2}", trackInfo.sectorsInfo[k - 1].st2, i, j, k); AaruConsole.DebugWriteLine("CPCDSK plugin", "trackInfo[{1}:{2}].sector[{3}].track = {0}", trackInfo.sectorsInfo[k - 1].track, i, j, k); int sectLen = extended ? trackInfo.sectorsInfo[k - 1].len : SizeCodeToBytes(trackInfo.sectorsInfo[k - 1].size); byte[] sector = new byte[sectLen]; stream.Read(sector, 0, sectLen); if (sectLen < SizeCodeToBytes(trackInfo.sectorsInfo[k - 1].size)) { byte[] temp = new byte[SizeCodeToBytes(trackInfo.sectorsInfo[k - 1].size)]; Array.Copy(sector, 0, temp, 0, sector.Length); sector = temp; } else if (sectLen > SizeCodeToBytes(trackInfo.sectorsInfo[k - 1].size)) { byte[] temp = new byte[SizeCodeToBytes(trackInfo.sectorsInfo[k - 1].size)]; Array.Copy(sector, 0, temp, 0, temp.Length); sector = temp; } thisTrackSectors[(trackInfo.sectorsInfo[k - 1].id & 0x3F) - 1] = sector; byte[] amForCrc = new byte[8]; amForCrc[0] = 0xA1; amForCrc[1] = 0xA1; amForCrc[2] = 0xA1; amForCrc[3] = (byte)IBMIdType.AddressMark; amForCrc[4] = trackInfo.sectorsInfo[k - 1].track; amForCrc[5] = trackInfo.sectorsInfo[k - 1].side; amForCrc[6] = trackInfo.sectorsInfo[k - 1].id; amForCrc[7] = (byte)trackInfo.sectorsInfo[k - 1].size; CRC16IBMContext.Data(amForCrc, 8, out byte[] amCrc); byte[] addressMark = new byte[22]; Array.Copy(amForCrc, 0, addressMark, 12, 8); Array.Copy(amCrc, 0, addressMark, 20, 2); thisTrackAddressMarks[(trackInfo.sectorsInfo[k - 1].id & 0x3F) - 1] = addressMark; } for (int s = 0; s < thisTrackSectors.Length; s++) { sectors.Add(currentSector, thisTrackSectors[s]); addressMarks.Add(currentSector, thisTrackAddressMarks[s]); currentSector++; if (thisTrackSectors[s].Length > imageInfo.SectorSize) { imageInfo.SectorSize = (uint)thisTrackSectors[s].Length; } } stream.Seek(trackPos, SeekOrigin.Begin); if (extended) { stream.Seek(header.tracksizeTable[(i * header.sides) + j] * 256, SeekOrigin.Current); imageInfo.ImageSize += (ulong)(header.tracksizeTable[(i * header.sides) + j] * 256) - 256; } else { stream.Seek(header.tracksize, SeekOrigin.Current); imageInfo.ImageSize += (ulong)header.tracksize - 256; } readtracks++; } } AaruConsole.DebugWriteLine("CPCDSK plugin", "Read {0} sectors", sectors.Count); AaruConsole.DebugWriteLine("CPCDSK plugin", "Read {0} tracks", readtracks); AaruConsole.DebugWriteLine("CPCDSK plugin", "All tracks are same size? {0}", allTracksSameSize); imageInfo.Application = StringHandlers.CToString(header.creator); imageInfo.CreationTime = imageFilter.GetCreationTime(); imageInfo.LastModificationTime = imageFilter.GetLastWriteTime(); imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename()); imageInfo.Sectors = (ulong)sectors.Count; imageInfo.XmlMediaType = XmlMediaType.BlockMedia; imageInfo.MediaType = MediaType.CompactFloppy; imageInfo.ReadableSectorTags.Add(SectorTagType.FloppyAddressMark); // Debug writing full disk as raw /* * FileStream foo = new FileStream(Path.GetFileNameWithoutExtension(imageFilter.GetFilename()) + ".bin", FileMode.Create); * for(ulong i = 0; i < (ulong)sectors.Count; i++) * { * byte[] foob; * sectors.TryGetValue(i, out foob); * foo.Write(foob, 0, foob.Length); * } * foo.Close(); */ imageInfo.Cylinders = header.tracks; imageInfo.Heads = header.sides; imageInfo.SectorsPerTrack = (uint)(imageInfo.Sectors / (imageInfo.Cylinders * imageInfo.Heads)); return(true); }
public bool Open(IFilter imageFilter) { Header = new ScpHeader(); _scpStream = imageFilter.GetDataForkStream(); _scpStream.Seek(0, SeekOrigin.Begin); if (_scpStream.Length < Marshal.SizeOf <ScpHeader>()) { return(false); } byte[] hdr = new byte[Marshal.SizeOf <ScpHeader>()]; _scpStream.Read(hdr, 0, Marshal.SizeOf <ScpHeader>()); Header = Marshal.ByteArrayToStructureLittleEndian <ScpHeader>(hdr); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.signature = \"{0}\"", StringHandlers.CToString(Header.signature)); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.version = {0}.{1}", (Header.version & 0xF0) >> 4, Header.version & 0xF); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.type = {0}", Header.type); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.revolutions = {0}", Header.revolutions); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.start = {0}", Header.start); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.end = {0}", Header.end); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.flags = {0}", Header.flags); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.bitCellEncoding = {0}", Header.bitCellEncoding); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.heads = {0}", Header.heads); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.reserved = {0}", Header.reserved); AaruConsole.DebugWriteLine("SuperCardPro plugin", "header.checksum = 0x{0:X8}", Header.checksum); if (!_scpSignature.SequenceEqual(Header.signature)) { return(false); } ScpTracks = new Dictionary <byte, TrackHeader>(); for (byte t = Header.start; t <= Header.end; t++) { if (t >= Header.offsets.Length) { break; } _scpStream.Position = Header.offsets[t]; var trk = new TrackHeader { Signature = new byte[3], Entries = new TrackEntry[Header.revolutions] }; _scpStream.Read(trk.Signature, 0, trk.Signature.Length); trk.TrackNumber = (byte)_scpStream.ReadByte(); if (!trk.Signature.SequenceEqual(_trkSignature)) { AaruConsole.DebugWriteLine("SuperCardPro plugin", "Track header at {0} contains incorrect signature.", Header.offsets[t]); continue; } if (trk.TrackNumber != t) { AaruConsole.DebugWriteLine("SuperCardPro plugin", "Track number at {0} should be {1} but is {2}.", Header.offsets[t], t, trk.TrackNumber); continue; } AaruConsole.DebugWriteLine("SuperCardPro plugin", "Found track {0} at {1}.", t, Header.offsets[t]); for (byte r = 0; r < Header.revolutions; r++) { byte[] rev = new byte[Marshal.SizeOf <TrackEntry>()]; _scpStream.Read(rev, 0, Marshal.SizeOf <TrackEntry>()); trk.Entries[r] = Marshal.ByteArrayToStructureLittleEndian <TrackEntry>(rev); // De-relative offsets trk.Entries[r].dataOffset += Header.offsets[t]; } ScpTracks.Add(t, trk); } if (Header.flags.HasFlag(ScpFlags.HasFooter)) { long position = _scpStream.Position; _scpStream.Seek(-4, SeekOrigin.End); while (_scpStream.Position >= position) { byte[] footerSig = new byte[4]; _scpStream.Read(footerSig, 0, 4); uint footerMagic = BitConverter.ToUInt32(footerSig, 0); if (footerMagic == FOOTER_SIGNATURE) { _scpStream.Seek(-Marshal.SizeOf <Footer>(), SeekOrigin.Current); AaruConsole.DebugWriteLine("SuperCardPro plugin", "Found footer at {0}", _scpStream.Position); byte[] ftr = new byte[Marshal.SizeOf <Footer>()]; _scpStream.Read(ftr, 0, Marshal.SizeOf <Footer>()); Footer footer = Marshal.ByteArrayToStructureLittleEndian <Footer>(ftr); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.manufacturerOffset = 0x{0:X8}", footer.manufacturerOffset); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.modelOffset = 0x{0:X8}", footer.modelOffset); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.serialOffset = 0x{0:X8}", footer.serialOffset); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.creatorOffset = 0x{0:X8}", footer.creatorOffset); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.applicationOffset = 0x{0:X8}", footer.applicationOffset); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.commentsOffset = 0x{0:X8}", footer.commentsOffset); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.creationTime = {0}", footer.creationTime); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.modificationTime = {0}", footer.modificationTime); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.applicationVersion = {0}.{1}", (footer.applicationVersion & 0xF0) >> 4, footer.applicationVersion & 0xF); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.hardwareVersion = {0}.{1}", (footer.hardwareVersion & 0xF0) >> 4, footer.hardwareVersion & 0xF); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.firmwareVersion = {0}.{1}", (footer.firmwareVersion & 0xF0) >> 4, footer.firmwareVersion & 0xF); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.imageVersion = {0}.{1}", (footer.imageVersion & 0xF0) >> 4, footer.imageVersion & 0xF); AaruConsole.DebugWriteLine("SuperCardPro plugin", "footer.signature = \"{0}\"", StringHandlers.CToString(BitConverter.GetBytes(footer.signature))); _imageInfo.DriveManufacturer = ReadPStringUtf8(_scpStream, footer.manufacturerOffset); _imageInfo.DriveModel = ReadPStringUtf8(_scpStream, footer.modelOffset); _imageInfo.DriveSerialNumber = ReadPStringUtf8(_scpStream, footer.serialOffset); _imageInfo.Creator = ReadPStringUtf8(_scpStream, footer.creatorOffset); _imageInfo.Application = ReadPStringUtf8(_scpStream, footer.applicationOffset); _imageInfo.Comments = ReadPStringUtf8(_scpStream, footer.commentsOffset); AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.driveManufacturer = \"{0}\"", _imageInfo.DriveManufacturer); AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.driveModel = \"{0}\"", _imageInfo.DriveModel); AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.driveSerialNumber = \"{0}\"", _imageInfo.DriveSerialNumber); AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageCreator = \"{0}\"", _imageInfo.Creator); AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageApplication = \"{0}\"", _imageInfo.Application); AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageComments = \"{0}\"", _imageInfo.Comments); _imageInfo.CreationTime = footer.creationTime != 0 ? DateHandlers.UnixToDateTime(footer.creationTime) : imageFilter.GetCreationTime(); _imageInfo.LastModificationTime = footer.modificationTime != 0 ? DateHandlers.UnixToDateTime(footer.modificationTime) : imageFilter.GetLastWriteTime(); AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageCreationTime = {0}", _imageInfo.CreationTime); AaruConsole.DebugWriteLine("SuperCardPro plugin", "ImageInfo.imageLastModificationTime = {0}", _imageInfo.LastModificationTime); _imageInfo.ApplicationVersion = $"{(footer.applicationVersion & 0xF0) >> 4}.{footer.applicationVersion & 0xF}"; _imageInfo.DriveFirmwareRevision = $"{(footer.firmwareVersion & 0xF0) >> 4}.{footer.firmwareVersion & 0xF}"; _imageInfo.Version = $"{(footer.imageVersion & 0xF0) >> 4}.{footer.imageVersion & 0xF}"; break; } _scpStream.Seek(-8, SeekOrigin.Current); } } else { _imageInfo.Application = "SuperCardPro"; _imageInfo.ApplicationVersion = $"{(Header.version & 0xF0) >> 4}.{Header.version & 0xF}"; _imageInfo.CreationTime = imageFilter.GetCreationTime(); _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime(); _imageInfo.Version = "1.5"; } throw new NotImplementedException("Flux decoding is not yet implemented."); }
/// <summary>Implements creating a metadata sidecar</summary> /// <returns>The metadata sidecar</returns> public CICMMetadataType Create() { // For fast debugging, skip checksum //goto skipImageChecksum; byte[] data; long position = 0; UpdateStatus("Hashing image file..."); InitProgress(); while (position < _fi.Length - 1048576) { if (_aborted) { return(_sidecar); } data = new byte[1048576]; _fs.Read(data, 0, 1048576); UpdateProgress("Hashing image file byte {0} of {1}", position, _fi.Length); _imgChkWorker.Update(data); position += 1048576; } data = new byte[_fi.Length - position]; _fs.Read(data, 0, (int)(_fi.Length - position)); UpdateProgress("Hashing image file byte {0} of {1}", position, _fi.Length); _imgChkWorker.Update(data); // For fast debugging, skip checksum //skipImageChecksum: EndProgress(); _fs.Close(); List <ChecksumType> imgChecksums = _imgChkWorker.End(); _sidecar.OpticalDisc = null; _sidecar.BlockMedia = null; _sidecar.AudioMedia = null; _sidecar.LinearMedia = null; if (_aborted) { return(_sidecar); } switch (_image.Info.XmlMediaType) { case XmlMediaType.OpticalDisc: if (_image is IOpticalMediaImage opticalImage) { OpticalDisc(opticalImage, _filterId, _imagePath, _fi, _plugins, imgChecksums, ref _sidecar, _encoding); } else { AaruConsole. ErrorWriteLine("The specified image says it contains an optical media but at the same time says it does not support them."); AaruConsole.ErrorWriteLine("Please open an issue at Github."); } break; case XmlMediaType.BlockMedia: BlockMedia(_image, _filterId, _imagePath, _fi, _plugins, imgChecksums, ref _sidecar, _encoding); break; case XmlMediaType.LinearMedia: LinearMedia(_image, _filterId, _imagePath, _fi, _plugins, imgChecksums, ref _sidecar, _encoding); break; case XmlMediaType.AudioMedia: AudioMedia(_image, _filterId, _imagePath, _fi, _plugins, imgChecksums, ref _sidecar, _encoding); break; } return(_sidecar); }
/// <summary>Sends the MMC READ CD command</summary> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <param name="buffer">Buffer where the MMC READ CD response will be stored</param> /// <param name="senseBuffer">Sense buffer.</param> /// <param name="timeout">Timeout in seconds.</param> /// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param> /// <param name="lba">Start block address.</param> /// <param name="transferLength">How many blocks to read.</param> /// <param name="blockSize">Block size.</param> /// <param name="expectedSectorType">Expected sector type.</param> /// <param name="dap">If set to <c>true</c> CD-DA should be modified by mute and interpolation</param> /// <param name="relAddr">If set to <c>true</c> address is relative to current position.</param> /// <param name="sync">If set to <c>true</c> we request the sync bytes for data sectors.</param> /// <param name="headerCodes">Header codes.</param> /// <param name="userData">If set to <c>true</c> we request the user data.</param> /// <param name="edcEcc">If set to <c>true</c> we request the EDC/ECC fields for data sectors.</param> /// <param name="c2Error">C2 error options.</param> /// <param name="subchannel">Subchannel selection.</param> public bool ReadCd(out byte[] buffer, out byte[] senseBuffer, uint lba, uint blockSize, uint transferLength, MmcSectorTypes expectedSectorType, bool dap, bool relAddr, bool sync, MmcHeaderCodes headerCodes, bool userData, bool edcEcc, MmcErrorField c2Error, MmcSubchannel subchannel, uint timeout, out double duration) { senseBuffer = new byte[32]; byte[] cdb = new byte[12]; cdb[0] = (byte)ScsiCommands.ReadCd; cdb[1] = (byte)((byte)expectedSectorType << 2); if (dap) { cdb[1] += 0x02; } if (relAddr) { cdb[1] += 0x01; } cdb[2] = (byte)((lba & 0xFF000000) >> 24); cdb[3] = (byte)((lba & 0xFF0000) >> 16); cdb[4] = (byte)((lba & 0xFF00) >> 8); cdb[5] = (byte)(lba & 0xFF); cdb[6] = (byte)((transferLength & 0xFF0000) >> 16); cdb[7] = (byte)((transferLength & 0xFF00) >> 8); cdb[8] = (byte)(transferLength & 0xFF); cdb[9] = (byte)((byte)c2Error << 1); cdb[9] += (byte)((byte)headerCodes << 5); if (sync) { cdb[9] += 0x80; } if (userData) { cdb[9] += 0x10; } if (edcEcc) { cdb[9] += 0x08; } cdb[10] = (byte)subchannel; buffer = new byte[blockSize * transferLength]; LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); Error = LastError != 0; AaruConsole.DebugWriteLine("SCSI Device", "READ CD (LBA: {1}, Block Size: {2}, Transfer Length: {3}, Expected Sector Type: {4}, DAP: {5}, Relative Address: {6}, Sync: {7}, Headers: {8}, User Data: {9}, ECC/EDC: {10}, C2: {11}, Subchannel: {12}, Sense: {13}, Last Error: {14}) took {0} ms.", duration, lba, blockSize, transferLength, expectedSectorType, dap, relAddr, sync, headerCodes, userData, edcEcc, c2Error, subchannel, sense, LastError); return(sense); }
/// <summary>Sends the MMC READ DISC STRUCTURE command</summary> /// <returns><c>true</c> if the command failed and <paramref name="senseBuffer" /> contains the sense buffer.</returns> /// <param name="buffer">Buffer where the SCSI READ DISC STRUCTURE response will be stored</param> /// <param name="senseBuffer">Sense buffer.</param> /// <param name="mediaType">Medium type for requested disc structure</param> /// <param name="address">Medium address for requested disc structure</param> /// <param name="layerNumber">Medium layer for requested disc structure</param> /// <param name="timeout">Timeout in seconds.</param> /// <param name="format">Which disc structure are we requesting</param> /// <param name="agid">AGID used in medium copy protection</param> /// <param name="duration">Duration in milliseconds it took for the device to execute the command.</param> public bool ReadDiscStructure(out byte[] buffer, out byte[] senseBuffer, MmcDiscStructureMediaType mediaType, uint address, byte layerNumber, MmcDiscStructureFormat format, byte agid, uint timeout, out double duration) { senseBuffer = new byte[32]; byte[] cdb = new byte[12]; buffer = new byte[8]; cdb[0] = (byte)ScsiCommands.ReadDiscStructure; cdb[1] = (byte)((byte)mediaType & 0x0F); cdb[2] = (byte)((address & 0xFF000000) >> 24); cdb[3] = (byte)((address & 0xFF0000) >> 16); cdb[4] = (byte)((address & 0xFF00) >> 8); cdb[5] = (byte)(address & 0xFF); cdb[6] = layerNumber; cdb[7] = (byte)format; cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[9] = (byte)(buffer.Length & 0xFF); cdb[10] = (byte)((agid & 0x03) << 6); LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out bool sense); Error = LastError != 0; if (sense) { return(true); } ushort strctLength = (ushort)((buffer[0] << 8) + buffer[1] + 2); // WORKAROUND: Some drives return incorrect length information. As these structures are fixed length just apply known length. if (mediaType == MmcDiscStructureMediaType.Bd) { switch (format) { case MmcDiscStructureFormat.DiscInformation: buffer = new byte[4100]; break; case MmcDiscStructureFormat.BdBurstCuttingArea: buffer = new byte[68]; break; case MmcDiscStructureFormat.BdDds: buffer = new byte[strctLength < 100 ? 100 : strctLength]; break; case MmcDiscStructureFormat.CartridgeStatus: buffer = new byte[8]; break; case MmcDiscStructureFormat.BdSpareAreaInformation: buffer = new byte[16]; break; default: buffer = new byte[strctLength]; break; } } else { buffer = new byte[strctLength]; } cdb[8] = (byte)((buffer.Length & 0xFF00) >> 8); cdb[9] = (byte)(buffer.Length & 0xFF); senseBuffer = new byte[32]; LastError = SendScsiCommand(cdb, ref buffer, out senseBuffer, timeout, ScsiDirection.In, out duration, out sense); Error = LastError != 0; AaruConsole.DebugWriteLine("SCSI Device", "READ DISC STRUCTURE (Media Type: {1}, Address: {2}, Layer Number: {3}, Format: {4}, AGID: {5}, Sense: {6}, Last Error: {7}) took {0} ms.", duration, mediaType, address, layerNumber, format, agid, sense, LastError); return(sense); }
void RetryCdUserData(ExtentsULong audioExtents, uint blockSize, DumpHardwareType currentTry, ExtentsULong extents, int offsetBytes, bool readcd, int sectorsForOffset, uint subSize, MmcSubchannel supportedSubchannel, ref double totalDuration) { bool sense = true; // Sense indicator byte[] cmdBuf = null; // Data buffer double cmdDuration; // Command execution time const uint sectorSize = 2352; // Full sector size byte[] senseBuf = null; // Sense buffer PlextorSubchannel supportedPlextorSubchannel; switch (supportedSubchannel) { case MmcSubchannel.None: supportedPlextorSubchannel = PlextorSubchannel.None; break; case MmcSubchannel.Raw: supportedPlextorSubchannel = PlextorSubchannel.All; break; case MmcSubchannel.Q16: supportedPlextorSubchannel = PlextorSubchannel.Q16; break; case MmcSubchannel.Rw: supportedPlextorSubchannel = PlextorSubchannel.Pack; break; default: supportedPlextorSubchannel = PlextorSubchannel.None; break; } if (_resume.BadBlocks.Count <= 0 || _aborted || _retryPasses <= 0) { return; } int pass = 1; bool forward = true; bool runningPersistent = false; Modes.ModePage?currentModePage = null; byte[] md6; byte[] md10; if (_persistent) { Modes.ModePage_01_MMC pgMmc; sense = _dev.ModeSense6(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x01, _dev.Timeout, out _); if (sense) { sense = _dev.ModeSense10(out cmdBuf, out _, false, ScsiModeSensePageControl.Current, 0x01, _dev.Timeout, out _); if (!sense) { Modes.DecodedMode?dcMode10 = Modes.DecodeMode10(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice); if (dcMode10?.Pages != null) { foreach (Modes.ModePage modePage in dcMode10.Value.Pages) { if (modePage.Page == 0x01 && modePage.Subpage == 0x00) { currentModePage = modePage; } } } } } else { Modes.DecodedMode?dcMode6 = Modes.DecodeMode6(cmdBuf, PeripheralDeviceTypes.MultiMediaDevice); if (dcMode6?.Pages != null) { 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 = 32, 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 }; var 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); 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 senseBuf, true, false, _dev.Timeout, out _); if (sense) { sense = _dev.ModeSelect10(md10, out 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(); cdRepeatRetry: ulong[] tmpArray = _resume.BadBlocks.ToArray(); List <ulong> sectorsNotEvenPartial = new List <ulong>(); 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, " : "")); byte sectorsToReRead = 1; uint badSectorToReRead = (uint)badSector; if (_fixOffset && audioExtents.Contains(badSector) && offsetBytes != 0) { if (offsetBytes > 0) { badSectorToReRead -= (uint)sectorsForOffset; } sectorsToReRead = (byte)(sectorsForOffset + 1); } if (_supportsPlextorD8 && audioExtents.Contains(badSector)) { sense = ReadPlextorWithSubchannel(out cmdBuf, out senseBuf, badSectorToReRead, blockSize, sectorsToReRead, supportedPlextorSubchannel, out cmdDuration); totalDuration += cmdDuration; } else if (readcd) { sense = _dev.ReadCd(out cmdBuf, out senseBuf, badSectorToReRead, blockSize, sectorsToReRead, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); totalDuration += cmdDuration; } if (sense || _dev.Error) { if (!runningPersistent) { continue; } FixedSense?decSense = Sense.DecodeFixed(senseBuf); // MEDIUM ERROR, retry with ignore error below if (decSense.HasValue && decSense.Value.ASC == 0x11) { if (!sectorsNotEvenPartial.Contains(badSector)) { sectorsNotEvenPartial.Add(badSector); } } } // Because one block has been partially used to fix the offset if (_fixOffset && audioExtents.Contains(badSector) && offsetBytes != 0) { uint blocksToRead = sectorsToReRead; FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead, subSize, ref cmdBuf, blockSize, false); } if (!sense && !_dev.Error) { _resume.BadBlocks.Remove(badSector); extents.Add(badSector); UpdateStatus?.Invoke($"Correctly retried sector {badSector} in pass {pass}."); _dumpLog.WriteLine("Correctly retried sector {0} in pass {1}.", badSector, pass); sectorsNotEvenPartial.Remove(badSector); } if (supportedSubchannel != MmcSubchannel.None) { byte[] data = new byte[sectorSize]; byte[] sub = new byte[subSize]; Array.Copy(cmdBuf, 0, data, 0, sectorSize); Array.Copy(cmdBuf, sectorSize, sub, 0, subSize); _outputPlugin.WriteSectorLong(data, badSector); _outputPlugin.WriteSectorTag(sub, badSector, SectorTagType.CdSectorSubchannel); } else { _outputPlugin.WriteSectorLong(cmdBuf, badSector); } } if (pass < _retryPasses && !_aborted && _resume.BadBlocks.Count > 0) { pass++; forward = !forward; _resume.BadBlocks.Sort(); _resume.BadBlocks.Reverse(); goto cdRepeatRetry; } EndProgress?.Invoke(); // TODO: Enable when underlying images support lead-outs /* * RetryCdLeadOuts(blocks, blockSize, ref currentSpeed, currentTry, extents, ibgLog, ref imageWriteDuration, * leadOutExtents, ref maxSpeed, mhddLog, ref minSpeed, read6, read10, read12, read16, readcd, * supportedSubchannel, subSize, ref totalDuration); */ // Try to ignore read errors, on some drives this allows to recover partial even if damaged data if (_persistent && sectorsNotEvenPartial.Count > 0) { var pgMmc = new Modes.ModePage_01_MMC { PS = false, ReadRetryCount = 255, Parameter = 0x01 }; var 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 (ignore error correction)."); 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) { runningPersistent = true; InitProgress?.Invoke(); foreach (ulong badSector in sectorsNotEvenPartial) { if (_aborted) { currentTry.Extents = ExtentsConverter.ToMetadata(extents); _dumpLog.WriteLine("Aborted!"); break; } PulseProgress?.Invoke($"Trying to get partial data for sector {badSector}"); if (readcd) { sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)badSector, blockSize, 1, MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration); totalDuration += cmdDuration; } if (sense || _dev.Error) { continue; } _dumpLog.WriteLine("Got partial data for sector {0} in pass {1}.", badSector, pass); if (supportedSubchannel != MmcSubchannel.None) { byte[] data = new byte[sectorSize]; byte[] sub = new byte[subSize]; Array.Copy(cmdBuf, 0, data, 0, sectorSize); Array.Copy(cmdBuf, sectorSize, sub, 0, subSize); _outputPlugin.WriteSectorLong(data, badSector); _outputPlugin.WriteSectorTag(sub, badSector, SectorTagType.CdSectorSubchannel); } else { _outputPlugin.WriteSectorLong(cmdBuf, badSector); } } EndProgress?.Invoke(); } } if (runningPersistent && currentModePage.HasValue) { var 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 _); } } EndProgress?.Invoke(); }
static void Park(string devPath, Device dev) { start: System.Console.Clear(); bool sense = dev.CertancePark(out byte[] senseBuffer, dev.Timeout, out double duration); menu: AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Sending PARK to the device:"); AaruConsole.WriteLine("Command took {0} ms.", duration); AaruConsole.WriteLine("Sense is {0}.", sense); AaruConsole.WriteLine("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null"); AaruConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer)); AaruConsole.WriteLine("PARK decoded sense:"); AaruConsole.Write("{0}", Sense.PrettifySense(senseBuffer)); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Print sense buffer."); AaruConsole.WriteLine("2.- Send command again."); AaruConsole.WriteLine("0.- Return to Certance vendor commands menu."); AaruConsole.Write("Choose: "); string strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out int item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to Certance vendor commands menu..."); return; case 1: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("PARK sense:"); if (senseBuffer != null) { PrintHex.PrintHexArray(senseBuffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 2: goto start; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
public static void PrintImageInfo(IMediaImage imageFormat) { AaruConsole.WriteLine("Image information:"); if (!string.IsNullOrWhiteSpace(imageFormat.Info.Version)) { AaruConsole.WriteLine("Format: {0} version {1}", imageFormat.Format, imageFormat.Info.Version); } else { AaruConsole.WriteLine("Format: {0}", imageFormat.Format); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.Application) && !string.IsNullOrWhiteSpace(imageFormat.Info.ApplicationVersion)) { AaruConsole.WriteLine("Was created with {0} version {1}", imageFormat.Info.Application, imageFormat.Info.ApplicationVersion); } else if (!string.IsNullOrWhiteSpace(imageFormat.Info.Application)) { AaruConsole.WriteLine("Was created with {0}", imageFormat.Info.Application); } AaruConsole.WriteLine("Image without headers is {0} bytes long", imageFormat.Info.ImageSize); AaruConsole. WriteLine("Contains a media of {0} sectors with a maximum sector size of {1} bytes (if all sectors are of the same size this would be {2} bytes)", imageFormat.Info.Sectors, imageFormat.Info.SectorSize, imageFormat.Info.Sectors * imageFormat.Info.SectorSize); if (!string.IsNullOrWhiteSpace(imageFormat.Info.Creator)) { AaruConsole.WriteLine("Created by: {0}", imageFormat.Info.Creator); } if (imageFormat.Info.CreationTime != DateTime.MinValue) { AaruConsole.WriteLine("Created on {0}", imageFormat.Info.CreationTime); } if (imageFormat.Info.LastModificationTime != DateTime.MinValue) { AaruConsole.WriteLine("Last modified on {0}", imageFormat.Info.LastModificationTime); } AaruConsole.WriteLine("Contains a media of type {0} and XML type {1}", imageFormat.Info.MediaType, imageFormat.Info.XmlMediaType); AaruConsole.WriteLine("{0} partitions", imageFormat.Info.HasPartitions ? "Has" : "Doesn't have"); AaruConsole.WriteLine("{0} sessions", imageFormat.Info.HasSessions ? "Has" : "Doesn't have"); if (!string.IsNullOrWhiteSpace(imageFormat.Info.Comments)) { AaruConsole.WriteLine("Comments: {0}", imageFormat.Info.Comments); } if (imageFormat.Info.MediaSequence != 0 && imageFormat.Info.LastMediaSequence != 0) { AaruConsole.WriteLine("Media is number {0} on a set of {1} medias", imageFormat.Info.MediaSequence, imageFormat.Info.LastMediaSequence); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.MediaTitle)) { AaruConsole.WriteLine("Media title: {0}", imageFormat.Info.MediaTitle); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.MediaManufacturer)) { AaruConsole.WriteLine("Media manufacturer: {0}", imageFormat.Info.MediaManufacturer); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.MediaModel)) { AaruConsole.WriteLine("Media model: {0}", imageFormat.Info.MediaModel); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.MediaSerialNumber)) { AaruConsole.WriteLine("Media serial number: {0}", imageFormat.Info.MediaSerialNumber); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.MediaBarcode)) { AaruConsole.WriteLine("Media barcode: {0}", imageFormat.Info.MediaBarcode); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.MediaPartNumber)) { AaruConsole.WriteLine("Media part number: {0}", imageFormat.Info.MediaPartNumber); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.DriveManufacturer)) { AaruConsole.WriteLine("Drive manufacturer: {0}", imageFormat.Info.DriveManufacturer); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.DriveModel)) { AaruConsole.WriteLine("Drive model: {0}", imageFormat.Info.DriveModel); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.DriveSerialNumber)) { AaruConsole.WriteLine("Drive serial number: {0}", imageFormat.Info.DriveSerialNumber); } if (!string.IsNullOrWhiteSpace(imageFormat.Info.DriveFirmwareRevision)) { AaruConsole.WriteLine("Drive firmware info: {0}", imageFormat.Info.DriveFirmwareRevision); } if (imageFormat.Info.Cylinders > 0 && imageFormat.Info.Heads > 0 && imageFormat.Info.SectorsPerTrack > 0 && imageFormat.Info.XmlMediaType != XmlMediaType.OpticalDisc && (!(imageFormat is ITapeImage tapeImage) || !tapeImage.IsTape)) { AaruConsole.WriteLine("Media geometry: {0} cylinders, {1} heads, {2} sectors per track", imageFormat.Info.Cylinders, imageFormat.Info.Heads, imageFormat.Info.SectorsPerTrack); } if (imageFormat.Info.ReadableMediaTags != null && imageFormat.Info.ReadableMediaTags.Count > 0) { AaruConsole.WriteLine("Contains {0} readable media tags:", imageFormat.Info.ReadableMediaTags.Count); foreach (MediaTagType tag in imageFormat.Info.ReadableMediaTags.OrderBy(t => t)) { AaruConsole.Write("{0} ", tag); } AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableSectorTags != null && imageFormat.Info.ReadableSectorTags.Count > 0) { AaruConsole.WriteLine("Contains {0} readable sector tags:", imageFormat.Info.ReadableSectorTags.Count); foreach (SectorTagType tag in imageFormat.Info.ReadableSectorTags.OrderBy(t => t)) { AaruConsole.Write("{0} ", tag); } AaruConsole.WriteLine(); } AaruConsole.WriteLine(); PeripheralDeviceTypes scsiDeviceType = PeripheralDeviceTypes.DirectAccess; byte[] scsiVendorId = null; if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SCSI_INQUIRY) == true) { byte[] inquiry = imageFormat.ReadDiskTag(MediaTagType.SCSI_INQUIRY); scsiDeviceType = (PeripheralDeviceTypes)(inquiry[0] & 0x1F); if (inquiry.Length >= 16) { scsiVendorId = new byte[8]; Array.Copy(inquiry, 8, scsiVendorId, 0, 8); } AaruConsole.WriteLine("SCSI INQUIRY contained in image:"); AaruConsole.Write("{0}", Inquiry.Prettify(inquiry)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.ATA_IDENTIFY) == true) { byte[] identify = imageFormat.ReadDiskTag(MediaTagType.ATA_IDENTIFY); AaruConsole.WriteLine("ATA IDENTIFY contained in image:"); AaruConsole.Write("{0}", Identify.Prettify(identify)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.ATAPI_IDENTIFY) == true) { byte[] identify = imageFormat.ReadDiskTag(MediaTagType.ATAPI_IDENTIFY); AaruConsole.WriteLine("ATAPI IDENTIFY contained in image:"); AaruConsole.Write("{0}", Identify.Prettify(identify)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SCSI_MODESENSE_10) == true) { byte[] modeSense10 = imageFormat.ReadDiskTag(MediaTagType.SCSI_MODESENSE_10); Modes.DecodedMode?decMode = Modes.DecodeMode10(modeSense10, scsiDeviceType); if (decMode.HasValue) { AaruConsole.WriteLine("SCSI MODE SENSE (10) contained in image:"); PrintScsiModePages.Print(decMode.Value, scsiDeviceType, scsiVendorId); AaruConsole.WriteLine(); } } else if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SCSI_MODESENSE_6) == true) { byte[] modeSense6 = imageFormat.ReadDiskTag(MediaTagType.SCSI_MODESENSE_6); Modes.DecodedMode?decMode = Modes.DecodeMode6(modeSense6, scsiDeviceType); if (decMode.HasValue) { AaruConsole.WriteLine("SCSI MODE SENSE (6) contained in image:"); PrintScsiModePages.Print(decMode.Value, scsiDeviceType, scsiVendorId); AaruConsole.WriteLine(); } } else if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SCSI_MODEPAGE_2A) == true) { byte[] mode2A = imageFormat.ReadDiskTag(MediaTagType.SCSI_MODEPAGE_2A); AaruConsole.Write("{0}", Modes.PrettifyModePage_2A(mode2A)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_FullTOC) == true) { byte[] toc = imageFormat.ReadDiskTag(MediaTagType.CD_FullTOC); if (toc.Length > 0) { ushort dataLen = Swapping.Swap(BitConverter.ToUInt16(toc, 0)); if (dataLen + 2 != toc.Length) { byte[] tmp = new byte[toc.Length + 2]; Array.Copy(toc, 0, tmp, 2, toc.Length); tmp[0] = (byte)((toc.Length & 0xFF00) >> 8); tmp[1] = (byte)(toc.Length & 0xFF); toc = tmp; } AaruConsole.WriteLine("CompactDisc Table of Contents contained in image:"); AaruConsole.Write("{0}", FullTOC.Prettify(toc)); AaruConsole.WriteLine(); } } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_PMA) == true) { byte[] pma = imageFormat.ReadDiskTag(MediaTagType.CD_PMA); if (pma.Length > 0) { ushort dataLen = Swapping.Swap(BitConverter.ToUInt16(pma, 0)); if (dataLen + 2 != pma.Length) { byte[] tmp = new byte[pma.Length + 2]; Array.Copy(pma, 0, tmp, 2, pma.Length); tmp[0] = (byte)((pma.Length & 0xFF00) >> 8); tmp[1] = (byte)(pma.Length & 0xFF); pma = tmp; } AaruConsole.WriteLine("CompactDisc Power Management Area contained in image:"); AaruConsole.Write("{0}", PMA.Prettify(pma)); AaruConsole.WriteLine(); } } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_ATIP) == true) { byte[] atip = imageFormat.ReadDiskTag(MediaTagType.CD_ATIP); uint dataLen = Swapping.Swap(BitConverter.ToUInt32(atip, 0)); if (dataLen + 4 != atip.Length) { byte[] tmp = new byte[atip.Length + 4]; Array.Copy(atip, 0, tmp, 4, atip.Length); tmp[0] = (byte)((atip.Length & 0xFF000000) >> 24); tmp[1] = (byte)((atip.Length & 0xFF0000) >> 16); tmp[2] = (byte)((atip.Length & 0xFF00) >> 8); tmp[3] = (byte)(atip.Length & 0xFF); atip = tmp; } AaruConsole.WriteLine("CompactDisc Absolute Time In Pregroove (ATIP) contained in image:"); AaruConsole.Write("{0}", ATIP.Prettify(atip)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_TEXT) == true) { byte[] cdtext = imageFormat.ReadDiskTag(MediaTagType.CD_TEXT); uint dataLen = Swapping.Swap(BitConverter.ToUInt32(cdtext, 0)); if (dataLen + 4 != cdtext.Length) { byte[] tmp = new byte[cdtext.Length + 4]; Array.Copy(cdtext, 0, tmp, 4, cdtext.Length); tmp[0] = (byte)((cdtext.Length & 0xFF000000) >> 24); tmp[1] = (byte)((cdtext.Length & 0xFF0000) >> 16); tmp[2] = (byte)((cdtext.Length & 0xFF00) >> 8); tmp[3] = (byte)(cdtext.Length & 0xFF); cdtext = tmp; } AaruConsole.WriteLine("CompactDisc Lead-in's CD-Text contained in image:"); AaruConsole.Write("{0}", CDTextOnLeadIn.Prettify(cdtext)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.CD_MCN) == true) { byte[] mcn = imageFormat.ReadDiskTag(MediaTagType.CD_MCN); AaruConsole.WriteLine("CompactDisc Media Catalogue Number contained in image: {0}", Encoding.UTF8.GetString(mcn)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVD_PFI) == true) { byte[] pfi = imageFormat.ReadDiskTag(MediaTagType.DVD_PFI); AaruConsole.WriteLine("DVD Physical Format Information contained in image:"); AaruConsole.Write("{0}", PFI.Prettify(pfi)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDRAM_DDS) == true) { byte[] dds = imageFormat.ReadDiskTag(MediaTagType.DVDRAM_DDS); AaruConsole.WriteLine("DVD-RAM Disc Definition Structure contained in image:"); AaruConsole.Write("{0}", DDS.Prettify(dds)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.DVDR_PFI) == true) { byte[] pfi = imageFormat.ReadDiskTag(MediaTagType.DVDR_PFI); AaruConsole.WriteLine("DVD-R Physical Format Information contained in image:"); AaruConsole.Write("{0}", PFI.Prettify(pfi)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.BD_DI) == true) { byte[] di = imageFormat.ReadDiskTag(MediaTagType.BD_DI); AaruConsole.WriteLine("Bluray Disc Information contained in image:"); AaruConsole.Write("{0}", DI.Prettify(di)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.BD_DDS) == true) { byte[] dds = imageFormat.ReadDiskTag(MediaTagType.BD_DDS); AaruConsole.WriteLine("Bluray Disc Definition Structure contained in image:"); AaruConsole.Write("{0}", Decoders.Bluray.DDS.Prettify(dds)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.PCMCIA_CIS) == true) { byte[] cis = imageFormat.ReadDiskTag(MediaTagType.PCMCIA_CIS); AaruConsole.WriteLine("PCMCIA CIS:"); Tuple[] tuples = CIS.GetTuples(cis); if (tuples != null) { foreach (Tuple tuple in tuples) { switch (tuple.Code) { case TupleCodes.CISTPL_NULL: case TupleCodes.CISTPL_END: break; case TupleCodes.CISTPL_DEVICEGEO: case TupleCodes.CISTPL_DEVICEGEO_A: AaruConsole.WriteLine("{0}", CIS.PrettifyDeviceGeometryTuple(tuple)); break; case TupleCodes.CISTPL_MANFID: AaruConsole.WriteLine("{0}", CIS.PrettifyManufacturerIdentificationTuple(tuple)); break; case TupleCodes.CISTPL_VERS_1: AaruConsole.WriteLine("{0}", CIS.PrettifyLevel1VersionTuple(tuple)); break; case TupleCodes.CISTPL_ALTSTR: case TupleCodes.CISTPL_BAR: case TupleCodes.CISTPL_BATTERY: case TupleCodes.CISTPL_BYTEORDER: case TupleCodes.CISTPL_CFTABLE_ENTRY: case TupleCodes.CISTPL_CFTABLE_ENTRY_CB: case TupleCodes.CISTPL_CHECKSUM: case TupleCodes.CISTPL_CONFIG: case TupleCodes.CISTPL_CONFIG_CB: case TupleCodes.CISTPL_DATE: case TupleCodes.CISTPL_DEVICE: case TupleCodes.CISTPL_DEVICE_A: case TupleCodes.CISTPL_DEVICE_OA: case TupleCodes.CISTPL_DEVICE_OC: case TupleCodes.CISTPL_EXTDEVIC: case TupleCodes.CISTPL_FORMAT: case TupleCodes.CISTPL_FORMAT_A: case TupleCodes.CISTPL_FUNCE: case TupleCodes.CISTPL_FUNCID: case TupleCodes.CISTPL_GEOMETRY: case TupleCodes.CISTPL_INDIRECT: case TupleCodes.CISTPL_JEDEC_A: case TupleCodes.CISTPL_JEDEC_C: case TupleCodes.CISTPL_LINKTARGET: case TupleCodes.CISTPL_LONGLINK_A: case TupleCodes.CISTPL_LONGLINK_C: case TupleCodes.CISTPL_LONGLINK_CB: case TupleCodes.CISTPL_LONGLINK_MFC: case TupleCodes.CISTPL_NO_LINK: case TupleCodes.CISTPL_ORG: case TupleCodes.CISTPL_PWR_MGMNT: case TupleCodes.CISTPL_SPCL: case TupleCodes.CISTPL_SWIL: case TupleCodes.CISTPL_VERS_2: AaruConsole.DebugWriteLine("Device-Info command", "Found undecoded tuple ID {0}", tuple.Code); break; default: AaruConsole.DebugWriteLine("Device-Info command", "Found unknown tuple ID 0x{0:X2}", (byte)tuple.Code); break; } } } else { AaruConsole.DebugWriteLine("Device-Info command", "Could not get tuples"); } } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SD_CID) == true) { byte[] cid = imageFormat.ReadDiskTag(MediaTagType.SD_CID); AaruConsole.WriteLine("SecureDigital CID contained in image:"); AaruConsole.Write("{0}", Decoders.SecureDigital.Decoders.PrettifyCID(cid)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SD_CSD) == true) { byte[] csd = imageFormat.ReadDiskTag(MediaTagType.SD_CSD); AaruConsole.WriteLine("SecureDigital CSD contained in image:"); AaruConsole.Write("{0}", Decoders.SecureDigital.Decoders.PrettifyCSD(csd)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SD_SCR) == true) { byte[] scr = imageFormat.ReadDiskTag(MediaTagType.SD_SCR); AaruConsole.WriteLine("SecureDigital SCR contained in image:"); AaruConsole.Write("{0}", Decoders.SecureDigital.Decoders.PrettifySCR(scr)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.SD_OCR) == true) { byte[] ocr = imageFormat.ReadDiskTag(MediaTagType.SD_OCR); AaruConsole.WriteLine("SecureDigital OCR contained in image:"); AaruConsole.Write("{0}", Decoders.SecureDigital.Decoders.PrettifyOCR(ocr)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_CID) == true) { byte[] cid = imageFormat.ReadDiskTag(MediaTagType.MMC_CID); AaruConsole.WriteLine("MultiMediaCard CID contained in image:"); AaruConsole.Write("{0}", Decoders.MMC.Decoders.PrettifyCID(cid)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_CSD) == true) { byte[] csd = imageFormat.ReadDiskTag(MediaTagType.MMC_CSD); AaruConsole.WriteLine("MultiMediaCard CSD contained in image:"); AaruConsole.Write("{0}", Decoders.MMC.Decoders.PrettifyCSD(csd)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_ExtendedCSD) == true) { byte[] ecsd = imageFormat.ReadDiskTag(MediaTagType.MMC_ExtendedCSD); AaruConsole.WriteLine("MultiMediaCard ExtendedCSD contained in image:"); AaruConsole.Write("{0}", Decoders.MMC.Decoders.PrettifyExtendedCSD(ecsd)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.MMC_OCR) == true) { byte[] ocr = imageFormat.ReadDiskTag(MediaTagType.MMC_OCR); AaruConsole.WriteLine("MultiMediaCard OCR contained in image:"); AaruConsole.Write("{0}", Decoders.MMC.Decoders.PrettifyOCR(ocr)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.Xbox_PFI) == true) { byte[] xpfi = imageFormat.ReadDiskTag(MediaTagType.Xbox_PFI); AaruConsole.WriteLine("Xbox Physical Format Information contained in image:"); AaruConsole.Write("{0}", PFI.Prettify(xpfi)); AaruConsole.WriteLine(); } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.Xbox_DMI) == true) { byte[] xdmi = imageFormat.ReadDiskTag(MediaTagType.Xbox_DMI); if (DMI.IsXbox(xdmi)) { DMI.XboxDMI?xmi = DMI.DecodeXbox(xdmi); if (xmi.HasValue) { AaruConsole.WriteLine("Xbox DMI contained in image:"); AaruConsole.Write("{0}", DMI.PrettifyXbox(xmi)); AaruConsole.WriteLine(); } } if (DMI.IsXbox360(xdmi)) { DMI.Xbox360DMI?xmi = DMI.DecodeXbox360(xdmi); if (xmi.HasValue) { AaruConsole.WriteLine("Xbox 360 DMI contained in image:"); AaruConsole.Write("{0}", DMI.PrettifyXbox360(xmi)); AaruConsole.WriteLine(); } } } if (imageFormat.Info.ReadableMediaTags?.Contains(MediaTagType.Xbox_SecuritySector) == true) { byte[] toc = imageFormat.ReadDiskTag(MediaTagType.Xbox_SecuritySector); AaruConsole.WriteLine("Xbox Security Sectors contained in image:"); AaruConsole.Write("{0}", SS.Prettify(toc)); AaruConsole.WriteLine(); } if (imageFormat is IOpticalMediaImage opticalImage) { try { if (opticalImage.Sessions != null && opticalImage.Sessions.Count > 0) { AaruConsole.WriteLine("Image sessions:"); AaruConsole.WriteLine("{0,-9}{1,-13}{2,-12}{3,-12}{4,-12}", "Session", "First track", "Last track", "Start", "End"); AaruConsole.WriteLine("========================================================="); foreach (Session session in opticalImage.Sessions) { AaruConsole.WriteLine("{0,-9}{1,-13}{2,-12}{3,-12}{4,-12}", session.SessionSequence, session.StartTrack, session.EndTrack, session.StartSector, session.EndSector); } AaruConsole.WriteLine(); } } catch { // ignored } try { if (opticalImage.Tracks != null && opticalImage.Tracks.Count > 0) { AaruConsole.WriteLine("Image tracks:"); AaruConsole.WriteLine("{0,-7}{1,-17}{2,-6}{3,-8}{4,-12}{5,-8}{6,-12}{7,-12}", "Track", "Type", "Bps", "Raw bps", "Subchannel", "Pregap", "Start", "End"); AaruConsole. WriteLine("================================================================================="); foreach (Track track in opticalImage.Tracks) { AaruConsole.WriteLine("{0,-7}{1,-17}{2,-6}{3,-8}{4,-12}{5,-8}{6,-12}{7,-12}", track.TrackSequence, track.TrackType, track.TrackBytesPerSector, track.TrackRawBytesPerSector, track.TrackSubchannelType, track.TrackPregap, track.TrackStartSector, track.TrackEndSector); } AaruConsole.WriteLine(); AaruConsole.WriteLine("Track indexes:"); AaruConsole.WriteLine("{0,-7}{1,-7}{2,-12}", "Track", "Index", "Start"); AaruConsole.WriteLine("======================="); foreach (Track track in opticalImage.Tracks) { foreach (KeyValuePair <ushort, int> index in track.Indexes) { AaruConsole.WriteLine("{0,-7}{1,-7}{2,-12}", track.TrackSequence, index.Key, index.Value); } } } } catch { // ignored } finally { AaruConsole.WriteLine(); } } if (imageFormat.DumpHardware == null) { return; } int manufacturerLen = MANUFACTURER_STRING.Length; int modelLen = MODEL_STRING.Length; int serialLen = SERIAL_STRING.Length; int softwareLen = SOFTWARE_STRING.Length; int versionLen = VERSION_STRING.Length; int osLen = OS_STRING.Length; int sectorLen = START_STRING.Length; foreach (DumpHardwareType dump in imageFormat.DumpHardware) { if (dump.Manufacturer?.Length > manufacturerLen) { manufacturerLen = dump.Manufacturer.Length; } if (dump.Model?.Length > modelLen) { modelLen = dump.Model.Length; } if (dump.Serial?.Length > serialLen) { serialLen = dump.Serial.Length; } if (dump.Software?.Name?.Length > softwareLen) { softwareLen = dump.Software.Name.Length; } if (dump.Software?.Version?.Length > versionLen) { versionLen = dump.Software.Version.Length; } if (dump.Software?.OperatingSystem?.Length > osLen) { osLen = dump.Software.OperatingSystem.Length; } foreach (ExtentType extent in dump.Extents) { if ($"{extent.Start}".Length > sectorLen) { sectorLen = $"{extent.Start}".Length; } if ($"{extent.End}".Length > sectorLen) { sectorLen = $"{extent.End}".Length; } } } manufacturerLen += 2; modelLen += 2; serialLen += 2; softwareLen += 2; versionLen += 2; osLen += 2; sectorLen += 2; sectorLen += 2; char[] separator = new char[manufacturerLen + modelLen + serialLen + softwareLen + versionLen + osLen + sectorLen + sectorLen]; for (int i = 0; i < separator.Length; i++) { separator[i] = '='; } string format = $"{{0,-{manufacturerLen}}}{{1,-{modelLen}}}{{2,-{serialLen}}}{{3,-{softwareLen}}}{{4,-{versionLen}}}{{5,-{osLen}}}{{6,-{sectorLen}}}{{7,-{sectorLen}}}"; AaruConsole.WriteLine("Dump hardware information:"); AaruConsole.WriteLine(format, MANUFACTURER_STRING, MODEL_STRING, SERIAL_STRING, SOFTWARE_STRING, VERSION_STRING, OS_STRING, START_STRING, END_STRING); AaruConsole.WriteLine(new string(separator)); foreach (DumpHardwareType dump in imageFormat.DumpHardware) { foreach (ExtentType extent in dump.Extents) { AaruConsole.WriteLine(format, dump.Manufacturer, dump.Model, dump.Serial, dump.Software.Name, dump.Software.Version, dump.Software.OperatingSystem, extent.Start, extent.End); } } AaruConsole.WriteLine(); }
public bool Open(IFilter imageFilter) { Stream imageStream = imageFilter.GetDataForkStream(); byte[] header = new byte[512]; byte[] footer; imageStream.Seek(0, SeekOrigin.Begin); imageStream.Read(header, 0, 512); if (imageStream.Length % 2 == 0) { footer = new byte[512]; imageStream.Seek(-512, SeekOrigin.End); imageStream.Read(footer, 0, 512); } else { footer = new byte[511]; imageStream.Seek(-511, SeekOrigin.End); imageStream.Read(footer, 0, 511); } uint headerChecksum = BigEndianBitConverter.ToUInt32(header, 0x40); uint footerChecksum = BigEndianBitConverter.ToUInt32(footer, 0x40); ulong headerCookie = BigEndianBitConverter.ToUInt64(header, 0); ulong footerCookie = BigEndianBitConverter.ToUInt64(footer, 0); header[0x40] = 0; header[0x41] = 0; header[0x42] = 0; header[0x43] = 0; footer[0x40] = 0; footer[0x41] = 0; footer[0x42] = 0; footer[0x43] = 0; uint headerCalculatedChecksum = VhdChecksum(header); uint footerCalculatedChecksum = VhdChecksum(footer); AaruConsole.DebugWriteLine("VirtualPC plugin", "Header checksum = 0x{0:X8}, calculated = 0x{1:X8}", headerChecksum, headerCalculatedChecksum); AaruConsole.DebugWriteLine("VirtualPC plugin", "Header checksum = 0x{0:X8}, calculated = 0x{1:X8}", footerChecksum, footerCalculatedChecksum); byte[] usableHeader; uint usableChecksum; if (headerCookie == IMAGE_COOKIE && headerChecksum == headerCalculatedChecksum) { usableHeader = header; usableChecksum = headerChecksum; } else if (footerCookie == IMAGE_COOKIE && footerChecksum == footerCalculatedChecksum) { usableHeader = footer; usableChecksum = footerChecksum; } else { throw new ImageNotSupportedException("(VirtualPC plugin): Both header and footer are corrupt, image cannot be opened."); } _thisFooter = new HardDiskFooter { Cookie = BigEndianBitConverter.ToUInt64(usableHeader, 0x00), Features = BigEndianBitConverter.ToUInt32(usableHeader, 0x08), Version = BigEndianBitConverter.ToUInt32(usableHeader, 0x0C), Offset = BigEndianBitConverter.ToUInt64(usableHeader, 0x10), Timestamp = BigEndianBitConverter.ToUInt32(usableHeader, 0x18), CreatorApplication = BigEndianBitConverter.ToUInt32(usableHeader, 0x1C), CreatorVersion = BigEndianBitConverter.ToUInt32(usableHeader, 0x20), CreatorHostOs = BigEndianBitConverter.ToUInt32(usableHeader, 0x24), OriginalSize = BigEndianBitConverter.ToUInt64(usableHeader, 0x28), CurrentSize = BigEndianBitConverter.ToUInt64(usableHeader, 0x30), DiskGeometry = BigEndianBitConverter.ToUInt32(usableHeader, 0x38), DiskType = BigEndianBitConverter.ToUInt32(usableHeader, 0x3C), Checksum = usableChecksum, UniqueId = BigEndianBitConverter.ToGuid(usableHeader, 0x44), SavedState = usableHeader[0x54], Reserved = new byte[usableHeader.Length - 0x55] }; Array.Copy(usableHeader, 0x55, _thisFooter.Reserved, 0, usableHeader.Length - 0x55); _thisDateTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc); _thisDateTime = _thisDateTime.AddSeconds(_thisFooter.Timestamp); var sha1Ctx = new Sha1Context(); sha1Ctx.Update(_thisFooter.Reserved); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.cookie = 0x{0:X8}", _thisFooter.Cookie); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.features = 0x{0:X8}", _thisFooter.Features); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.version = 0x{0:X8}", _thisFooter.Version); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.offset = {0}", _thisFooter.Offset); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.timestamp = 0x{0:X8} ({1})", _thisFooter.Timestamp, _thisDateTime); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.creatorApplication = 0x{0:X8} (\"{1}\")", _thisFooter.CreatorApplication, Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(_thisFooter. CreatorApplication))); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.creatorVersion = 0x{0:X8}", _thisFooter.CreatorVersion); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.creatorHostOS = 0x{0:X8} (\"{1}\")", _thisFooter.CreatorHostOs, Encoding.ASCII.GetString(BigEndianBitConverter. GetBytes(_thisFooter.CreatorHostOs))); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.originalSize = {0}", _thisFooter.OriginalSize); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.currentSize = {0}", _thisFooter.CurrentSize); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.diskGeometry = 0x{0:X8} (C/H/S: {1}/{2}/{3})", _thisFooter.DiskGeometry, (_thisFooter.DiskGeometry & 0xFFFF0000) >> 16, (_thisFooter.DiskGeometry & 0xFF00) >> 8, _thisFooter.DiskGeometry & 0xFF); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.diskType = 0x{0:X8}", _thisFooter.DiskType); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.checksum = 0x{0:X8}", _thisFooter.Checksum); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.uniqueId = {0}", _thisFooter.UniqueId); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.savedState = 0x{0:X2}", _thisFooter.SavedState); AaruConsole.DebugWriteLine("VirtualPC plugin", "footer.reserved's SHA1 = 0x{0}", sha1Ctx.End()); if (_thisFooter.Version == VERSION1) { _imageInfo.Version = "1.0"; } else { throw new ImageNotSupportedException($"(VirtualPC plugin): Unknown image type {_thisFooter.DiskType} found. Please submit a bug with an example image."); } switch (_thisFooter.CreatorApplication) { case CREATOR_QEMU: { _imageInfo.Application = "QEMU"; // QEMU always set same version _imageInfo.ApplicationVersion = "Unknown"; break; } case CREATOR_VIRTUAL_BOX: { _imageInfo.ApplicationVersion = $"{(_thisFooter.CreatorVersion & 0xFFFF0000) >> 16}.{_thisFooter.CreatorVersion & 0x0000FFFF:D2}"; switch (_thisFooter.CreatorHostOs) { case CREATOR_MACINTOSH: case CREATOR_MACINTOSH_OLD: _imageInfo.Application = "VirtualBox for Mac"; break; case CREATOR_WINDOWS: // VirtualBox uses Windows creator for any other OS _imageInfo.Application = "VirtualBox"; break; default: _imageInfo.Application = $"VirtualBox for unknown OS \"{Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(_thisFooter.CreatorHostOs))}\""; break; } break; } case CREATOR_VIRTUAL_SERVER: { _imageInfo.Application = "Microsoft Virtual Server"; switch (_thisFooter.CreatorVersion) { case VERSION_VIRTUAL_SERVER2004: _imageInfo.ApplicationVersion = "2004"; break; default: _imageInfo.ApplicationVersion = $"Unknown version 0x{_thisFooter.CreatorVersion:X8}"; break; } break; } case CREATOR_VIRTUAL_PC: { switch (_thisFooter.CreatorHostOs) { case CREATOR_MACINTOSH: case CREATOR_MACINTOSH_OLD: switch (_thisFooter.CreatorVersion) { case VERSION_VIRTUAL_PC_MAC: _imageInfo.Application = "Connectix Virtual PC"; _imageInfo.ApplicationVersion = "5, 6 or 7"; break; default: _imageInfo.ApplicationVersion = $"Unknown version 0x{_thisFooter.CreatorVersion:X8}"; break; } break; case CREATOR_WINDOWS: switch (_thisFooter.CreatorVersion) { case VERSION_VIRTUAL_PC_MAC: _imageInfo.Application = "Connectix Virtual PC"; _imageInfo.ApplicationVersion = "5, 6 or 7"; break; case VERSION_VIRTUAL_PC2004: _imageInfo.Application = "Microsoft Virtual PC"; _imageInfo.ApplicationVersion = "2004"; break; case VERSION_VIRTUAL_PC2007: _imageInfo.Application = "Microsoft Virtual PC"; _imageInfo.ApplicationVersion = "2007"; break; default: _imageInfo.ApplicationVersion = $"Unknown version 0x{_thisFooter.CreatorVersion:X8}"; break; } break; default: _imageInfo.Application = $"Virtual PC for unknown OS \"{Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(_thisFooter.CreatorHostOs))}\""; _imageInfo.ApplicationVersion = $"Unknown version 0x{_thisFooter.CreatorVersion:X8}"; break; } break; } case CREATOR_DISCIMAGECHEF: { _imageInfo.Application = "DiscImageChef"; _imageInfo.ApplicationVersion = $"{(_thisFooter.CreatorVersion & 0xFF000000) >> 24}.{(_thisFooter.CreatorVersion & 0xFF0000) >> 16}.{(_thisFooter.CreatorVersion & 0xFF00) >> 8}.{_thisFooter.CreatorVersion & 0xFF}"; } break; case CREATOR_AARU: { _imageInfo.Application = "Aaru"; _imageInfo.ApplicationVersion = $"{(_thisFooter.CreatorVersion & 0xFF000000) >> 24}.{(_thisFooter.CreatorVersion & 0xFF0000) >> 16}.{(_thisFooter.CreatorVersion & 0xFF00) >> 8}.{_thisFooter.CreatorVersion & 0xFF}"; } break; default: { _imageInfo.Application = $"Unknown application \"{Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(_thisFooter.CreatorHostOs))}\""; _imageInfo.ApplicationVersion = $"Unknown version 0x{_thisFooter.CreatorVersion:X8}"; break; } } _thisFilter = imageFilter; _imageInfo.ImageSize = _thisFooter.CurrentSize; _imageInfo.Sectors = _thisFooter.CurrentSize / 512; _imageInfo.SectorSize = 512; _imageInfo.CreationTime = imageFilter.GetCreationTime(); _imageInfo.LastModificationTime = _thisDateTime; _imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename()); _imageInfo.Cylinders = (_thisFooter.DiskGeometry & 0xFFFF0000) >> 16; _imageInfo.Heads = (_thisFooter.DiskGeometry & 0xFF00) >> 8; _imageInfo.SectorsPerTrack = _thisFooter.DiskGeometry & 0xFF; if (_thisFooter.DiskType == TYPE_DYNAMIC || _thisFooter.DiskType == TYPE_DIFFERENCING) { imageStream.Seek((long)_thisFooter.Offset, SeekOrigin.Begin); byte[] dynamicBytes = new byte[1024]; imageStream.Read(dynamicBytes, 0, 1024); uint dynamicChecksum = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x24); dynamicBytes[0x24] = 0; dynamicBytes[0x25] = 0; dynamicBytes[0x26] = 0; dynamicBytes[0x27] = 0; uint dynamicChecksumCalculated = VhdChecksum(dynamicBytes); AaruConsole.DebugWriteLine("VirtualPC plugin", "Dynamic header checksum = 0x{0:X8}, calculated = 0x{1:X8}", dynamicChecksum, dynamicChecksumCalculated); if (dynamicChecksum != dynamicChecksumCalculated) { throw new ImageNotSupportedException("(VirtualPC plugin): Both header and footer are corrupt, image cannot be opened."); } _thisDynamic = new DynamicDiskHeader { LocatorEntries = new ParentLocatorEntry[8], Reserved2 = new byte[256] }; for (int i = 0; i < 8; i++) { _thisDynamic.LocatorEntries[i] = new ParentLocatorEntry(); } _thisDynamic.Cookie = BigEndianBitConverter.ToUInt64(dynamicBytes, 0x00); _thisDynamic.DataOffset = BigEndianBitConverter.ToUInt64(dynamicBytes, 0x08); _thisDynamic.TableOffset = BigEndianBitConverter.ToUInt64(dynamicBytes, 0x10); _thisDynamic.HeaderVersion = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x18); _thisDynamic.MaxTableEntries = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x1C); _thisDynamic.BlockSize = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x20); _thisDynamic.Checksum = dynamicChecksum; _thisDynamic.ParentId = BigEndianBitConverter.ToGuid(dynamicBytes, 0x28); _thisDynamic.ParentTimestamp = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x38); _thisDynamic.Reserved = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x3C); _thisDynamic.ParentName = Encoding.BigEndianUnicode.GetString(dynamicBytes, 0x40, 512); for (int i = 0; i < 8; i++) { _thisDynamic.LocatorEntries[i].PlatformCode = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x240 + 0x00 + (24 * i)); _thisDynamic.LocatorEntries[i].PlatformDataSpace = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x240 + 0x04 + (24 * i)); _thisDynamic.LocatorEntries[i].PlatformDataLength = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x240 + 0x08 + (24 * i)); _thisDynamic.LocatorEntries[i].Reserved = BigEndianBitConverter.ToUInt32(dynamicBytes, 0x240 + 0x0C + (24 * i)); _thisDynamic.LocatorEntries[i].PlatformDataOffset = BigEndianBitConverter.ToUInt64(dynamicBytes, 0x240 + 0x10 + (24 * i)); } Array.Copy(dynamicBytes, 0x300, _thisDynamic.Reserved2, 0, 256); _parentDateTime = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc); _parentDateTime = _parentDateTime.AddSeconds(_thisDynamic.ParentTimestamp); sha1Ctx = new Sha1Context(); sha1Ctx.Update(_thisDynamic.Reserved2); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.cookie = 0x{0:X8}", _thisDynamic.Cookie); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.dataOffset = {0}", _thisDynamic.DataOffset); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.tableOffset = {0}", _thisDynamic.TableOffset); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.headerVersion = 0x{0:X8}", _thisDynamic.HeaderVersion); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.maxTableEntries = {0}", _thisDynamic.MaxTableEntries); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.blockSize = {0}", _thisDynamic.BlockSize); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.checksum = 0x{0:X8}", _thisDynamic.Checksum); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.parentID = {0}", _thisDynamic.ParentId); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.parentTimestamp = 0x{0:X8} ({1})", _thisDynamic.ParentTimestamp, _parentDateTime); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.reserved = 0x{0:X8}", _thisDynamic.Reserved); for (int i = 0; i < 8; i++) { AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.locatorEntries[{0}].platformCode = 0x{1:X8} (\"{2}\")", i, _thisDynamic.LocatorEntries[i].PlatformCode, Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(_thisDynamic. LocatorEntries [i]. PlatformCode))); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.locatorEntries[{0}].platformDataSpace = {1}", i, _thisDynamic.LocatorEntries[i].PlatformDataSpace); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.locatorEntries[{0}].platformDataLength = {1}", i, _thisDynamic.LocatorEntries[i].PlatformDataLength); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.locatorEntries[{0}].reserved = 0x{1:X8}", i, _thisDynamic.LocatorEntries[i].Reserved); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.locatorEntries[{0}].platformDataOffset = {1}", i, _thisDynamic.LocatorEntries[i].PlatformDataOffset); } AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.parentName = \"{0}\"", _thisDynamic.ParentName); AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.reserved2's SHA1 = 0x{0}", sha1Ctx.End()); if (_thisDynamic.HeaderVersion != VERSION1) { throw new ImageNotSupportedException($"(VirtualPC plugin): Unknown image type {_thisFooter.DiskType} found. Please submit a bug with an example image."); } DateTime startTime = DateTime.UtcNow; _blockAllocationTable = new uint[_thisDynamic.MaxTableEntries]; // How many sectors uses the BAT int batSectorCount = (int)Math.Ceiling(((double)_thisDynamic.MaxTableEntries * 4) / 512); byte[] bat = new byte[_thisDynamic.MaxTableEntries * 4]; imageStream.Seek((long)_thisDynamic.TableOffset, SeekOrigin.Begin); imageStream.Read(bat, 0, batSectorCount); ReadOnlySpan <byte> span = bat; _blockAllocationTable = MemoryMarshal. Cast <byte, uint>(span).Slice(0, (int)_thisDynamic.MaxTableEntries).ToArray(); for (int i = 0; i < _blockAllocationTable.Length; i++) { _blockAllocationTable[i] = Swapping.Swap(_blockAllocationTable[i]); } DateTime endTime = DateTime.UtcNow; AaruConsole.DebugWriteLine("VirtualPC plugin", "Filling the BAT took {0} seconds", (endTime - startTime).TotalSeconds); _bitmapSize = (uint)Math.Ceiling((double)_thisDynamic.BlockSize / 512 // 1 bit per sector on the bitmap / 8 // and aligned to 512 byte boundary / 512); AaruConsole.DebugWriteLine("VirtualPC plugin", "Bitmap is {0} sectors", _bitmapSize); } _imageInfo.XmlMediaType = XmlMediaType.BlockMedia; switch (_thisFooter.DiskType) { case TYPE_FIXED: case TYPE_DYNAMIC: { // Nothing to do here, really. return(true); } case TYPE_DIFFERENCING: { _locatorEntriesData = new byte[8][]; for (int i = 0; i < 8; i++) { if (_thisDynamic.LocatorEntries[i].PlatformCode != 0x00000000) { _locatorEntriesData[i] = new byte[_thisDynamic.LocatorEntries[i].PlatformDataLength]; imageStream.Seek((long)_thisDynamic.LocatorEntries[i].PlatformDataOffset, SeekOrigin.Begin); imageStream.Read(_locatorEntriesData[i], 0, (int)_thisDynamic.LocatorEntries[i].PlatformDataLength); switch (_thisDynamic.LocatorEntries[i].PlatformCode) { case PLATFORM_CODE_WINDOWS_ABSOLUTE: case PLATFORM_CODE_WINDOWS_RELATIVE: AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.locatorEntries[{0}] = \"{1}\"", i, Encoding.ASCII.GetString(_locatorEntriesData[i])); break; case PLATFORM_CODE_WINDOWS_ABSOLUTE_U: case PLATFORM_CODE_WINDOWS_RELATIVE_U: AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.locatorEntries[{0}] = \"{1}\"", i, Encoding.BigEndianUnicode. GetString(_locatorEntriesData[i])); break; case PLATFORM_CODE_MACINTOSH_URI: AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.locatorEntries[{0}] = \"{1}\"", i, Encoding.UTF8.GetString(_locatorEntriesData[i])); break; default: AaruConsole.DebugWriteLine("VirtualPC plugin", "dynamic.locatorEntries[{0}] =", i); PrintHex.PrintHexArray(_locatorEntriesData[i], 64); break; } } } int currentLocator = 0; bool locatorFound = false; string parentPath = null; while (!locatorFound && currentLocator < 8) { switch (_thisDynamic.LocatorEntries[currentLocator].PlatformCode) { case PLATFORM_CODE_WINDOWS_ABSOLUTE: case PLATFORM_CODE_WINDOWS_RELATIVE: parentPath = Encoding.ASCII.GetString(_locatorEntriesData[currentLocator]); break; case PLATFORM_CODE_WINDOWS_ABSOLUTE_U: case PLATFORM_CODE_WINDOWS_RELATIVE_U: parentPath = Encoding.BigEndianUnicode.GetString(_locatorEntriesData[currentLocator]); break; case PLATFORM_CODE_MACINTOSH_URI: parentPath = Uri.UnescapeDataString(Encoding.UTF8.GetString(_locatorEntriesData [currentLocator])); if (parentPath.StartsWith("file://localhost", StringComparison.InvariantCulture)) { parentPath = parentPath.Remove(0, 16); } else { AaruConsole.DebugWriteLine("VirtualPC plugin", "Unsupported protocol classified found in URI parent path: \"{0}\"", parentPath); parentPath = null; } break; } if (parentPath != null) { AaruConsole.DebugWriteLine("VirtualPC plugin", "Possible parent path: \"{0}\"", parentPath); IFilter parentFilter = new FiltersList().GetFilter(Path.Combine(imageFilter.GetParentFolder(), parentPath)); if (parentFilter != null) { locatorFound = true; } if (!locatorFound) { parentPath = null; } } currentLocator++; } if (!locatorFound) { throw new FileNotFoundException("(VirtualPC plugin): Cannot find parent file for differencing disk image"); } { _parentImage = new Vhd(); IFilter parentFilter = new FiltersList().GetFilter(Path.Combine(imageFilter.GetParentFolder(), parentPath)); if (parentFilter == null) { throw new ImageNotSupportedException("(VirtualPC plugin): Cannot find parent image filter"); } /* PluginBase plugins = new PluginBase(); * plugins.RegisterAllPlugins(); * if (!plugins.ImagePluginsList.TryGetValue(Name.ToLower(), out parentImage)) * throw new SystemException("(VirtualPC plugin): Unable to open myself");*/ if (!_parentImage.Identify(parentFilter)) { throw new ImageNotSupportedException("(VirtualPC plugin): Parent image is not a Virtual PC disk image"); } if (!_parentImage.Open(parentFilter)) { throw new ImageNotSupportedException("(VirtualPC plugin): Cannot open parent disk image"); } // While specification says that parent and child disk images should contain UUID relationship // in reality it seems that old differencing disk images stored a parent UUID that, nonetheless // the parent never stored itself. So the only real way to know that images are related is // because the parent IS found and SAME SIZE. Ugly... // More funny even, tested parent images show an empty host OS, and child images a correct one. if (_parentImage.Info.Sectors != _imageInfo.Sectors) { throw new ImageNotSupportedException("(VirtualPC plugin): Parent image is of different size"); } } return(true); } case TYPE_DEPRECATED1: case TYPE_DEPRECATED2: case TYPE_DEPRECATED3: { throw new ImageNotSupportedException("(VirtualPC plugin): Deprecated image type found. Please submit a bug with an example image."); } default: { throw new ImageNotSupportedException($"(VirtualPC plugin): Unknown image type {_thisFooter.DiskType} found. Please submit a bug with an example image."); } } }
public static void Scsi(string devPath, Device dev) { while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Send a SCSI command to the device:"); AaruConsole.WriteLine("1.- Send an Adaptec vendor command to the device."); AaruConsole.WriteLine("2.- Send an Archive vendor command to the device."); AaruConsole.WriteLine("3.- Send a Certance vendor command to the device."); AaruConsole.WriteLine("4.- Send a Fujitsu vendor command to the device."); AaruConsole.WriteLine("5.- Send an HL-DT-ST vendor command to the device."); AaruConsole.WriteLine("6.- Send a Hewlett-Packard vendor command to the device."); AaruConsole.WriteLine("7.- Send a Kreon vendor command to the device."); AaruConsole.WriteLine("8.- Send a SCSI MultiMedia Command to the device."); AaruConsole.WriteLine("9.- Send a NEC vendor command to the device."); AaruConsole.WriteLine("10.- Send a Pioneer vendor command to the device."); AaruConsole.WriteLine("11.- Send a Plasmon vendor command to the device."); AaruConsole.WriteLine("12.- Send a Plextor vendor command to the device."); AaruConsole.WriteLine("13.- Send a SCSI Block Command to the device."); AaruConsole.WriteLine("14.- Send a SCSI Media Changer command to the device."); AaruConsole.WriteLine("15.- Send a SCSI Primary Command to the device."); AaruConsole.WriteLine("16.- Send a SCSI Streaming Command to the device."); AaruConsole.WriteLine("17.- Send a SyQuest vendor command to the device."); AaruConsole.WriteLine("0.- Return to command class menu."); AaruConsole.Write("Choose: "); string strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out int item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to command class menu..."); return; case 1: Adaptec.Menu(devPath, dev); continue; case 2: ArchiveCorp.Menu(devPath, dev); continue; case 3: Certance.Menu(devPath, dev); continue; case 4: Fujitsu.Menu(devPath, dev); continue; case 5: HlDtSt.Menu(devPath, dev); continue; case 6: Hp.Menu(devPath, dev); continue; case 7: Kreon.Menu(devPath, dev); continue; case 8: Mmc.Menu(devPath, dev); continue; case 9: Nec.Menu(devPath, dev); continue; case 10: Pioneer.Menu(devPath, dev); continue; case 11: Plasmon.Menu(devPath, dev); continue; case 12: Plextor.Menu(devPath, dev); continue; case 13: Sbc.Menu(devPath, dev); continue; case 14: Smc.Menu(devPath, dev); continue; case 15: Spc.Menu(devPath, dev); continue; case 16: Ssc.Menu(devPath, dev); continue; case 17: SyQuest.Menu(devPath, dev); continue; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); continue; } } }
public bool Open(IFilter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); stream.Seek(0, SeekOrigin.Begin); if (stream.Length < 512) { return(false); } byte[] qHdrB = new byte[68]; stream.Read(qHdrB, 0, 68); _qHdr = Marshal.SpanToStructureLittleEndian <QedHeader>(qHdrB); AaruConsole.DebugWriteLine("QED plugin", "qHdr.magic = 0x{0:X8}", _qHdr.magic); AaruConsole.DebugWriteLine("QED plugin", "qHdr.cluster_size = {0}", _qHdr.cluster_size); AaruConsole.DebugWriteLine("QED plugin", "qHdr.table_size = {0}", _qHdr.table_size); AaruConsole.DebugWriteLine("QED plugin", "qHdr.header_size = {0}", _qHdr.header_size); AaruConsole.DebugWriteLine("QED plugin", "qHdr.features = {0}", _qHdr.features); AaruConsole.DebugWriteLine("QED plugin", "qHdr.compat_features = {0}", _qHdr.compat_features); AaruConsole.DebugWriteLine("QED plugin", "qHdr.autoclear_features = {0}", _qHdr.autoclear_features); AaruConsole.DebugWriteLine("QED plugin", "qHdr.l1_table_offset = {0}", _qHdr.l1_table_offset); AaruConsole.DebugWriteLine("QED plugin", "qHdr.image_size = {0}", _qHdr.image_size); AaruConsole.DebugWriteLine("QED plugin", "qHdr.backing_file_offset = {0}", _qHdr.backing_file_offset); AaruConsole.DebugWriteLine("QED plugin", "qHdr.backing_file_size = {0}", _qHdr.backing_file_size); if (_qHdr.image_size <= 1) { throw new ArgumentOutOfRangeException(nameof(_qHdr.image_size), "Image size is too small"); } if (!IsPowerOfTwo(_qHdr.cluster_size)) { throw new ArgumentOutOfRangeException(nameof(_qHdr.cluster_size), "Cluster size must be a power of 2"); } if (_qHdr.cluster_size < 4096 || _qHdr.cluster_size > 67108864) { throw new ArgumentOutOfRangeException(nameof(_qHdr.cluster_size), "Cluster size must be between 4 Kbytes and 64 Mbytes"); } if (!IsPowerOfTwo(_qHdr.table_size)) { throw new ArgumentOutOfRangeException(nameof(_qHdr.table_size), "Table size must be a power of 2"); } if (_qHdr.table_size < 1 || _qHdr.table_size > 16) { throw new ArgumentOutOfRangeException(nameof(_qHdr.table_size), "Table size must be between 1 and 16 clusters"); } if ((_qHdr.features & QED_FEATURE_MASK) > 0) { throw new ArgumentOutOfRangeException(nameof(_qHdr.features), $"Image uses unknown incompatible features {_qHdr.features & QED_FEATURE_MASK:X}"); } if ((_qHdr.features & QED_FEATURE_BACKING_FILE) == QED_FEATURE_BACKING_FILE) { throw new NotImplementedException("Differencing images not yet supported"); } _clusterSectors = _qHdr.cluster_size / 512; _tableSize = (_qHdr.cluster_size * _qHdr.table_size) / 8; AaruConsole.DebugWriteLine("QED plugin", "qHdr.clusterSectors = {0}", _clusterSectors); AaruConsole.DebugWriteLine("QED plugin", "qHdr.tableSize = {0}", _tableSize); byte[] l1TableB = new byte[_tableSize * 8]; stream.Seek((long)_qHdr.l1_table_offset, SeekOrigin.Begin); stream.Read(l1TableB, 0, (int)_tableSize * 8); AaruConsole.DebugWriteLine("QED plugin", "Reading L1 table"); _l1Table = MemoryMarshal.Cast <byte, ulong>(l1TableB).ToArray(); _l1Mask = 0; int c = 0; _clusterBits = Ctz32(_qHdr.cluster_size); _l2Mask = (_tableSize - 1) << _clusterBits; _l1Shift = _clusterBits + Ctz32(_tableSize); for (int i = 0; i < 64; i++) { _l1Mask <<= 1; if (c >= 64 - _l1Shift) { continue; } _l1Mask += 1; c++; } _sectorMask = 0; for (int i = 0; i < _clusterBits; i++) { _sectorMask = (_sectorMask << 1) + 1; } AaruConsole.DebugWriteLine("QED plugin", "qHdr.clusterBits = {0}", _clusterBits); AaruConsole.DebugWriteLine("QED plugin", "qHdr.l1Mask = {0:X}", _l1Mask); AaruConsole.DebugWriteLine("QED plugin", "qHdr.l1Shift = {0}", _l1Shift); AaruConsole.DebugWriteLine("QED plugin", "qHdr.l2Mask = {0:X}", _l2Mask); AaruConsole.DebugWriteLine("QED plugin", "qHdr.sectorMask = {0:X}", _sectorMask); _maxL2TableCache = MAX_CACHE_SIZE / _tableSize; _maxClusterCache = MAX_CACHE_SIZE / _qHdr.cluster_size; _imageStream = stream; _sectorCache = new Dictionary <ulong, byte[]>(); _l2TableCache = new Dictionary <ulong, ulong[]>(); _clusterCache = new Dictionary <ulong, byte[]>(); _imageInfo.CreationTime = imageFilter.GetCreationTime(); _imageInfo.LastModificationTime = imageFilter.GetLastWriteTime(); _imageInfo.MediaTitle = Path.GetFileNameWithoutExtension(imageFilter.GetFilename()); _imageInfo.Sectors = _qHdr.image_size / 512; _imageInfo.SectorSize = 512; _imageInfo.XmlMediaType = XmlMediaType.BlockMedia; _imageInfo.MediaType = MediaType.GENERIC_HDD; _imageInfo.ImageSize = _qHdr.image_size; _imageInfo.Cylinders = (uint)(_imageInfo.Sectors / 16 / 63); _imageInfo.Heads = 16; _imageInfo.SectorsPerTrack = 63; return(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); }
internal static void Menu(string devPath, Device dev) { while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Send a CHS ATA command to the device:"); AaruConsole.WriteLine("1.- Send IDENTIFY DEVICE command."); AaruConsole.WriteLine("2.- Send READ DMA command."); AaruConsole.WriteLine("3.- Send READ DMA WITH RETRIES command."); AaruConsole.WriteLine("4.- Send READ LONG command."); AaruConsole.WriteLine("5.- Send READ LONG WITH RETRIES command."); AaruConsole.WriteLine("6.- Send READ MULTIPLE command."); AaruConsole.WriteLine("7.- Send READ SECTORS command."); AaruConsole.WriteLine("8.- Send READ SECTORS WITH RETRIES command."); AaruConsole.WriteLine("9.- Send SEEK command."); AaruConsole.WriteLine("10.- Send SET FEATURES command."); AaruConsole.WriteLine("0.- Return to ATA commands menu."); AaruConsole.Write("Choose: "); string strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out int item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to ATA commands menu..."); return; case 1: Identify(devPath, dev); continue; case 2: ReadDma(devPath, dev, false); continue; case 3: ReadDma(devPath, dev, true); continue; case 4: ReadLong(devPath, dev, false); continue; case 5: ReadLong(devPath, dev, true); continue; case 6: ReadMultiple(devPath, dev); continue; case 7: ReadSectors(devPath, dev, false); continue; case 8: ReadSectors(devPath, dev, true); continue; case 9: Seek(devPath, dev); continue; case 10: SetFeatures(devPath, dev); continue; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); continue; } } }
static void ExecuteOfflineImmediate(string devPath, Device dev) { byte subcommand = 0; string strDev; int item; parameters: while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Parameters for EXECUTE OFF-LINE IMMEDIATE command:"); AaruConsole.WriteLine("Subcommand: {0}", subcommand); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Change parameters."); AaruConsole.WriteLine("2.- Send command with these parameters."); AaruConsole.WriteLine("0.- Return to S.M.A.R.T. commands menu."); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to S.M.A.R.T. commands menu..."); return; case 1: AaruConsole.Write("Subcommand?: "); strDev = System.Console.ReadLine(); if (!byte.TryParse(strDev, out subcommand)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); subcommand = 0; System.Console.ReadKey(); } break; case 2: goto start; } } start: System.Console.Clear(); bool sense = dev.SmartExecuteOffLineImmediate(out AtaErrorRegistersLba28 errorRegisters, subcommand, dev.Timeout, out double duration); menu: AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Sending EXECUTE OFF-LINE IMMEDIATE to the device:"); AaruConsole.WriteLine("Command took {0} ms.", duration); AaruConsole.WriteLine("Sense is {0}.", sense); AaruConsole.WriteLine("EXECUTE OFF-LINE IMMEDIATE status registers:"); AaruConsole.Write("{0}", MainClass.DecodeAtaRegisters(errorRegisters)); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Send command again."); AaruConsole.WriteLine("2.- Change parameters."); AaruConsole.WriteLine("0.- Return to Media Card Pass Through commands menu."); AaruConsole.Write("Choose: "); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to S.M.A.R.T. commands menu..."); return; case 1: goto start; case 2: goto parameters; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
static void Seek(string devPath, Device dev) { ushort cylinder = 0; byte head = 0; byte sector = 1; string strDev; int item; parameters: while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Parameters for SEEK command:"); AaruConsole.WriteLine("Cylinder: {0}", cylinder); AaruConsole.WriteLine("Head: {0}", head); AaruConsole.WriteLine("Sector: {0}", sector); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Change parameters."); AaruConsole.WriteLine("2.- Send command with these parameters."); AaruConsole.WriteLine("0.- Return to CHS ATA commands menu."); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to CHS ATA commands menu..."); return; case 1: AaruConsole.Write("What cylinder?: "); strDev = System.Console.ReadLine(); if (!ushort.TryParse(strDev, out cylinder)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); cylinder = 0; System.Console.ReadKey(); continue; } AaruConsole.Write("What head?: "); strDev = System.Console.ReadLine(); if (!byte.TryParse(strDev, out head)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); head = 0; System.Console.ReadKey(); continue; } if (head > 15) { AaruConsole.WriteLine("Head cannot be bigger than 15. Setting it to 15..."); head = 15; } AaruConsole.Write("What sector?: "); strDev = System.Console.ReadLine(); if (!byte.TryParse(strDev, out sector)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); sector = 0; System.Console.ReadKey(); } break; case 2: goto start; } } start: System.Console.Clear(); bool sense = dev.Seek(out AtaErrorRegistersChs errorRegisters, cylinder, head, sector, dev.Timeout, out double duration); menu: AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Sending SEEK to the device:"); AaruConsole.WriteLine("Command took {0} ms.", duration); AaruConsole.WriteLine("Sense is {0}.", sense); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Decode error registers."); AaruConsole.WriteLine("2.- Send command again."); AaruConsole.WriteLine("3.- Change parameters."); AaruConsole.WriteLine("0.- Return to CHS ATA commands menu."); AaruConsole.Write("Choose: "); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to CHS ATA commands menu..."); return; case 1: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("SEEK status registers:"); AaruConsole.Write("{0}", MainClass.DecodeAtaRegisters(errorRegisters)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 2: goto start; case 3: goto parameters; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
internal static void Menu(string devPath, Device dev) { while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Send a S.M.A.R.T. command to the device:"); AaruConsole.WriteLine("1.- Send DISABLE ATTRIBUTE AUTOSAVE command."); AaruConsole.WriteLine("2.- Send DISABLE OPERATIONS command."); AaruConsole.WriteLine("3.- Send ENABLE ATTRIBUTE AUTOSAVE command."); AaruConsole.WriteLine("4.- Send ENABLE OPERATIONS command."); AaruConsole.WriteLine("5.- Send EXECUTE OFF-LINE IMMEDIATE command."); AaruConsole.WriteLine("6.- Send READ DATA command."); AaruConsole.WriteLine("7.- Send READ LOG command."); AaruConsole.WriteLine("8.- Send RETURN STATUS command."); AaruConsole.WriteLine("0.- Return to ATA commands menu."); AaruConsole.Write("Choose: "); string strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out int item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to ATA commands menu..."); return; case 1: DisableAttributeAutosave(devPath, dev); continue; case 2: DisableOperations(devPath, dev); continue; case 3: EnableAttributeAutosave(devPath, dev); continue; case 4: EnableOperations(devPath, dev); continue; case 5: ExecuteOfflineImmediate(devPath, dev); continue; case 6: ReadData(devPath, dev); continue; case 7: ReadLog(devPath, dev); continue; case 8: ReturnStatus(devPath, dev); continue; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); continue; } } }
bool ScsiReadBlocks(out byte[] buffer, ulong block, uint count, out double duration, out bool recoveredError, out bool blankCheck) { bool sense; byte[] senseBuf; buffer = null; duration = 0; recoveredError = false; blankCheck = false; if (CanReadRaw) { if (_readLong16) { sense = _dev.ReadLong16(out buffer, out senseBuf, false, block, LongBlockSize, _timeout, out duration); } else if (_readLong10) { sense = _dev.ReadLong10(out buffer, out senseBuf, false, false, (uint)block, (ushort)LongBlockSize, _timeout, out duration); } else if (_syqReadLong10) { sense = _dev.SyQuestReadLong10(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout, out duration); } else if (_syqReadLong6) { sense = _dev.SyQuestReadLong6(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout, out duration); } else if (_hldtstReadRaw) { sense = _dev.HlDtStReadRawDvd(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout, out duration); } else if (_plextorReadRaw) { sense = _dev.PlextorReadRawDvd(out buffer, out senseBuf, (uint)block, LongBlockSize, _timeout, out duration); } else { return(true); } } else { if (_read6) { sense = _dev.Read6(out buffer, out senseBuf, (uint)block, LogicalBlockSize, (byte)count, _timeout, out duration); } else if (_read10) { sense = _dev.Read10(out buffer, out senseBuf, 0, false, false, false, false, (uint)block, LogicalBlockSize, 0, (ushort)count, _timeout, out duration); } else if (_read12) { sense = _dev.Read12(out buffer, out senseBuf, 0, false, false, false, false, (uint)block, LogicalBlockSize, 0, count, false, _timeout, out duration); } else if (_read16) { sense = _dev.Read16(out buffer, out senseBuf, 0, false, false, false, block, LogicalBlockSize, 0, count, false, _timeout, out duration); } else { return(true); } } if (sense || _dev.Error) { _errorLog?.WriteLine(block, _dev.Error, _dev.LastError, senseBuf); } if (!sense && !_dev.Error) { return(false); } recoveredError = Sense.DecodeFixed(senseBuf)?.SenseKey == SenseKeys.RecoveredError || Sense.DecodeDescriptor(senseBuf)?.SenseKey == SenseKeys.RecoveredError; blankCheck = Sense.DecodeFixed(senseBuf)?.SenseKey == SenseKeys.BlankCheck || Sense.DecodeDescriptor(senseBuf)?.SenseKey == SenseKeys.BlankCheck; AaruConsole.DebugWriteLine("SCSI Reader", "READ error:\n{0}", Sense.PrettifySense(senseBuf)); return(sense); }
static void ReadLog(string devPath, Device dev) { byte address = 0; string strDev; int item; parameters: while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Parameters for READ LOG command:"); AaruConsole.WriteLine("Log address: {0}", address); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Change parameters."); AaruConsole.WriteLine("2.- Send command with these parameters."); AaruConsole.WriteLine("0.- Return to S.M.A.R.T. commands menu."); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to S.M.A.R.T. commands menu..."); return; case 1: AaruConsole.Write("Log address?: "); strDev = System.Console.ReadLine(); if (!byte.TryParse(strDev, out address)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); address = 0; System.Console.ReadKey(); } break; case 2: goto start; } } start: System.Console.Clear(); bool sense = dev.SmartReadLog(out byte[] buffer, out AtaErrorRegistersLba28 errorRegisters, address, dev.Timeout, out double duration); menu: AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Sending READ LOG to the device:"); AaruConsole.WriteLine("Command took {0} ms.", duration); AaruConsole.WriteLine("Sense is {0}.", sense); AaruConsole.WriteLine("Buffer is {0} bytes.", buffer?.Length.ToString() ?? "null"); AaruConsole.WriteLine("Buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(buffer)); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Print buffer."); AaruConsole.WriteLine("2.- Decode error registers."); AaruConsole.WriteLine("3.- Send command again."); AaruConsole.WriteLine("4.- Change parameters."); AaruConsole.WriteLine("0.- Return to S.M.A.R.T. commands menu."); AaruConsole.Write("Choose: "); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to S.M.A.R.T. commands menu..."); return; case 1: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("READ LOG response:"); if (buffer != null) { PrintHex.PrintHexArray(buffer, 64); } AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 2: System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("READ LOG status registers:"); AaruConsole.Write("{0}", MainClass.DecodeAtaRegisters(errorRegisters)); AaruConsole.WriteLine("Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); goto menu; case 3: goto start; case 4: goto parameters; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
internal static void Menu(string devPath, Device dev) { while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Send a MultiMediaCard command to the device:"); AaruConsole.WriteLine("1.- Send READ_MULTIPLE_BLOCK command."); AaruConsole.WriteLine("2.- Send READ_SINGLE_BLOCK command."); AaruConsole.WriteLine("3.- Send SEND_CID command."); AaruConsole.WriteLine("4.- Send SEND_CSD command."); AaruConsole.WriteLine("5.- Send SEND_EXT_CSD command."); AaruConsole.WriteLine("6.- Send SEND_OP_COND command."); AaruConsole.WriteLine("7.- Send SEND_STATUS command."); AaruConsole.WriteLine("8.- Send SET_BLOCKLEN command."); AaruConsole.WriteLine("0.- Return to SecureDigital/MultiMediaCard commands menu."); AaruConsole.Write("Choose: "); string strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out int item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to SecureDigital/MultiMediaCard commands menu..."); return; case 1: Read(devPath, dev, true); continue; case 2: Read(devPath, dev, false); continue; case 3: SendCid(devPath, dev); continue; case 4: SendCsd(devPath, dev); continue; case 5: SendExtendedCsd(devPath, dev); continue; case 6: SendOpCond(devPath, dev); continue; case 7: Status(devPath, dev); continue; case 8: SetBlockLength(devPath, dev); continue; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); continue; } } }
public static void Main() { AaruConsole.WriteLineEvent += System.Console.WriteLine; AaruConsole.WriteEvent += System.Console.Write; AaruConsole.ErrorWriteLineEvent += System.Console.Error.WriteLine; AaruConsole.DebugWriteLineEvent += System.Console.Error.WriteLine; AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine; DeviceInfo[] devices = Aaru.Devices.Device.ListDevices(); if (devices == null || devices.Length == 0) { AaruConsole.WriteLine("No known devices attached."); return; } devices = devices.OrderBy(d => d.Path).ToArray(); while (true) { System.Console.Clear(); AaruConsole.WriteLine("DiscImageChef device handling tests"); AaruConsole.WriteLine("{6,-8}|{0,-22}|{1,-16}|{2,-24}|{3,-24}|{4,-10}|{5,-10}", "Path", "Vendor", "Model", "Serial", "Bus", "Supported?", "Number"); AaruConsole.WriteLine("{6,-8}|{0,-22}+{1,-16}+{2,-24}+{3,-24}+{4,-10}+{5,-10}", "----------------------", "----------------", "------------------------", "------------------------", "----------", "----------", "--------"); for (int i = 0; i < devices.Length; i++) { AaruConsole.WriteLine("{6,-8}|{0,-22}|{1,-16}|{2,-24}|{3,-24}|{4,-10}|{5,-10}", devices[i].Path, devices[i].Vendor, devices[i].Model, devices[i].Serial, devices[i].Bus, devices[i].Supported, i + 1); } AaruConsole.Write("Please choose which drive to test (0 to exit): "); string strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out int item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } if (item == 0) { AaruConsole.WriteLine("Exiting..."); return; } if (item > devices.Length) { AaruConsole.WriteLine("No such device. Press any key to continue..."); System.Console.ReadKey(); continue; } Device(devices[item - 1].Path); } }
static void SetBlockLength(string devPath, Device dev) { uint blockSize = 512; string strDev; int item; parameters: while (true) { System.Console.Clear(); AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Parameters for SET_BLOCKLEN command:"); AaruConsole.WriteLine("Set block length to: {0} bytes", blockSize); AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Change parameters."); AaruConsole.WriteLine("2.- Send command with these parameters."); AaruConsole.WriteLine("0.- Return to MultiMediaCard commands menu."); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); continue; } switch (item) { case 0: AaruConsole.WriteLine("Returning to MultiMediaCard commands menu..."); return; case 1: AaruConsole.Write("Set block length to?"); strDev = System.Console.ReadLine(); if (!uint.TryParse(strDev, out blockSize)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); blockSize = 512; System.Console.ReadKey(); } break; case 2: goto start; } } start: System.Console.Clear(); bool sense = dev.SetBlockLength(blockSize, out uint[] response, dev.Timeout, out double duration); menu: AaruConsole.WriteLine("Device: {0}", devPath); AaruConsole.WriteLine("Sending SET_BLOCKLEN to the device:"); AaruConsole.WriteLine("Command took {0} ms.", duration); AaruConsole.WriteLine("Sense is {0}.", sense); AaruConsole.WriteLine("Response has {0} elements.", response?.Length.ToString() ?? "null"); AaruConsole.WriteLine("SET_BLOCKLEN response:"); if (response != null) { foreach (uint res in response) { AaruConsole.Write("0x{0:x8} ", res); } AaruConsole.WriteLine(); } AaruConsole.WriteLine(); AaruConsole.WriteLine("Choose what to do:"); AaruConsole.WriteLine("1.- Send command again."); AaruConsole.WriteLine("2.- Change parameters."); AaruConsole.WriteLine("0.- Return to MultiMediaCard commands menu."); AaruConsole.Write("Choose: "); strDev = System.Console.ReadLine(); if (!int.TryParse(strDev, out item)) { AaruConsole.WriteLine("Not a number. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } switch (item) { case 0: AaruConsole.WriteLine("Returning to MultiMediaCard commands menu..."); return; case 1: goto start; case 2: goto parameters; default: AaruConsole.WriteLine("Incorrect option. Press any key to continue..."); System.Console.ReadKey(); System.Console.Clear(); goto menu; } }
public bool Open(IFilter imageFilter) { Stream stream = imageFilter.GetDataForkStream(); stream.Seek(0, SeekOrigin.Begin); var type = (DiskType)stream.ReadByte(); byte tracks; switch (type) { case DiskType.MD1DD8: case DiskType.MD1DD: case DiskType.MD2DD8: case DiskType.MD2DD: tracks = 80; break; case DiskType.MF2DD: case DiskType.MD2HD: case DiskType.MF2HD: tracks = 160; break; default: throw new ImageNotSupportedException($"Incorrect disk type {(byte)type}"); } byte[] trackBytes = new byte[tracks]; stream.Read(trackBytes, 0, tracks); var cmpr = (Compression)stream.ReadByte(); if (cmpr != Compression.None) { throw new FeatureSupportedButNotImplementedImageException("Compressed images are not supported."); } int tracksize = 0; switch (type) { case DiskType.MD1DD8: case DiskType.MD2DD8: tracksize = 8 * 512; break; case DiskType.MD1DD: case DiskType.MD2DD: case DiskType.MF2DD: tracksize = 9 * 512; break; case DiskType.MD2HD: tracksize = 15 * 512; break; case DiskType.MF2HD: tracksize = 18 * 512; break; } int headstep = 1; if (type == DiskType.MD1DD || type == DiskType.MD1DD8) { headstep = 2; } var decodedImage = new MemoryStream(); for (int i = 0; i < tracks; i += headstep) { byte[] track = new byte[tracksize]; if ((TrackType)trackBytes[i] == TrackType.Copied) { stream.Read(track, 0, tracksize); } else { ArrayHelpers.ArrayFill(track, (byte)0xF6); } decodedImage.Write(track, 0, tracksize); } imageInfo.Application = "CisCopy"; imageInfo.CreationTime = imageFilter.GetCreationTime(); imageInfo.LastModificationTime = imageFilter.GetLastWriteTime(); imageInfo.MediaTitle = imageFilter.GetFilename(); imageInfo.ImageSize = (ulong)(stream.Length - 2 - trackBytes.Length); imageInfo.SectorSize = 512; switch (type) { case DiskType.MD1DD8: imageInfo.MediaType = MediaType.DOS_525_SS_DD_8; imageInfo.Sectors = 40 * 1 * 8; imageInfo.Heads = 1; imageInfo.Cylinders = 40; imageInfo.SectorsPerTrack = 8; break; case DiskType.MD2DD8: imageInfo.MediaType = MediaType.DOS_525_DS_DD_8; imageInfo.Sectors = 40 * 2 * 8; imageInfo.Heads = 2; imageInfo.Cylinders = 40; imageInfo.SectorsPerTrack = 8; break; case DiskType.MD1DD: imageInfo.MediaType = MediaType.DOS_525_SS_DD_9; imageInfo.Sectors = 40 * 1 * 9; imageInfo.Heads = 1; imageInfo.Cylinders = 40; imageInfo.SectorsPerTrack = 9; break; case DiskType.MD2DD: imageInfo.MediaType = MediaType.DOS_525_DS_DD_9; imageInfo.Sectors = 40 * 2 * 9; imageInfo.Heads = 2; imageInfo.Cylinders = 40; imageInfo.SectorsPerTrack = 9; break; case DiskType.MF2DD: imageInfo.MediaType = MediaType.DOS_35_DS_DD_9; imageInfo.Sectors = 80 * 2 * 9; imageInfo.Heads = 2; imageInfo.Cylinders = 80; imageInfo.SectorsPerTrack = 9; break; case DiskType.MD2HD: imageInfo.MediaType = MediaType.DOS_525_HD; imageInfo.Sectors = 80 * 2 * 15; imageInfo.Heads = 2; imageInfo.Cylinders = 80; imageInfo.SectorsPerTrack = 15; break; case DiskType.MF2HD: imageInfo.MediaType = MediaType.DOS_35_HD; imageInfo.Sectors = 80 * 2 * 18; imageInfo.Heads = 2; imageInfo.Cylinders = 80; imageInfo.SectorsPerTrack = 18; break; } imageInfo.XmlMediaType = XmlMediaType.BlockMedia; decodedDisk = decodedImage.ToArray(); decodedImage.Close(); AaruConsole.VerboseWriteLine("CisCopy image contains a disk of type {0}", imageInfo.MediaType); return(true); }