Beispiel #1
0
        public DeviceInfo(Device dev)
        {
            Type                  = dev.Type;
            Manufacturer          = dev.Manufacturer;
            Model                 = dev.Model;
            FirmwareRevision      = dev.FirmwareRevision;
            Serial                = dev.Serial;
            ScsiType              = dev.ScsiType;
            IsRemovable           = dev.IsRemovable;
            IsUsb                 = dev.IsUsb;
            UsbVendorId           = dev.UsbVendorId;
            UsbProductId          = dev.UsbProductId;
            UsbDescriptors        = dev.UsbDescriptors;
            UsbManufacturerString = dev.UsbManufacturerString;
            UsbProductString      = dev.UsbProductString;
            UsbSerialString       = dev.UsbSerialString;
            IsFireWire            = dev.IsFireWire;
            FireWireGuid          = dev.FireWireGuid;
            FireWireModel         = dev.FireWireModel;
            FireWireModelName     = dev.FireWireModelName;
            FireWireVendor        = dev.FireWireVendor;
            FireWireVendorName    = dev.FireWireVendorName;
            IsCompactFlash        = dev.IsCompactFlash;
            IsPcmcia              = dev.IsPcmcia;
            Cis = dev.Cis;

            switch (dev.Type)
            {
            case DeviceType.ATA:
            {
                bool sense = dev.AtaIdentify(out byte[] ataBuf, out AtaErrorRegistersChs errorRegisters);

                if (sense)
                {
                    AaruConsole.DebugWriteLine("Device-Info command", "STATUS = 0x{0:X2}", errorRegisters.Status);
                    AaruConsole.DebugWriteLine("Device-Info command", "ERROR = 0x{0:X2}", errorRegisters.Error);

                    AaruConsole.DebugWriteLine("Device-Info command", "NSECTOR = 0x{0:X2}",
                                               errorRegisters.SectorCount);

                    AaruConsole.DebugWriteLine("Device-Info command", "SECTOR = 0x{0:X2}", errorRegisters.Sector);

                    AaruConsole.DebugWriteLine("Device-Info command", "CYLHIGH = 0x{0:X2}",
                                               errorRegisters.CylinderHigh);

                    AaruConsole.DebugWriteLine("Device-Info command", "CYLLOW = 0x{0:X2}",
                                               errorRegisters.CylinderLow);

                    AaruConsole.DebugWriteLine("Device-Info command", "DEVICE = 0x{0:X2}",
                                               errorRegisters.DeviceHead);

                    AaruConsole.DebugWriteLine("Device-Info command", "Error code = {0}", dev.LastError);

                    break;
                }

                if (dev.Error)
                {
                    AaruConsole.ErrorWriteLine("Error {0} querying ATA IDENTIFY", dev.LastError);

                    break;
                }

                AtaIdentify = ataBuf;

                dev.EnableMediaCardPassThrough(out errorRegisters, dev.Timeout, out _);

                if (errorRegisters.Sector == 0xAA &&
                    errorRegisters.SectorCount == 0x55)
                {
                    AtaMcptError = errorRegisters;
                }

                break;
            }

            case DeviceType.ATAPI:
            {
                bool sense = dev.AtapiIdentify(out byte[] ataBuf, out AtaErrorRegistersChs errorRegisters);

                if (sense)
                {
                    AaruConsole.DebugWriteLine("Device-Info command", "STATUS = 0x{0:X2}", errorRegisters.Status);
                    AaruConsole.DebugWriteLine("Device-Info command", "ERROR = 0x{0:X2}", errorRegisters.Error);

                    AaruConsole.DebugWriteLine("Device-Info command", "NSECTOR = 0x{0:X2}",
                                               errorRegisters.SectorCount);

                    AaruConsole.DebugWriteLine("Device-Info command", "SECTOR = 0x{0:X2}", errorRegisters.Sector);

                    AaruConsole.DebugWriteLine("Device-Info command", "CYLHIGH = 0x{0:X2}",
                                               errorRegisters.CylinderHigh);

                    AaruConsole.DebugWriteLine("Device-Info command", "CYLLOW = 0x{0:X2}",
                                               errorRegisters.CylinderLow);

                    AaruConsole.DebugWriteLine("Device-Info command", "DEVICE = 0x{0:X2}",
                                               errorRegisters.DeviceHead);

                    AaruConsole.DebugWriteLine("Device-Info command", "Error code = {0}", dev.LastError);

                    break;
                }

                if (!dev.Error)
                {
                    AtapiIdentify = ataBuf;
                }
                else
                {
                    AaruConsole.ErrorWriteLine("Error {0} querying ATA PACKET IDENTIFY", dev.LastError);
                }

                // ATAPI devices are also SCSI devices
                goto case DeviceType.SCSI;
            }

            case DeviceType.SCSI:
            {
                bool sense = dev.ScsiInquiry(out byte[] inqBuf, out byte[] senseBuf);

                if (sense)
                {
                    AaruConsole.ErrorWriteLine("SCSI error:\n{0}", Sense.PrettifySense(senseBuf));

                    break;
                }

                ScsiInquiryData = inqBuf;
                ScsiInquiry     = Inquiry.Decode(inqBuf);

                sense = dev.ScsiInquiry(out inqBuf, out senseBuf, 0x00);

                if (!sense)
                {
                    ScsiEvpdPages = new Dictionary <byte, byte[]>();

                    byte[] pages = EVPD.DecodePage00(inqBuf);

                    if (pages != null)
                    {
                        foreach (byte page in pages)
                        {
                            sense = dev.ScsiInquiry(out inqBuf, out senseBuf, page);

                            if (sense)
                            {
                                continue;
                            }

                            ScsiEvpdPages.Add(page, inqBuf);
                        }
                    }
                }

                var devType = (PeripheralDeviceTypes)ScsiInquiry.Value.PeripheralDeviceType;

                sense = dev.ModeSense10(out byte[] modeBuf, out senseBuf, false, true,
                                        ScsiModeSensePageControl.Current, 0x3F, 0xFF, 5, out _);

                if (!sense &&
                    !dev.Error)
                {
                    ScsiModeSense10 = modeBuf;
                }

                if (sense || dev.Error)
                {
                    sense = dev.ModeSense10(out modeBuf, out senseBuf, false, true,
                                            ScsiModeSensePageControl.Current, 0x3F, 0x00, 5, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        ScsiModeSense10 = modeBuf;
                    }
                }

                if (!sense &&
                    !dev.Error)
                {
                    ScsiMode = Modes.DecodeMode10(modeBuf, devType);
                }

                bool useMode10 = !(sense || dev.Error || !ScsiMode.HasValue);

                sense = dev.ModeSense6(out modeBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F,
                                       0xFF, 5, out _);

                if (!sense &&
                    !dev.Error)
                {
                    ScsiModeSense6 = modeBuf;
                }

                if (sense || dev.Error)
                {
                    sense = dev.ModeSense6(out modeBuf, out senseBuf, false, ScsiModeSensePageControl.Current, 0x3F,
                                           0x00, 5, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        ScsiModeSense6 = modeBuf;
                    }
                }

                if (sense || dev.Error)
                {
                    sense = dev.ModeSense(out modeBuf, out senseBuf, 5, out _);

                    if (!sense &&
                        !dev.Error)
                    {
                        ScsiModeSense6 = modeBuf;
                    }
                }

                if (!sense &&
                    !dev.Error &&
                    !useMode10)
                {
                    ScsiMode = Modes.DecodeMode6(modeBuf, devType);
                }

                switch (devType)
                {
                case PeripheralDeviceTypes.MultiMediaDevice:
                {
                    sense = dev.GetConfiguration(out byte[] confBuf, out senseBuf, dev.Timeout, out _);

                    if (!sense)
                    {
                        MmcConfiguration = confBuf;
                    }

                    // TODO: DVD drives respond correctly to BD status.
                    // While specification says if no medium is present
                    // it should inform all possible capabilities,
                    // testing drives show only supported media capabilities.

                    /*
                     * byte[] strBuf;
                     * sense = dev.ReadDiscStructure(out strBuf, out senseBuf, MmcDiscStructureMediaType.DVD, 0, 0, MmcDiscStructureFormat.CapabilityList, 0, dev.Timeout, out _);
                     *
                     * if (!sense)
                     * {
                     *  Decoders.SCSI.DiscStructureCapabilities.Capability[] caps = Decoders.SCSI.DiscStructureCapabilities.Decode(strBuf);
                     *  if (caps != null)
                     *  {
                     *      foreach (Decoders.SCSI.DiscStructureCapabilities.Capability cap in caps)
                     *      {
                     *          if (cap.SDS && cap.RDS)
                     *              AaruConsole.WriteLine("Drive can READ/SEND DISC STRUCTURE format {0:X2}h", cap.FormatCode);
                     *          else if (cap.SDS)
                     *              AaruConsole.WriteLine("Drive can SEND DISC STRUCTURE format {0:X2}h", cap.FormatCode);
                     *          else if (cap.RDS)
                     *              AaruConsole.WriteLine("Drive can READ DISC STRUCTURE format {0:X2}h", cap.FormatCode);
                     *      }
                     *  }
                     * }
                     *
                     * sense = dev.ReadDiscStructure(out strBuf, out senseBuf, MmcDiscStructureMediaType.BD, 0, 0, MmcDiscStructureFormat.CapabilityList, 0, dev.Timeout, out _);
                     *
                     * if (!sense)
                     * {
                     *  Decoders.SCSI.DiscStructureCapabilities.Capability[] caps = Decoders.SCSI.DiscStructureCapabilities.Decode(strBuf);
                     *  if (caps != null)
                     *  {
                     *      foreach (Decoders.SCSI.DiscStructureCapabilities.Capability cap in caps)
                     *      {
                     *          if (cap.SDS && cap.RDS)
                     *              AaruConsole.WriteLine("Drive can READ/SEND DISC STRUCTURE format {0:X2}h", cap.FormatCode);
                     *          else if (cap.SDS)
                     *              AaruConsole.WriteLine("Drive can SEND DISC STRUCTURE format {0:X2}h", cap.FormatCode);
                     *          else if (cap.RDS)
                     *              AaruConsole.WriteLine("Drive can READ DISC STRUCTURE format {0:X2}h", cap.FormatCode);
                     *      }
                     *  }
                     * }
                     */

                    #region Plextor
                    if (dev.Manufacturer == "PLEXTOR")
                    {
                        bool   plxtSense = true;
                        bool   plxtDvd   = false;
                        byte[] plxtBuf   = null;

                        switch (dev.Model)
                        {
                        case "DVDR   PX-708A":
                        case "DVDR   PX-708A2":
                        case "DVDR   PX-712A":
                            plxtDvd = true;

                            plxtSense = dev.PlextorReadEeprom(out plxtBuf, out senseBuf, dev.Timeout,
                                                              out _);

                            break;

                        case "DVDR   PX-714A":
                        case "DVDR   PX-716A":
                        case "DVDR   PX-716AL":
                        case "DVDR   PX-755A":
                        case "DVDR   PX-760A":
                        {
                            plxtBuf = new byte[256 * 4];

                            for (byte i = 0; i < 4; i++)
                            {
                                plxtSense = dev.PlextorReadEepromBlock(out byte[] plxtBufSmall,
                                                                       out senseBuf, i, 256, dev.Timeout, out _);

                                if (plxtSense)
                                {
                                    break;
                                }

                                Array.Copy(plxtBufSmall, 0, plxtBuf, i * 256, 256);
                            }

                            plxtDvd = true;

                            break;
                        }

                        default:
                        {
                            if (dev.Model.StartsWith("CD-R   ", StringComparison.Ordinal))
                            {
                                plxtSense = dev.PlextorReadEepromCdr(out plxtBuf, out senseBuf, dev.Timeout,
                                                                     out _);
                            }

                            break;
                        }
                        }

                        PlextorFeatures = new Plextor
                        {
                            IsDvd = plxtDvd
                        };

                        if (!plxtSense)
                        {
                            PlextorFeatures.Eeprom = plxtBuf;

                            if (plxtDvd)
                            {
                                PlextorFeatures.Discs        = BigEndianBitConverter.ToUInt16(plxtBuf, 0x0120);
                                PlextorFeatures.CdReadTime   = BigEndianBitConverter.ToUInt32(plxtBuf, 0x0122);
                                PlextorFeatures.CdWriteTime  = BigEndianBitConverter.ToUInt32(plxtBuf, 0x0126);
                                PlextorFeatures.DvdReadTime  = BigEndianBitConverter.ToUInt32(plxtBuf, 0x012A);
                                PlextorFeatures.DvdWriteTime = BigEndianBitConverter.ToUInt32(plxtBuf, 0x012E);
                            }
                            else
                            {
                                PlextorFeatures.Discs       = BigEndianBitConverter.ToUInt16(plxtBuf, 0x0078);
                                PlextorFeatures.CdReadTime  = BigEndianBitConverter.ToUInt32(plxtBuf, 0x006C);
                                PlextorFeatures.CdWriteTime = BigEndianBitConverter.ToUInt32(plxtBuf, 0x007A);
                            }
                        }

                        plxtSense = dev.PlextorGetPoweRec(out senseBuf, out bool plxtPwrRecEnabled,
                                                          out ushort plxtPwrRecSpeed, dev.Timeout, out _);

                        if (!plxtSense)
                        {
                            PlextorFeatures.PoweRec = true;

                            if (plxtPwrRecEnabled)
                            {
                                PlextorFeatures.PoweRecEnabled          = true;
                                PlextorFeatures.PoweRecRecommendedSpeed = plxtPwrRecSpeed;

                                plxtSense = dev.PlextorGetSpeeds(out senseBuf, out ushort plxtPwrRecSelected,
                                                                 out ushort plxtPwrRecMax,
                                                                 out ushort plxtPwrRecLast, dev.Timeout, out _);

                                if (!plxtSense)
                                {
                                    PlextorFeatures.PoweRecSelected = plxtPwrRecSelected;
                                    PlextorFeatures.PoweRecMax      = plxtPwrRecMax;
                                    PlextorFeatures.PoweRecLast     = plxtPwrRecLast;
                                }
                            }
                        }

                        // TODO: Check it with a drive
                        plxtSense = dev.PlextorGetSilentMode(out plxtBuf, out senseBuf, dev.Timeout, out _);

                        if (!plxtSense)
                        {
                            if (plxtBuf[0] == 1)
                            {
                                PlextorFeatures.SilentModeEnabled = true;
                                PlextorFeatures.AccessTimeLimit   = plxtBuf[1];

                                PlextorFeatures.CdReadSpeedLimit  = plxtBuf[2];
                                PlextorFeatures.DvdReadSpeedLimit = plxtBuf[3];
                                PlextorFeatures.CdWriteSpeedLimit = plxtBuf[4];

                                // TODO: Check which one is each one

                                /*
                                 *  if(plxtBuf[6] > 0)
                                 *      AaruConsole.WriteLine("\tTray eject speed limited to {0}",
                                 *                           -(plxtBuf[6] + 48));
                                 *  if(plxtBuf[7] > 0)
                                 *      AaruConsole.WriteLine("\tTray eject speed limited to {0}",
                                 *                           plxtBuf[7] - 47);
                                 */
                            }
                        }

                        plxtSense = dev.PlextorGetGigaRec(out plxtBuf, out senseBuf, dev.Timeout, out _);

                        if (!plxtSense)
                        {
                            PlextorFeatures.GigaRec = true;
                        }

                        plxtSense = dev.PlextorGetSecuRec(out plxtBuf, out senseBuf, dev.Timeout, out _);

                        if (!plxtSense)
                        {
                            PlextorFeatures.SecuRec = true;
                        }

                        plxtSense = dev.PlextorGetSpeedRead(out plxtBuf, out senseBuf, dev.Timeout, out _);

                        if (!plxtSense)
                        {
                            PlextorFeatures.SpeedRead = true;

                            if ((plxtBuf[2] & 0x01) == 0x01)
                            {
                                PlextorFeatures.SpeedReadEnabled = true;
                            }
                        }

                        plxtSense = dev.PlextorGetHiding(out plxtBuf, out senseBuf, dev.Timeout, out _);

                        if (!plxtSense)
                        {
                            PlextorFeatures.Hiding = true;

                            if ((plxtBuf[2] & 0x02) == 0x02)
                            {
                                PlextorFeatures.HidesRecordables = true;
                            }

                            if ((plxtBuf[2] & 0x01) == 0x01)
                            {
                                PlextorFeatures.HidesSessions = true;
                            }
                        }

                        plxtSense = dev.PlextorGetVariRec(out plxtBuf, out senseBuf, false, dev.Timeout, out _);

                        if (!plxtSense)
                        {
                            PlextorFeatures.VariRec = true;
                        }

                        if (plxtDvd)
                        {
                            plxtSense = dev.PlextorGetVariRec(out plxtBuf, out senseBuf, true, dev.Timeout,
                                                              out _);

                            if (!plxtSense)
                            {
                                PlextorFeatures.VariRecDvd = true;
                            }

                            plxtSense = dev.PlextorGetBitsetting(out plxtBuf, out senseBuf, false, dev.Timeout,
                                                                 out _);

                            if (!plxtSense)
                            {
                                PlextorFeatures.BitSetting = true;
                            }

                            plxtSense = dev.PlextorGetBitsetting(out plxtBuf, out senseBuf, true, dev.Timeout,
                                                                 out _);

                            if (!plxtSense)
                            {
                                PlextorFeatures.BitSettingDl = true;
                            }

                            plxtSense = dev.PlextorGetTestWriteDvdPlus(out plxtBuf, out senseBuf, dev.Timeout,
                                                                       out _);

                            if (!plxtSense)
                            {
                                PlextorFeatures.DvdPlusWriteTest = true;
                            }
                        }
                    }
                    #endregion Plextor

                    if (ScsiInquiry.Value.KreonPresent)
                    {
                        if (!dev.KreonGetFeatureList(out senseBuf, out KreonFeatures krFeatures, dev.Timeout,
                                                     out _))
                        {
                            KreonFeatures = krFeatures;
                        }
                    }

                    break;
                }

                case PeripheralDeviceTypes.SequentialAccess:
                {
                    sense = dev.ReadBlockLimits(out byte[] seqBuf, out senseBuf, dev.Timeout, out _);

                    if (sense)
                    {
                        AaruConsole.ErrorWriteLine("READ BLOCK LIMITS:\n{0}", Sense.PrettifySense(senseBuf));
                    }
                    else
                    {
                        BlockLimits = seqBuf;
                    }

                    sense = dev.ReportDensitySupport(out seqBuf, out senseBuf, dev.Timeout, out _);

                    if (sense)
                    {
                        AaruConsole.ErrorWriteLine("REPORT DENSITY SUPPORT:\n{0}",
                                                   Sense.PrettifySense(senseBuf));
                    }
                    else
                    {
                        DensitySupport       = seqBuf;
                        DensitySupportHeader = Decoders.SCSI.SSC.DensitySupport.DecodeDensity(seqBuf);
                    }

                    sense = dev.ReportDensitySupport(out seqBuf, out senseBuf, true, false, dev.Timeout, out _);

                    if (sense)
                    {
                        AaruConsole.ErrorWriteLine("REPORT DENSITY SUPPORT (MEDIUM):\n{0}",
                                                   Sense.PrettifySense(senseBuf));
                    }
                    else
                    {
                        MediumDensitySupport   = seqBuf;
                        MediaTypeSupportHeader = Decoders.SCSI.SSC.DensitySupport.DecodeMediumType(seqBuf);
                    }

                    break;
                }
                }

                break;
            }

            case DeviceType.MMC:
            {
                bool sense = dev.ReadCid(out byte[] mmcBuf, out _, dev.Timeout, out _);

                if (!sense)
                {
                    CID = mmcBuf;
                }

                sense = dev.ReadCsd(out mmcBuf, out _, dev.Timeout, out _);

                if (!sense)
                {
                    CSD = mmcBuf;
                }

                sense = dev.ReadOcr(out mmcBuf, out _, dev.Timeout, out _);

                if (!sense)
                {
                    OCR = mmcBuf;
                }

                sense = dev.ReadExtendedCsd(out mmcBuf, out _, dev.Timeout, out _);

                if (!sense &&
                    !ArrayHelpers.ArrayIsNullOrEmpty(mmcBuf))
                {
                    ExtendedCSD = mmcBuf;
                }
            }

            break;

            case DeviceType.SecureDigital:
            {
                bool sense = dev.ReadCid(out byte[] sdBuf, out _, dev.Timeout, out _);

                if (!sense)
                {
                    CID = sdBuf;
                }

                sense = dev.ReadCsd(out sdBuf, out _, dev.Timeout, out _);

                if (!sense)
                {
                    CSD = sdBuf;
                }

                sense = dev.ReadSdocr(out sdBuf, out _, dev.Timeout, out _);

                if (!sense)
                {
                    OCR = sdBuf;
                }

                sense = dev.ReadScr(out sdBuf, out _, dev.Timeout, out _);

                if (!sense)
                {
                    SCR = sdBuf;
                }
            }

            break;

            default:
                AaruConsole.ErrorWriteLine("Unknown device type {0}, cannot get information.", dev.Type);

                break;
            }
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        static void Display(string devPath, Device dev)
        {
            bool flash = false;
            FujitsuDisplayModes mode = FujitsuDisplayModes.Ready;
            string firstHalf         = "DIC TEST";
            string secondHalf        = "TEST DIC";
            string strDev;
            int    item;

parameters:
            while (true)
            {
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("Parameters for DISPLAY command:");
                DicConsole.WriteLine("Descriptor: {0}", flash);
                DicConsole.WriteLine();
                DicConsole.WriteLine("Choose what to do:");
                DicConsole.WriteLine("1.- Change parameters.");
                DicConsole.WriteLine("2.- Send command with these parameters.");
                DicConsole.WriteLine("0.- Return to Fujitsu vendor commands menu.");

                strDev = System.Console.ReadLine();
                if (!int.TryParse(strDev, out item))
                {
                    DicConsole.WriteLine("Not a number. Press any key to continue...");
                    System.Console.ReadKey();
                    continue;
                }

                switch (item)
                {
                case 0:
                    DicConsole.WriteLine("Returning to Fujitsu vendor commands menu...");
                    return;

                case 1:
                    DicConsole.Write("Flash?: ");
                    strDev = System.Console.ReadLine();
                    if (!bool.TryParse(strDev, out flash))
                    {
                        DicConsole.WriteLine("Not a number. Press any key to continue...");
                        flash = false;
                        System.Console.ReadKey();
                        continue;
                    }

                    DicConsole.WriteLine("Display mode");
                    DicConsole.WriteLine("Available values: {0} {1} {2} {3} {4}", FujitsuDisplayModes.Cancel,
                                         FujitsuDisplayModes.Cart, FujitsuDisplayModes.Half,
                                         FujitsuDisplayModes.Idle, FujitsuDisplayModes.Ready);
                    DicConsole.Write("Choose?: ");
                    strDev = System.Console.ReadLine();
                    if (!Enum.TryParse(strDev, true, out mode))
                    {
                        DicConsole.WriteLine("Not a correct display mode. Press any key to continue...");
                        mode = FujitsuDisplayModes.Ready;
                        System.Console.ReadKey();
                        continue;
                    }

                    DicConsole.Write("First display half (will be cut to 7-bit ASCII, 8 chars?: ");
                    firstHalf = System.Console.ReadLine();
                    DicConsole.Write("Second display half (will be cut to 7-bit ASCII, 8 chars?: ");
                    secondHalf = System.Console.ReadLine();
                    break;

                case 2: goto start;
                }
            }

start:
            System.Console.Clear();
            bool sense = dev.FujitsuDisplay(out byte[] senseBuffer, flash, mode, firstHalf, secondHalf, dev.Timeout,
                                            out double duration);

menu:
            DicConsole.WriteLine("Device: {0}", devPath);
            DicConsole.WriteLine("Sending DISPLAY to the device:");
            DicConsole.WriteLine("Command took {0} ms.", duration);
            DicConsole.WriteLine("Sense is {0}.", sense);
            DicConsole.WriteLine("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null");
            DicConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer));
            DicConsole.WriteLine("DISPLAY decoded sense:");
            DicConsole.Write("{0}", Sense.PrettifySense(senseBuffer));
            DicConsole.WriteLine();
            DicConsole.WriteLine("Choose what to do:");
            DicConsole.WriteLine("1.- Print sense buffer.");
            DicConsole.WriteLine("2.- Send command again.");
            DicConsole.WriteLine("3.- Change parameters.");
            DicConsole.WriteLine("0.- Return to Fujitsu vendor commands menu.");
            DicConsole.Write("Choose: ");

            strDev = System.Console.ReadLine();
            if (!int.TryParse(strDev, out item))
            {
                DicConsole.WriteLine("Not a number. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                goto menu;
            }

            switch (item)
            {
            case 0:
                DicConsole.WriteLine("Returning to Fujitsu vendor commands menu...");
                return;

            case 1:
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("DISPLAY sense:");
                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(senseBuffer, 64);
                }
                DicConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                goto menu;

            case 2: goto start;

            case 3: goto parameters;

            default:
                DicConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                goto menu;
            }
        }
Beispiel #4
0
        static void ReadAttribute(string devPath, Device dev)
        {
            ushort element             = 0;
            byte   elementType         = 0;
            byte   volume              = 0;
            byte   partition           = 0;
            ushort firstAttribute      = 0;
            bool   cache               = false;
            ScsiAttributeAction action = ScsiAttributeAction.Values;
            string strDev;
            int    item;

parameters:

            while (true)
            {
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("Parameters for READ ATTRIBUTE command:");
                AaruConsole.WriteLine("Action: {0}", action);
                AaruConsole.WriteLine("Element: {0}", element);
                AaruConsole.WriteLine("Element type: {0}", elementType);
                AaruConsole.WriteLine("Volume: {0}", volume);
                AaruConsole.WriteLine("Partition: {0}", partition);
                AaruConsole.WriteLine("First attribute: {0}", firstAttribute);
                AaruConsole.WriteLine("Use cache?: {0}", cache);
                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 SCSI Media Changer 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 SCSI Media Changer commands menu...");

                    return;

                case 1:
                    AaruConsole.WriteLine("Attribute action");

                    AaruConsole.WriteLine("Available values: {0} {1} {2} {3} {4}", ScsiAttributeAction.Values,
                                          ScsiAttributeAction.List, ScsiAttributeAction.VolumeList,
                                          ScsiAttributeAction.PartitionList, ScsiAttributeAction.ElementList,
                                          ScsiAttributeAction.Supported);

                    AaruConsole.Write("Choose?: ");
                    strDev = System.Console.ReadLine();

                    if (!Enum.TryParse(strDev, true, out action))
                    {
                        AaruConsole.WriteLine("Not a valid attribute action. Press any key to continue...");
                        action = ScsiAttributeAction.Values;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Element?: ");
                    strDev = System.Console.ReadLine();

                    if (!ushort.TryParse(strDev, out element))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        element = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Element type?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.TryParse(strDev, out elementType))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        elementType = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Volume?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.TryParse(strDev, out volume))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        volume = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Partition?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.TryParse(strDev, out partition))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        partition = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("First attribute?: ");
                    strDev = System.Console.ReadLine();

                    if (!ushort.TryParse(strDev, out firstAttribute))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        firstAttribute = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Use cache?: ");
                    strDev = System.Console.ReadLine();

                    if (!bool.TryParse(strDev, out cache))
                    {
                        AaruConsole.WriteLine("Not a boolean. Press any key to continue...");
                        cache = false;
                        System.Console.ReadKey();
                    }

                    break;

                case 2: goto start;
                }
            }

start:
            System.Console.Clear();

            bool sense = dev.ReadAttribute(out byte[] buffer, out byte[] senseBuffer, action, element, elementType,
                                           volume, partition, firstAttribute, cache, dev.Timeout, out double duration);

menu:
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Sending READ ATTRIBUTE 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("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null");
            AaruConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer));
            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print buffer.");
            AaruConsole.WriteLine("2.- Print sense buffer.");
            AaruConsole.WriteLine("3.- Decode sense buffer.");
            AaruConsole.WriteLine("4.- Send command again.");
            AaruConsole.WriteLine("5.- Change parameters.");
            AaruConsole.WriteLine("0.- Return to SCSI Media Changer 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 SCSI Media Changer commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ ATTRIBUTE 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 ATTRIBUTE 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 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ ATTRIBUTE decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);

                goto menu;

            case 4: goto start;

            case 5: goto parameters;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
Beispiel #5
0
        static void ReadCdDaMsf(string devPath, Device dev)
        {
            byte startFrame           = 0;
            byte startSecond          = 2;
            byte startMinute          = 0;
            byte endFrame             = 0;
            byte endSecond            = 0;
            byte endMinute            = 0;
            PioneerSubchannel subchan = PioneerSubchannel.None;
            uint   blockSize          = 2352;
            string strDev;
            int    item;

parameters:

            while (true)
            {
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("Parameters for READ CD-DA MSF command:");
                AaruConsole.WriteLine("Start: {0:D2}:{1:D2}:{2:D2}", startMinute, startSecond, startFrame);
                AaruConsole.WriteLine("End: {0:D2}:{1:D2}:{2:D2}", endMinute, endSecond, endFrame);
                AaruConsole.WriteLine("Subchannel mode: {0}", subchan);
                AaruConsole.WriteLine("{0} bytes per sectors", 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 Pioneer vendor 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 Pioneer vendor commands menu...");

                    return;

                case 1:
                    AaruConsole.Write("Start minute?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.TryParse(strDev, out startMinute))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        startMinute = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Start second?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.TryParse(strDev, out startSecond))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        startSecond = 2;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Start frame?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.TryParse(strDev, out startFrame))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        startFrame = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("End minute?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.TryParse(strDev, out endMinute))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        endMinute = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("End second?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.TryParse(strDev, out endMinute))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        endMinute = 2;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("End frame?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.TryParse(strDev, out endFrame))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        endFrame = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.WriteLine("Subchannel mode");

                    AaruConsole.WriteLine("Available values: {0} {1} {2} {3}", PioneerSubchannel.None,
                                          PioneerSubchannel.Q16, PioneerSubchannel.All, PioneerSubchannel.Only);

                    AaruConsole.Write("Choose?: ");
                    strDev = System.Console.ReadLine();

                    if (!Enum.TryParse(strDev, true, out subchan))
                    {
                        AaruConsole.WriteLine("Not a correct page control. Press any key to continue...");
                        subchan = PioneerSubchannel.None;
                        System.Console.ReadKey();

                        continue;
                    }

                    switch (subchan)
                    {
                    case PioneerSubchannel.Q16:
                        blockSize = 2368;

                        break;

                    case PioneerSubchannel.All:
                        blockSize = 2448;

                        break;

                    case PioneerSubchannel.Only:
                        blockSize = 96;

                        break;

                    default:
                        blockSize = 2352;

                        break;
                    }

                    break;

                case 2: goto start;
                }
            }

start:
            uint startMsf = (uint)((startMinute << 16) + (startSecond << 8) + startFrame);
            uint endMsf = (uint)((startMinute << 16) + (startSecond << 8) + startFrame);

            System.Console.Clear();

            bool sense = dev.PioneerReadCdDaMsf(out byte[] buffer, out byte[] senseBuffer, startMsf, endMsf, blockSize,
                                                subchan, dev.Timeout, out double duration);

menu:
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Sending READ CD-DA MSF 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("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null");
            AaruConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer));
            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print buffer.");
            AaruConsole.WriteLine("2.- Print sense buffer.");
            AaruConsole.WriteLine("3.- Decode sense buffer.");
            AaruConsole.WriteLine("4.- Send command again.");
            AaruConsole.WriteLine("5.- Change parameters.");
            AaruConsole.WriteLine("0.- Return to Pioneer vendor 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 Pioneer vendor commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ CD-DA MSF 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 CD-DA MSF 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 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ CD-DA MSF decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);

                goto menu;

            case 4: goto start;

            case 5: goto parameters;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
Beispiel #6
0
        void RetryCdUserData(ExtentsULong audioExtents, uint blockSize, DumpHardwareType currentTry,
                             ExtentsULong extents, int offsetBytes, bool readcd, int sectorsForOffset, uint subSize,
                             MmcSubchannel supportedSubchannel, ref double totalDuration, SubchannelLog subLog,
                             MmcSubchannel desiredSubchannel, Track[] tracks, Dictionary <byte, string> isrcs,
                             ref string mcn)
        {
            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>();

            for (int i = 0; i < tmpArray.Length; i++)
            {
                ulong badSector = tmpArray[i];

                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, " : ""));

                Track track = tracks.OrderBy(t => t.TrackStartSector).
                              LastOrDefault(t => badSector >= t.TrackStartSector);

                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);

                    bool indexesChanged = WriteSubchannelToImage(supportedSubchannel, desiredSubchannel, sub, badSector,
                                                                 1, subLog, isrcs, (byte)track.TrackSequence, ref mcn,
                                                                 tracks);

                    // Set tracks and go back
                    if (indexesChanged)
                    {
                        (_outputPlugin as IWritableOpticalImage).SetTracks(tracks.ToList());
                        i--;
                    }
                }
                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();

                    for (int i = 0; i < sectorsNotEvenPartial.Count; i++)
                    {
                        ulong badSector = sectorsNotEvenPartial[i];

                        if (_aborted)
                        {
                            currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                            _dumpLog.WriteLine("Aborted!");

                            break;
                        }

                        PulseProgress?.Invoke($"Trying to get partial data for sector {badSector}");

                        Track track = tracks.OrderBy(t => t.TrackStartSector).
                                      LastOrDefault(t => badSector >= t.TrackStartSector);

                        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);

                            bool indexesChanged = WriteSubchannelToImage(supportedSubchannel, desiredSubchannel, sub,
                                                                         badSector, 1, subLog, isrcs,
                                                                         (byte)track.TrackSequence, ref mcn, tracks);

                            // Set tracks and go back
                            if (indexesChanged)
                            {
                                (_outputPlugin as IWritableOpticalImage).SetTracks(tracks.ToList());
                                i--;
                            }
                        }
                        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();
        }
Beispiel #7
0
        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;
            }
        }
Beispiel #8
0
        bool ScsiReadBlocks(out byte[] buffer, ulong block, uint count, out double duration)
        {
            bool sense;

            byte[] senseBuf;
            buffer   = null;
            duration = 0;

            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 (read16)
                {
                    sense = dev.Read16(out buffer, out senseBuf, 0, false, true, false, block, LogicalBlockSize, 0,
                                       count, false, 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 (read10)
                {
                    sense = dev.Read10(out buffer, out senseBuf, 0, false, true, false, false, (uint)block,
                                       LogicalBlockSize, 0, (ushort)count, timeout, out duration);
                }
                else if (read6)
                {
                    sense = dev.Read6(out buffer, out senseBuf, (uint)block, LogicalBlockSize, (byte)count, timeout,
                                      out duration);
                }
                else
                {
                    return(true);
                }
            }

            if (!sense && !dev.Error)
            {
                return(false);
            }

            DicConsole.DebugWriteLine("SCSI Reader", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
            return(sense);
        }
Beispiel #9
0
        static void ReadCdDa(string devPath, Device dev)
        {
            uint   address = 0;
            uint   length  = 1;
            string strDev;
            int    item;

parameters:

            while (true)
            {
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("Parameters for READ CD-DA command:");
                AaruConsole.WriteLine("LBA: {0}", address);
                AaruConsole.WriteLine("Will transfer {0} sectors", length);
                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 NEC vendor 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 NEC vendor commands menu...");

                    return;

                case 1:
                    AaruConsole.Write("Logical Block Address?: ");
                    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;
                    }

                    AaruConsole.Write("How many sectors to transfer?: ");
                    strDev = System.Console.ReadLine();

                    if (!uint.TryParse(strDev, out length))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        length = 1;
                        System.Console.ReadKey();
                    }

                    break;

                case 2: goto start;
                }
            }

start:
            System.Console.Clear();

            bool sense = dev.NecReadCdDa(out byte[] buffer, out byte[] senseBuffer, address, length, dev.Timeout,
                                         out double duration);

menu:
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Sending READ CD-DA 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("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null");
            AaruConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer));
            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print buffer.");
            AaruConsole.WriteLine("2.- Print sense buffer.");
            AaruConsole.WriteLine("3.- Decode sense buffer.");
            AaruConsole.WriteLine("4.- Send command again.");
            AaruConsole.WriteLine("5.- Change parameters.");
            AaruConsole.WriteLine("0.- Return to NEC vendor 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 NEC vendor commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ CD-DA 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 CD-DA 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 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ CD-DA decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);

                goto menu;

            case 4: goto start;

            case 5: goto parameters;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
        static void ReadDvdRaw(string devPath, Device dev)
        {
            uint   count = 1;
            uint   lba   = 0;
            string strDev;
            int    item;

parameters:
            while (true)
            {
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("Parameters for READ DVD (RAW) command:");
                DicConsole.WriteLine("LBA: {0}", lba);
                DicConsole.WriteLine("Count: {0}", count);
                DicConsole.WriteLine();
                DicConsole.WriteLine("Choose what to do:");
                DicConsole.WriteLine("1.- Change parameters.");
                DicConsole.WriteLine("2.- Send command with these parameters.");
                DicConsole.WriteLine("0.- Return to HL-DT-ST vendor commands menu.");

                strDev = System.Console.ReadLine();
                if (!int.TryParse(strDev, out item))
                {
                    DicConsole.WriteLine("Not a number. Press any key to continue...");
                    System.Console.ReadKey();
                    continue;
                }

                switch (item)
                {
                case 0:
                    DicConsole.WriteLine("Returning to HL-DT-ST vendor commands menu...");
                    return;

                case 1:
                    DicConsole.Write("How many sectors?: ");
                    strDev = System.Console.ReadLine();
                    if (!uint.TryParse(strDev, out count))
                    {
                        DicConsole.WriteLine("Not a numbr. Press any key to continue...");
                        count = 1;
                        System.Console.ReadKey();
                        continue;
                    }

                    DicConsole.Write("LBA?: ");
                    strDev = System.Console.ReadLine();
                    if (!uint.TryParse(strDev, out lba))
                    {
                        DicConsole.WriteLine("Not a number. Press any key to continue...");
                        lba = 0;
                        System.Console.ReadKey();
                    }

                    break;

                case 2: goto start;
                }
            }

start:
            System.Console.Clear();
            bool sense = dev.HlDtStReadRawDvd(out byte[] buffer, out byte[] senseBuffer, lba, count, dev.Timeout,
                                              out double duration);

menu:
            DicConsole.WriteLine("Device: {0}", devPath);
            DicConsole.WriteLine("Sending READ DVD (RAW) to the device:");
            DicConsole.WriteLine("Command took {0} ms.", duration);
            DicConsole.WriteLine("Sense is {0}.", sense);
            DicConsole.WriteLine("Buffer is {0} bytes.", buffer?.Length.ToString() ?? "null");
            DicConsole.WriteLine("Buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(buffer));
            DicConsole.WriteLine("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null");
            DicConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer));
            DicConsole.WriteLine();
            DicConsole.WriteLine("Choose what to do:");
            DicConsole.WriteLine("1.- Print buffer.");
            DicConsole.WriteLine("2.- Print sense buffer.");
            DicConsole.WriteLine("3.- Decode sense buffer.");
            DicConsole.WriteLine("4.- Send command again.");
            DicConsole.WriteLine("5.- Change parameters.");
            DicConsole.WriteLine("0.- Return to HL-DT-ST vendor commands menu.");
            DicConsole.Write("Choose: ");

            strDev = System.Console.ReadLine();
            if (!int.TryParse(strDev, out item))
            {
                DicConsole.WriteLine("Not a number. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                goto menu;
            }

            switch (item)
            {
            case 0:
                DicConsole.WriteLine("Returning to HL-DT-ST vendor commands menu...");
                return;

            case 1:
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("READ DVD (RAW) response:");
                if (buffer != null)
                {
                    PrintHex.PrintHexArray(buffer, 64);
                }
                DicConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                goto menu;

            case 2:
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("READ DVD (RAW) sense:");
                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(senseBuffer, 64);
                }
                DicConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                goto menu;

            case 3:
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("READ DVD (RAW) decoded sense:");
                DicConsole.Write("{0}", Sense.PrettifySense(senseBuffer));
                DicConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                goto menu;

            case 4: goto start;

            case 5: goto parameters;

            default:
                DicConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                goto menu;
            }
        }
Beispiel #11
0
        // TODO: Get cartridge serial number from Certance vendor EVPD
        /// <summary>Dumps a SCSI Block Commands device or a Reduced Block Commands devices</summary>
        void Scsi()
        {
            int resets = 0;

            if (_dev.IsRemovable)
            {
                InitProgress?.Invoke();
deviceGotReset:
                bool sense = _dev.ScsiTestUnitReady(out byte[] senseBuf, _dev.Timeout, out _);

                if (sense)
                {
                    FixedSense?decSense = Sense.DecodeFixed(senseBuf);

                    if (decSense.HasValue)
                    {
                        ErrorMessage?.
                        Invoke($"Device not ready. Sense {decSense.Value.SenseKey} ASC {decSense.Value.ASC:X2}h ASCQ {decSense.Value.ASCQ:X2}h");

                        _dumpLog.WriteLine("Device not ready. Sense {0} ASC {1:X2}h ASCQ {2:X2}h",
                                           decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);

                        // Just retry, for 5 times
                        if (decSense.Value.ASC == 0x29)
                        {
                            resets++;

                            if (resets < 5)
                            {
                                goto deviceGotReset;
                            }
                        }

                        if (decSense.Value.ASC == 0x3A)
                        {
                            int leftRetries = 5;

                            while (leftRetries > 0)
                            {
                                PulseProgress?.Invoke("Waiting for drive to become ready");
                                Thread.Sleep(2000);
                                sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _);

                                if (!sense)
                                {
                                    break;
                                }

                                decSense = Sense.DecodeFixed(senseBuf);

                                if (decSense.HasValue)
                                {
                                    ErrorMessage?.
                                    Invoke($"Device not ready. Sense {decSense.Value.SenseKey} ASC {decSense.Value.ASC:X2}h ASCQ {decSense.Value.ASCQ:X2}h");

                                    _dumpLog.WriteLine("Device not ready. Sense {0} ASC {1:X2}h ASCQ {2:X2}h",
                                                       decSense.Value.SenseKey, decSense.Value.ASC,
                                                       decSense.Value.ASCQ);
                                }

                                leftRetries--;
                            }

                            if (sense)
                            {
                                StoppingErrorMessage?.Invoke("Please insert media in drive");

                                return;
                            }
                        }
                        else if (decSense.Value.ASC == 0x04 &&
                                 decSense.Value.ASCQ == 0x01)
                        {
                            int leftRetries = 50;

                            while (leftRetries > 0)
                            {
                                PulseProgress?.Invoke("Waiting for drive to become ready");
                                Thread.Sleep(2000);
                                sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _);

                                if (!sense)
                                {
                                    break;
                                }

                                decSense = Sense.DecodeFixed(senseBuf);

                                if (decSense.HasValue)
                                {
                                    ErrorMessage?.
                                    Invoke($"Device not ready. Sense {decSense.Value.SenseKey} ASC {decSense.Value.ASC:X2}h ASCQ {decSense.Value.ASCQ:X2}h");

                                    _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
                                                       decSense.Value.SenseKey, decSense.Value.ASC,
                                                       decSense.Value.ASCQ);
                                }

                                leftRetries--;
                            }

                            if (sense)
                            {
                                StoppingErrorMessage?.
                                Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}");

                                return;
                            }
                        }

                        /*else if (decSense.Value.ASC == 0x29 && decSense.Value.ASCQ == 0x00)
                         * {
                         *  if (!deviceReset)
                         *  {
                         *      deviceReset = true;
                         *      ErrorMessage?.Invoke("Device did reset, retrying...");
                         *      goto retryTestReady;
                         *  }
                         *
                         *  StoppingErrorMessage?.Invoke(string.Format("Error testing unit was ready:\n{0}",
                         *                               Decoders.SCSI.Sense.PrettifySense(senseBuf)));
                         *  return;
                         * }*/
                        // These should be trapped by the OS but seems in some cases they're not
                        else if (decSense.Value.ASC == 0x28)
                        {
                            int leftRetries = 10;

                            while (leftRetries > 0)
                            {
                                PulseProgress?.Invoke("Waiting for drive to become ready");
                                Thread.Sleep(2000);
                                sense = _dev.ScsiTestUnitReady(out senseBuf, _dev.Timeout, out _);

                                if (!sense)
                                {
                                    break;
                                }

                                decSense = Sense.DecodeFixed(senseBuf);

                                if (decSense.HasValue)
                                {
                                    ErrorMessage?.
                                    Invoke($"Device not ready. Sense {decSense.Value.SenseKey} ASC {decSense.Value.ASC:X2}h ASCQ {decSense.Value.ASCQ:X2}h");

                                    _dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
                                                       decSense.Value.SenseKey, decSense.Value.ASC,
                                                       decSense.Value.ASCQ);
                                }

                                leftRetries--;
                            }

                            if (sense)
                            {
                                StoppingErrorMessage?.
                                Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}");

                                return;
                            }
                        }
                        else
                        {
                            StoppingErrorMessage?.
                            Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}");

                            return;
                        }
                    }
                    else
                    {
                        StoppingErrorMessage?.Invoke("Unknown testing unit was ready.");

                        return;
                    }
                }

                EndProgress?.Invoke();
            }

            switch (_dev.ScsiType)
            {
            case PeripheralDeviceTypes.SequentialAccess:
                if (_dumpRaw)
                {
                    StoppingErrorMessage?.Invoke("Tapes cannot be dumped raw.");

                    return;
                }

                if (_outputPlugin is IWritableTapeImage)
                {
                    Ssc();
                }
                else
                {
                    StoppingErrorMessage?.
                    Invoke("The specified plugin does not support storing streaming tape images.");
                }

                return;

            case PeripheralDeviceTypes.MultiMediaDevice:
                if (_outputPlugin is IWritableOpticalImage)
                {
                    Mmc();
                }
                else
                {
                    StoppingErrorMessage?.
                    Invoke("The specified plugin does not support storing optical disc images.");
                }

                return;

            case PeripheralDeviceTypes.BridgingExpander
                when _dev.Model.StartsWith("MDM", StringComparison.InvariantCulture) ||
                _dev.Model.StartsWith("MDH", StringComparison.InvariantCulture):
                MiniDisc();

                break;

            default:
                Sbc(null, MediaType.Unknown, false);

                break;
            }
        }
Beispiel #12
0
        static void CheckGdromReadability(string devPath, Device dev)
        {
            string strDev;
            int    item;
            bool   tocIsNotBcd = false;
            bool   sense;

            byte[] buffer;
            byte[] senseBuffer;
            int    retries;

start:
            System.Console.Clear();

            AaruConsole.WriteLine("Ejecting disc...");

            dev.AllowMediumRemoval(out _, dev.Timeout, out _);
            dev.EjectTray(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please insert trap disc inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                FixedSense?decodedSense = Sense.DecodeFixed(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }

                Thread.Sleep(2000);
            } while(retries < 25);

            sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            FullTOC.CDFullTOC?decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            FullTOC.CDFullTOC toc = decodedToc.Value;

            FullTOC.TrackDataDescriptor leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (leadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            int min = 0, sec, frame;

            if (leadOutTrack.PMIN == 122)
            {
                tocIsNotBcd = true;
            }

            if (leadOutTrack.PMIN >= 0xA0 &&
                !tocIsNotBcd)
            {
                min += 90;
                leadOutTrack.PMIN -= 0x90;
            }

            if (tocIsNotBcd)
            {
                min   = leadOutTrack.PMIN;
                sec   = leadOutTrack.PSEC;
                frame = leadOutTrack.PFRAME;
            }
            else
            {
                min  += ((leadOutTrack.PMIN >> 4) * 10) + (leadOutTrack.PMIN & 0x0F);
                sec   = ((leadOutTrack.PSEC >> 4) * 10) + (leadOutTrack.PSEC & 0x0F);
                frame = ((leadOutTrack.PFRAME >> 4) * 10) + (leadOutTrack.PFRAME & 0x0F);
            }

            int sectors = ((min * 60 * 75) + (sec * 75) + frame) - 150;

            AaruConsole.WriteLine("Trap disc shows {0} sectors...", sectors);

            if (sectors < 450000)
            {
                AaruConsole.WriteLine("Trap disc doesn't have enough sectors...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            AaruConsole.WriteLine("Stopping motor...");

            dev.StopUnit(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please MANUALLY get the trap disc out and put the GD-ROM disc inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Waiting 5 seconds...");
            Thread.Sleep(5000);

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                FixedSense?decodedSense = Sense.DecodeFixed(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }
            } while(retries < 25);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            toc = decodedToc.Value;

            FullTOC.TrackDataDescriptor newLeadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (newLeadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            if (newLeadOutTrack.PMIN >= 0xA0 &&
                !tocIsNotBcd)
            {
                newLeadOutTrack.PMIN -= 0x90;
            }

            if (newLeadOutTrack.PMIN != leadOutTrack.PMIN ||
                newLeadOutTrack.PSEC != leadOutTrack.PSEC ||
                newLeadOutTrack.PFRAME != leadOutTrack.PFRAME)
            {
                AaruConsole.WriteLine("Lead-out has changed, this drive does not support hot swapping discs...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            dev.SetCdSpeed(out _, RotationalControl.PureCav, 170, 0, dev.Timeout, out _);

            AaruConsole.Write("Reading LBA 0... ");

            bool lba0Result = dev.ReadCd(out byte[] lba0Buffer, out byte[] lba0Sense, 0, 2352, 1,
                                         MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
                                         true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba0Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 0 as audio (scrambled)... ");

            bool lba0ScrambledResult = dev.ReadCd(out byte[] lba0ScrambledBuffer, out byte[] lba0ScrambledSense, 0,
                                                  2352, 1, MmcSectorTypes.Cdda, false, false, false,
                                                  MmcHeaderCodes.None, true, false, MmcErrorField.None,
                                                  MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba0ScrambledResult ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 100000... ");

            bool lba100000Result = dev.ReadCd(out byte[] lba100000Buffer, out byte[] lba100000Sense, 100000, 2352, 1,
                                              MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                              true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba100000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 50000... ");

            bool lba50000Result = dev.ReadCd(out byte[] lba50000Buffer, out byte[] lba50000Sense, 50000, 2352, 1,
                                             MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                             true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba50000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 450000... ");

            bool lba450000Result = dev.ReadCd(out byte[] lba450000Buffer, out byte[] lba450000Sense, 450000, 2352, 1,
                                              MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                              true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba450000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 400000... ");

            bool lba400000Result = dev.ReadCd(out byte[] lba400000Buffer, out byte[] lba400000Sense, 400000, 2352, 1,
                                              MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                              true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba400000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 45000... ");

            bool lba45000Result = dev.ReadCd(out byte[] lba45000Buffer, out byte[] lba45000Sense, 45000, 2352, 1,
                                             MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                             true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba45000Result ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA 44990... ");

            bool lba44990Result = dev.ReadCd(out byte[] lba44990Buffer, out byte[] lba44990Sense, 44990, 2352, 1,
                                             MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders,
                                             true, true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(lba44990Result ? "FAIL!" : "Success!");

menu:
            System.Console.Clear();
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Device {0} read HD area.", lba450000Result ? "cannot" : "can");

            AaruConsole.WriteLine("LBA 0 sense is {0}, buffer is {1}, sense buffer is {2}.", lba0Result,
                                  lba0Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba0Buffer)
                                          ? "empty"
                                          : $"{lba0Buffer.Length} bytes", lba0Sense is null
                                                                              ? "null"
                                                                              : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba0Sense)
                                                                                  ? "empty"
                                                                                  : $"{lba0Sense.Length}");

            AaruConsole.WriteLine("LBA 0 (scrambled) sense is {0}, buffer is {1}, sense buffer is {2}.",
                                  lba0ScrambledResult, lba0ScrambledBuffer is null
                                                           ? "null"
                                                           : ArrayHelpers.ArrayIsNullOrEmpty(lba0ScrambledBuffer)
                                                               ? "empty"
                                                               : $"{lba0ScrambledBuffer.Length} bytes",
                                  lba0ScrambledSense is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba0ScrambledSense)
                                          ? "empty"
                                          : $"{lba0ScrambledSense.Length}");

            AaruConsole.WriteLine("LBA 44990 sense is {0}, buffer is {1}, sense buffer is {2}.", lba44990Result,
                                  lba44990Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba44990Buffer)
                                          ? "empty"
                                          : $"{lba44990Buffer.Length} bytes", lba44990Sense is null
                                                                                  ? "null"
                                                                                  : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba44990Sense)
                                                                                      ? "empty"
                                                                                      : $"{lba44990Sense.Length}");

            AaruConsole.WriteLine("LBA 45000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba45000Result,
                                  lba45000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba45000Buffer)
                                          ? "empty"
                                          : $"{lba45000Buffer.Length} bytes", lba45000Sense is null
                                                                                  ? "null"
                                                                                  : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba45000Sense)
                                                                                      ? "empty"
                                                                                      : $"{lba45000Sense.Length}");

            AaruConsole.WriteLine("LBA 50000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba50000Result,
                                  lba50000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba50000Buffer)
                                          ? "empty"
                                          : $"{lba50000Buffer.Length} bytes", lba50000Sense is null
                                                                                  ? "null"
                                                                                  : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba50000Sense)
                                                                                      ? "empty"
                                                                                      : $"{lba50000Sense.Length}");

            AaruConsole.WriteLine("LBA 100000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba100000Result,
                                  lba100000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba100000Buffer)
                                          ? "empty"
                                          : $"{lba100000Buffer.Length} bytes", lba100000Sense is null
                                                                                   ? "null"
                                                                                   : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba100000Sense)
                                                                                       ? "empty"
                                                                                       : $"{lba100000Sense.Length}");

            AaruConsole.WriteLine("LBA 400000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba400000Result,
                                  lba400000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba400000Buffer)
                                          ? "empty"
                                          : $"{lba400000Buffer.Length} bytes", lba400000Sense is null
                                                                                   ? "null"
                                                                                   : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba400000Sense)
                                                                                       ? "empty"
                                                                                       : $"{lba400000Sense.Length}");

            AaruConsole.WriteLine("LBA 450000 sense is {0}, buffer is {1}, sense buffer is {2}.", lba450000Result,
                                  lba450000Buffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(lba450000Buffer)
                                          ? "empty"
                                          : $"{lba450000Buffer.Length} bytes", lba450000Sense is null
                                                                                   ? "null"
                                                                                   : ArrayHelpers.
                                  ArrayIsNullOrEmpty(lba450000Sense)
                                                                                       ? "empty"
                                                                                       : $"{lba450000Sense.Length}");

            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print LBA 0 buffer.");
            AaruConsole.WriteLine("2.- Print LBA 0 sense buffer.");
            AaruConsole.WriteLine("3.- Decode LBA 0 sense buffer.");
            AaruConsole.WriteLine("4.- Print LBA 0 (scrambled) buffer.");
            AaruConsole.WriteLine("5.- Print LBA 0 (scrambled) sense buffer.");
            AaruConsole.WriteLine("6.- Decode LBA 0 (scrambled) sense buffer.");
            AaruConsole.WriteLine("7.- Print LBA 44990 buffer.");
            AaruConsole.WriteLine("8.- Print LBA 44990 sense buffer.");
            AaruConsole.WriteLine("9.- Decode LBA 44990 sense buffer.");
            AaruConsole.WriteLine("10.- Print LBA 45000 buffer.");
            AaruConsole.WriteLine("11.- Print LBA 45000 sense buffer.");
            AaruConsole.WriteLine("12.- Decode LBA 45000 sense buffer.");
            AaruConsole.WriteLine("13.- Print LBA 50000 buffer.");
            AaruConsole.WriteLine("14.- Print LBA 50000 sense buffer.");
            AaruConsole.WriteLine("15.- Decode LBA 50000 sense buffer.");
            AaruConsole.WriteLine("16.- Print LBA 100000 buffer.");
            AaruConsole.WriteLine("17.- Print LBA 100000 sense buffer.");
            AaruConsole.WriteLine("18.- Decode LBA 100000 sense buffer.");
            AaruConsole.WriteLine("19.- Print LBA 400000 buffer.");
            AaruConsole.WriteLine("20.- Print LBA 400000 sense buffer.");
            AaruConsole.WriteLine("21.- Decode LBA 400000 sense buffer.");
            AaruConsole.WriteLine("22.- Print LBA 450000 buffer.");
            AaruConsole.WriteLine("23.- Print LBA 450000 sense buffer.");
            AaruConsole.WriteLine("24.- Decode LBA 450000 sense buffer.");
            AaruConsole.WriteLine("25.- Send command again.");
            AaruConsole.WriteLine("0.- Return to special SCSI MultiMedia 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 special SCSI MultiMedia Commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba0Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 2:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba0Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba0Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 4:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 (scrambled) response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba0ScrambledBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 5:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 (scrambled) sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba0ScrambledSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 6:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 0 (scrambled) decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba0ScrambledSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 7:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 44990 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba44990Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 8:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 44990 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba44990Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 9:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 44990 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba44990Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 10:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 45000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba45000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 11:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 45000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba45000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 12:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 45000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba45000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 13:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 50000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba50000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 14:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 50000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba50000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 15:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 50000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba50000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 16:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 100000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba100000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 17:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 100000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba100000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 18:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 100000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba100000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 19:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 400000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba400000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 20:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 400000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba400000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 21:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 400000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba400000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 22:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 450000 response:");

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(lba450000Buffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 23:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 450000 sense:");

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(lba450000Sense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 24:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA 450000 decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(lba450000Sense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 25: goto start;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
Beispiel #13
0
        // TODO: Get cartridge serial number from Certance vendor EVPD
        /// <summary>
        ///     Dumps a SCSI Block Commands device or a Reduced Block Commands devices
        /// </summary>
        /// <param name="dev">Device</param>
        /// <param name="devicePath">Path to the device</param>
        /// <param name="outputPrefix">Prefix for output data files</param>
        /// <param name="outputPlugin">Plugin for output file</param>
        /// <param name="retryPasses">How many times to retry</param>
        /// <param name="force">Force to continue dump whenever possible</param>
        /// <param name="dumpRaw">Dump long or scrambled sectors</param>
        /// <param name="persistent">Store whatever data the drive returned on error</param>
        /// <param name="stopOnError">Stop dump on first error</param>
        /// <param name="resume">Information for dump resuming</param>
        /// <param name="dumpLog">Dump logger</param>
        /// <param name="encoding">Encoding to use when analyzing dump</param>
        /// <param name="dumpLeadIn">Try to read and dump as much Lead-in as possible</param>
        /// <param name="outputPath">Path to output file</param>
        /// <param name="formatOptions">Formats to pass to output file plugin</param>
        /// <exception cref="ArgumentException">If you asked to dump long sectors from a SCSI Streaming device</exception>
        public static void Dump(Device dev, string devicePath,
                                IWritableImage outputPlugin, ushort retryPasses,
                                bool force, bool dumpRaw,
                                bool persistent, bool stopOnError, ref Resume resume,
                                ref DumpLog dumpLog, bool dumpLeadIn,
                                Encoding encoding, string outputPrefix,
                                string outputPath, Dictionary <string, string> formatOptions,
                                CICMMetadataType preSidecar, uint skip, bool nometadata,
                                bool notrim)
        {
            MediaType dskType = MediaType.Unknown;
            int       resets  = 0;

            if (dev.IsRemovable)
            {
deviceGotReset:
                bool sense = dev.ScsiTestUnitReady(out byte[] senseBuf, dev.Timeout, out _);
                if (sense)
                {
                    FixedSense?decSense = Sense.DecodeFixed(senseBuf);
                    if (decSense.HasValue)
                    {
                        dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
                                          decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);

                        // Just retry, for 5 times
                        if (decSense.Value.ASC == 0x29)
                        {
                            resets++;
                            if (resets < 5)
                            {
                                goto deviceGotReset;
                            }
                        }

                        if (decSense.Value.ASC == 0x3A)
                        {
                            int leftRetries = 5;
                            while (leftRetries > 0)
                            {
                                DicConsole.WriteLine("\rWaiting for drive to become ready");
                                Thread.Sleep(2000);
                                sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _);
                                if (!sense)
                                {
                                    break;
                                }

                                decSense = Sense.DecodeFixed(senseBuf);
                                if (decSense.HasValue)
                                {
                                    dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
                                                      decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
                                }
                                leftRetries--;
                            }

                            if (sense)
                            {
                                DicConsole.ErrorWriteLine("Please insert media in drive");
                                return;
                            }
                        }
                        else if (decSense.Value.ASC == 0x04 && decSense.Value.ASCQ == 0x01)
                        {
                            int leftRetries = 10;
                            while (leftRetries > 0)
                            {
                                DicConsole.WriteLine("\rWaiting for drive to become ready");
                                Thread.Sleep(2000);
                                sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _);
                                if (!sense)
                                {
                                    break;
                                }

                                decSense = Sense.DecodeFixed(senseBuf);
                                if (decSense.HasValue)
                                {
                                    dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
                                                      decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
                                }
                                leftRetries--;
                            }

                            if (sense)
                            {
                                DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}",
                                                          Sense.PrettifySense(senseBuf));
                                return;
                            }
                        }

                        /*else if (decSense.Value.ASC == 0x29 && decSense.Value.ASCQ == 0x00)
                         * {
                         *  if (!deviceReset)
                         *  {
                         *      deviceReset = true;
                         *      DicConsole.ErrorWriteLine("Device did reset, retrying...");
                         *      goto retryTestReady;
                         *  }
                         *
                         *  DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf));
                         *  return;
                         * }*/
                        // These should be trapped by the OS but seems in some cases they're not
                        else if (decSense.Value.ASC == 0x28)
                        {
                            int leftRetries = 10;
                            while (leftRetries > 0)
                            {
                                DicConsole.WriteLine("\rWaiting for drive to become ready");
                                Thread.Sleep(2000);
                                sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _);
                                if (!sense)
                                {
                                    break;
                                }

                                decSense = Sense.DecodeFixed(senseBuf);
                                if (decSense.HasValue)
                                {
                                    dumpLog.WriteLine("Device not ready. Sense {0}h ASC {1:X2}h ASCQ {2:X2}h",
                                                      decSense.Value.SenseKey, decSense.Value.ASC, decSense.Value.ASCQ);
                                }
                                leftRetries--;
                            }

                            if (sense)
                            {
                                DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}",
                                                          Sense.PrettifySense(senseBuf));
                                return;
                            }
                        }
                        else
                        {
                            DicConsole.ErrorWriteLine("Error testing unit was ready:\n{0}",
                                                      Sense.PrettifySense(senseBuf));
                            return;
                        }
                    }
                    else
                    {
                        DicConsole.ErrorWriteLine("Unknown testing unit was ready.");
                        return;
                    }
                }
            }

            switch (dev.ScsiType)
            {
            case PeripheralDeviceTypes.SequentialAccess:
                if (dumpRaw)
                {
                    throw new ArgumentException("Tapes cannot be dumped raw.");
                }

                Ssc.Dump(dev, outputPrefix, devicePath, ref resume, ref dumpLog, preSidecar);
                return;

            case PeripheralDeviceTypes.MultiMediaDevice:
                Mmc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError,
                         ref dskType, ref resume, ref dumpLog, dumpLeadIn, encoding, outputPrefix, outputPath,
                         formatOptions, preSidecar, skip, nometadata, notrim);
                return;

            default:
                Sbc.Dump(dev, devicePath, outputPlugin, retryPasses, force, dumpRaw, persistent, stopOnError, null,
                         ref dskType, false, ref resume, ref dumpLog, encoding, outputPrefix, outputPath,
                         formatOptions, preSidecar, skip, nometadata, notrim);
                break;
            }
        }
Beispiel #14
0
        static void ReadLeadOutUsingTrapDisc(string devPath, Device dev)
        {
            string strDev;
            int    item;
            bool   tocIsNotBcd = false;
            bool   sense;

            byte[] buffer;
            byte[] senseBuffer;
            int    retries;

start:
            System.Console.Clear();

            AaruConsole.WriteLine("Ejecting disc...");

            dev.AllowMediumRemoval(out _, dev.Timeout, out _);
            dev.EjectTray(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please insert a data only disc inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                FixedSense?decodedSense = Sense.DecodeFixed(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }

                Thread.Sleep(2000);
            } while(retries < 25);

            sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            FullTOC.CDFullTOC?decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            FullTOC.CDFullTOC toc = decodedToc.Value;

            FullTOC.TrackDataDescriptor leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (leadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            int min   = ((leadOutTrack.PMIN >> 4) * 10) + (leadOutTrack.PMIN & 0x0F);
            int sec   = ((leadOutTrack.PSEC >> 4) * 10) + (leadOutTrack.PSEC & 0x0F);
            int frame = ((leadOutTrack.PFRAME >> 4) * 10) + (leadOutTrack.PFRAME & 0x0F);

            int sectors = ((min * 60 * 75) + (sec * 75) + frame) - 150;

            AaruConsole.WriteLine("Data disc shows {0} sectors...", sectors);

            AaruConsole.WriteLine("Ejecting disc...");

            dev.AllowMediumRemoval(out _, dev.Timeout, out _);
            dev.EjectTray(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please insert the trap disc inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ScsiTestUnitReady(out senseBuffer, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                FixedSense?decodedSense = Sense.DecodeFixed(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }

                Thread.Sleep(2000);
            } while(retries < 25);

            sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            toc = decodedToc.Value;

            leadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (leadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            min = 0;

            if (leadOutTrack.PMIN == 122)
            {
                tocIsNotBcd = true;
            }

            if (leadOutTrack.PMIN >= 0xA0 &&
                !tocIsNotBcd)
            {
                min += 90;
                leadOutTrack.PMIN -= 0x90;
            }

            if (tocIsNotBcd)
            {
                min   = leadOutTrack.PMIN;
                sec   = leadOutTrack.PSEC;
                frame = leadOutTrack.PFRAME;
            }
            else
            {
                min  += ((leadOutTrack.PMIN >> 4) * 10) + (leadOutTrack.PMIN & 0x0F);
                sec   = ((leadOutTrack.PSEC >> 4) * 10) + (leadOutTrack.PSEC & 0x0F);
                frame = ((leadOutTrack.PFRAME >> 4) * 10) + (leadOutTrack.PFRAME & 0x0F);
            }

            int trapSectors = ((min * 60 * 75) + (sec * 75) + frame) - 150;

            AaruConsole.WriteLine("Trap disc shows {0} sectors...", trapSectors);

            if (trapSectors < sectors + 100)
            {
                AaruConsole.WriteLine("Trap disc doesn't have enough sectors...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            AaruConsole.WriteLine("Stopping motor...");

            dev.StopUnit(out _, dev.Timeout, out _);

            AaruConsole.WriteLine("Please MANUALLY get the trap disc out and put the data disc back inside...");
            AaruConsole.WriteLine("Press any key to continue...");
            System.Console.ReadLine();

            AaruConsole.WriteLine("Waiting 5 seconds...");
            Thread.Sleep(5000);

            AaruConsole.WriteLine("Sending READ FULL TOC to the device...");

            retries = 0;

            do
            {
                retries++;
                sense = dev.ReadRawToc(out buffer, out senseBuffer, 1, dev.Timeout, out _);

                if (!sense)
                {
                    break;
                }

                FixedSense?decodedSense = Sense.DecodeFixed(senseBuffer);

                if (decodedSense.Value.ASC != 0x04)
                {
                    break;
                }

                if (decodedSense.Value.ASCQ != 0x01)
                {
                    break;
                }
            } while(retries < 25);

            if (sense)
            {
                AaruConsole.WriteLine("READ FULL TOC failed...");
                AaruConsole.WriteLine("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            decodedToc = FullTOC.Decode(buffer);

            if (decodedToc is null)
            {
                AaruConsole.WriteLine("Could not decode TOC...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            toc = decodedToc.Value;

            FullTOC.TrackDataDescriptor newLeadOutTrack = toc.TrackDescriptors.FirstOrDefault(t => t.POINT == 0xA2);

            if (newLeadOutTrack.POINT != 0xA2)
            {
                AaruConsole.WriteLine("Cannot find lead-out...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            if (newLeadOutTrack.PMIN >= 0xA0 &&
                !tocIsNotBcd)
            {
                newLeadOutTrack.PMIN -= 0x90;
            }

            if (newLeadOutTrack.PMIN != leadOutTrack.PMIN ||
                newLeadOutTrack.PSEC != leadOutTrack.PSEC ||
                newLeadOutTrack.PFRAME != leadOutTrack.PFRAME)
            {
                AaruConsole.WriteLine("Lead-out has changed, this drive does not support hot swapping discs...");
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadLine();

                return;
            }

            AaruConsole.Write("Reading LBA {0}... ", sectors + 5);

            bool dataResult = dev.ReadCd(out byte[] dataBuffer, out byte[] dataSense, (uint)(sectors + 5), 2352, 1,
                                         MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
                                         true, MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out _);

            AaruConsole.WriteLine(dataResult ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA {0} as audio (scrambled)... ", sectors + 5);

            bool scrambledResult = dev.ReadCd(out byte[] scrambledBuffer, out byte[] scrambledSense,
                                              (uint)(sectors + 5), 2352, 1, MmcSectorTypes.Cdda, false, false, false,
                                              MmcHeaderCodes.None, true, false, MmcErrorField.None, MmcSubchannel.None,
                                              dev.Timeout, out _);

            AaruConsole.WriteLine(scrambledResult ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA {0}'s PQ subchannel... ", sectors + 5);

            bool pqResult = dev.ReadCd(out byte[] pqBuffer, out byte[] pqSense, (uint)(sectors + 5), 16, 1,
                                       MmcSectorTypes.AllTypes, false, false, false, MmcHeaderCodes.None, false, false,
                                       MmcErrorField.None, MmcSubchannel.Q16, dev.Timeout, out _);

            if (pqResult)
            {
                pqResult = dev.ReadCd(out pqBuffer, out pqSense, (uint)(sectors + 5), 16, 1, MmcSectorTypes.AllTypes,
                                      false, false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None,
                                      MmcSubchannel.Q16, dev.Timeout, out _);
            }

            AaruConsole.WriteLine(pqResult ? "FAIL!" : "Success!");

            AaruConsole.Write("Reading LBA {0}'s PQ subchannel... ", sectors + 5);

            bool rwResult = dev.ReadCd(out byte[] rwBuffer, out byte[] rwSense, (uint)(sectors + 5), 16, 1,
                                       MmcSectorTypes.AllTypes, false, false, false, MmcHeaderCodes.None, false, false,
                                       MmcErrorField.None, MmcSubchannel.Rw, dev.Timeout, out _);

            if (rwResult)
            {
                rwResult = dev.ReadCd(out rwBuffer, out rwSense, (uint)(sectors + 5), 16, 1, MmcSectorTypes.Cdda, false,
                                      false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None,
                                      MmcSubchannel.Rw, dev.Timeout, out _);
            }

            AaruConsole.WriteLine(pqResult ? "FAIL!" : "Success!");

menu:
            System.Console.Clear();
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Device {0} read Lead-Out.", dataResult && scrambledResult ? "cannot" : "can");

            AaruConsole.WriteLine("LBA {0} sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5, dataResult,
                                  dataBuffer is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(dataBuffer)
                                          ? "empty"
                                          : $"{dataBuffer.Length} bytes", dataSense is null
                                                                              ? "null"
                                                                              : ArrayHelpers.
                                  ArrayIsNullOrEmpty(dataSense)
                                                                                  ? "empty"
                                                                                  : $"{dataSense.Length}");

            AaruConsole.WriteLine("LBA {0} (scrambled) sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5,
                                  scrambledResult, scrambledBuffer is null
                                                       ? "null"
                                                       : ArrayHelpers.ArrayIsNullOrEmpty(scrambledBuffer)
                                                           ? "empty"
                                                           : $"{scrambledBuffer.Length} bytes", scrambledSense is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(scrambledSense)
                                          ? "empty"
                                          : $"{scrambledSense.Length}");

            AaruConsole.WriteLine("LBA {0}'s PQ sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5,
                                  pqResult, pqBuffer is null
                                                ? "null"
                                                : ArrayHelpers.ArrayIsNullOrEmpty(pqBuffer)
                                                    ? "empty"
                                                    : $"{pqBuffer.Length} bytes", pqSense is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(pqSense)
                                          ? "empty"
                                          : $"{pqSense.Length}");

            AaruConsole.WriteLine("LBA {0}'s RW sense is {1}, buffer is {2}, sense buffer is {3}.", sectors + 5,
                                  rwResult, rwBuffer is null
                                                ? "null"
                                                : ArrayHelpers.ArrayIsNullOrEmpty(rwBuffer)
                                                    ? "empty"
                                                    : $"{rwBuffer.Length} bytes", rwSense is null
                                      ? "null"
                                      : ArrayHelpers.ArrayIsNullOrEmpty(rwSense)
                                          ? "empty"
                                          : $"{rwSense.Length}");

            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print LBA {0} buffer.", sectors + 5);
            AaruConsole.WriteLine("2.- Print LBA {0} sense buffer.", sectors + 5);
            AaruConsole.WriteLine("3.- Decode LBA {0} sense buffer.", sectors + 5);
            AaruConsole.WriteLine("4.- Print LBA {0} (scrambled) buffer.", sectors + 5);
            AaruConsole.WriteLine("5.- Print LBA {0} (scrambled) sense buffer.", sectors + 5);
            AaruConsole.WriteLine("6.- Decode LBA {0} (scrambled) sense buffer.", sectors + 5);
            AaruConsole.WriteLine("7.- Print LBA {0}'s PQ buffer.", sectors + 5);
            AaruConsole.WriteLine("8.- Print LBA {0}'s PQ sense buffer.", sectors + 5);
            AaruConsole.WriteLine("9.- Decode LBA {0}'s PQ sense buffer.", sectors + 5);
            AaruConsole.WriteLine("10.- Print LBA {0}'s RW buffer.", sectors + 5);
            AaruConsole.WriteLine("11.- Print LBA {0}'s RW sense buffer.", sectors + 5);
            AaruConsole.WriteLine("12.- Decode LBA {0}'s RW sense buffer.", sectors + 5);
            AaruConsole.WriteLine("13.- Send command again.");
            AaruConsole.WriteLine("0.- Return to special SCSI MultiMedia 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 special SCSI MultiMedia Commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} response:", sectors + 5);

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(dataBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 2:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} sense:", sectors + 5);

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(dataSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} decoded sense:", sectors + 5);
                AaruConsole.Write("{0}", Sense.PrettifySense(dataSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 4:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} (scrambled) response:", sectors + 5);

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(scrambledBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 5:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} (scrambled) sense:", sectors + 5);

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(scrambledSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 6:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA {0} (scrambled) decoded sense:", sectors + 5);
                AaruConsole.Write("{0}", Sense.PrettifySense(scrambledSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 7:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's PQ {0} response:", sectors + 5);

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(pqBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 8:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's PQ {0} sense:", sectors + 5);

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(pqSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 9:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's PQ {0} decoded sense:", sectors + 5);
                AaruConsole.Write("{0}", Sense.PrettifySense(pqSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 10:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's RW {0} response:", sectors + 5);

                if (buffer != null)
                {
                    PrintHex.PrintHexArray(rwBuffer, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 11:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's RW {0} sense:", sectors + 5);

                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(rwSense, 64);
                }

                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 12:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("LBA's RW {0} decoded sense:", sectors + 5);
                AaruConsole.Write("{0}", Sense.PrettifySense(rwSense));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();

                goto menu;

            case 13: goto start;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
Beispiel #15
0
        static void Read10(string devPath, Device dev, bool readlong)
        {
            uint   lba       = 0;
            uint   blockSize = 512;
            byte   count     = 1;
            bool   noDma     = false;
            string strDev;
            int    item;

parameters:

            while (true)
            {
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("Parameters for READ {0}(10) command:", readlong ? "LONG " : "");
                AaruConsole.WriteLine("LBA: {0}", lba);
                AaruConsole.WriteLine("{0} blocks to read", count == 0 ? 256 : count);
                AaruConsole.WriteLine("{0} bytes expected per block", blockSize);
                AaruConsole.WriteLine("Inhibit DMA?: {0}", noDma);
                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 SyQuest vendor 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 SyQuest vendor commands menu...");

                    return;

                case 1:
                    AaruConsole.Write("LBA?: ");
                    strDev = System.Console.ReadLine();

                    if (!uint.TryParse(strDev, out lba))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        lba = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Blocks to read (0 for 256 blocks)?: ");
                    strDev = System.Console.ReadLine();

                    if (!byte.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 per 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();

                        continue;
                    }

                    AaruConsole.Write("Inhibit DMA?: ");
                    strDev = System.Console.ReadLine();

                    if (!bool.TryParse(strDev, out noDma))
                    {
                        AaruConsole.WriteLine("Not a boolean. Press any key to continue...");
                        noDma = false;
                        System.Console.ReadKey();
                    }

                    break;

                case 2: goto start;
                }
            }

start:
            System.Console.Clear();

            bool sense = dev.SyQuestRead10(out byte[] buffer, out byte[] senseBuffer, lba, blockSize, count, noDma,
                                           readlong, dev.Timeout, out double duration);

menu:
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Sending READ {0}(10) to the device:", readlong ? "LONG " : "");
            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("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null");
            AaruConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer));
            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print buffer.");
            AaruConsole.WriteLine("2.- Print sense buffer.");
            AaruConsole.WriteLine("3.- Decode sense buffer.");
            AaruConsole.WriteLine("4.- Send command again.");
            AaruConsole.WriteLine("5.- Change parameters.");
            AaruConsole.WriteLine("0.- Return to SyQuest vendor 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 SyQuest vendor commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ {0}(10) response:", readlong ? "LONG " : "");

                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}(10) sense:", readlong ? "LONG " : "");

                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 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ {0}(10) decoded sense:", readlong ? "LONG " : "");
                AaruConsole.Write("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);

                goto menu;

            case 4: goto start;

            case 5: goto parameters;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
Beispiel #16
0
        /// <summary>Register an SCSI error after trying to read</summary>
        /// <param name="block">Starting block</param>
        /// <param name="osError"><c>true</c> if operating system returned an error status instead of the device</param>
        /// <param name="errno">Operating system error number</param>
        /// <param name="senseBuffer">REQUEST SENSE response buffer</param>
        public void WriteLine(ulong block, bool osError, int errno, byte[] senseBuffer)
        {
            if (osError)
            {
                _logSw.WriteLine("SCSI reading LBA {0} operating system error: {1}.", block, errno);
                _logSw.Flush();

                if (senseBuffer is null ||
                    senseBuffer.Length == 0 ||
                    senseBuffer.All(s => s == 0))
                {
                    return;
                }
            }

            FixedSense?     decodedFixedSense      = Sense.DecodeFixed(senseBuffer);
            DescriptorSense?decodedDescriptorSense = Sense.DecodeDescriptor(senseBuffer);
            string          prettySense            = Sense.PrettifySense(senseBuffer);
            string          hexSense = string.Join(' ', senseBuffer.Select(b => $"{b:X2}"));

            if (decodedFixedSense.HasValue)
            {
                if (prettySense != null)
                {
                    if (prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal))
                    {
                        prettySense = prettySense.Substring(12);
                    }

                    if (prettySense.EndsWith('\n'))
                    {
                        prettySense = prettySense.Substring(0, prettySense.Length - 1);
                    }

                    prettySense = prettySense.Replace("\n", " - ");

                    _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}, {5}.", block,
                                     decodedFixedSense?.SenseKey, decodedFixedSense?.ASC, decodedFixedSense?.ASCQ,
                                     hexSense, prettySense);
                }
                else
                {
                    _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}.", block,
                                     decodedFixedSense?.SenseKey, decodedFixedSense?.ASC, decodedFixedSense?.ASCQ,
                                     hexSense);
                }
            }
            else if (decodedDescriptorSense.HasValue)
            {
                if (prettySense != null)
                {
                    if (prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal))
                    {
                        prettySense = prettySense.Substring(12);
                    }

                    if (prettySense.EndsWith('\n'))
                    {
                        prettySense = prettySense.Substring(0, prettySense.Length - 1);
                    }

                    prettySense = prettySense.Replace("\n", " - ");

                    _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}, {5}.", block,
                                     decodedDescriptorSense?.SenseKey, decodedDescriptorSense?.ASC,
                                     decodedDescriptorSense?.ASCQ, hexSense, prettySense);
                }
                else
                {
                    _logSw.WriteLine("SCSI reading LBA {0} error: SENSE {1} ASC {2:X2}h ASCQ {3:X2}h, {4}.", block,
                                     decodedDescriptorSense?.SenseKey, decodedDescriptorSense?.ASC,
                                     decodedDescriptorSense?.ASCQ, hexSense);
                }
            }
            else
            {
                if (prettySense != null)
                {
                    if (prettySense.StartsWith("SCSI SENSE: ", StringComparison.Ordinal))
                    {
                        prettySense = prettySense.Substring(12);
                    }

                    if (prettySense.EndsWith('\n'))
                    {
                        prettySense = prettySense.Substring(0, prettySense.Length - 1);
                    }

                    prettySense = prettySense.Replace("\n", " - ");

                    _logSw.WriteLine("SCSI reading LBA {0} error: {1}, {2}.", block, hexSense, prettySense);
                }
                else
                {
                    _logSw.WriteLine("SCSI reading LBA {0} error: {1}", block, hexSense);
                }
            }

            _logSw.Flush();
        }
Beispiel #17
0
        ScanResults Scsi()
        {
            ScanResults results = new ScanResults();
            MhddLog     mhddLog;
            IbgLog      ibgLog;

            byte[] senseBuf;
            bool   sense = false;

            results.Blocks = 0;
            uint   blockSize      = 0;
            ushort currentProfile = 0x0001;

            if (dev.IsRemovable)
            {
                sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _);
                if (sense)
                {
                    InitProgress?.Invoke();
                    FixedSense?decSense = Sense.DecodeFixed(senseBuf);
                    if (decSense.HasValue)
                    {
                        if (decSense.Value.ASC == 0x3A)
                        {
                            int leftRetries = 5;
                            while (leftRetries > 0)
                            {
                                PulseProgress?.Invoke("Waiting for drive to become ready");
                                Thread.Sleep(2000);
                                sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _);
                                if (!sense)
                                {
                                    break;
                                }

                                leftRetries--;
                            }

                            if (sense)
                            {
                                StoppingErrorMessage?.Invoke("Please insert media in drive");
                                return(results);
                            }
                        }
                        else if (decSense.Value.ASC == 0x04 && decSense.Value.ASCQ == 0x01)
                        {
                            int leftRetries = 10;
                            while (leftRetries > 0)
                            {
                                PulseProgress?.Invoke("Waiting for drive to become ready");
                                Thread.Sleep(2000);
                                sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _);
                                if (!sense)
                                {
                                    break;
                                }

                                leftRetries--;
                            }

                            if (sense)
                            {
                                StoppingErrorMessage
                                ?.Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}");
                                return(results);
                            }
                        }
                        // These should be trapped by the OS but seems in some cases they're not
                        else if (decSense.Value.ASC == 0x28)
                        {
                            int leftRetries = 10;
                            while (leftRetries > 0)
                            {
                                PulseProgress?.Invoke("Waiting for drive to become ready");
                                Thread.Sleep(2000);
                                sense = dev.ScsiTestUnitReady(out senseBuf, dev.Timeout, out _);
                                if (!sense)
                                {
                                    break;
                                }

                                leftRetries--;
                            }

                            if (sense)
                            {
                                StoppingErrorMessage
                                ?.Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}");
                                return(results);
                            }
                        }
                        else
                        {
                            StoppingErrorMessage
                            ?.Invoke($"Error testing unit was ready:\n{Sense.PrettifySense(senseBuf)}");
                            return(results);
                        }
                    }
                    else
                    {
                        StoppingErrorMessage?.Invoke("Unknown testing unit was ready.");
                        return(results);
                    }

                    EndProgress?.Invoke();
                }
            }

            Reader scsiReader = null;

            switch (dev.ScsiType)
            {
            case PeripheralDeviceTypes.DirectAccess:
            case PeripheralDeviceTypes.MultiMediaDevice:
            case PeripheralDeviceTypes.OCRWDevice:
            case PeripheralDeviceTypes.OpticalDevice:
            case PeripheralDeviceTypes.SimplifiedDevice:
            case PeripheralDeviceTypes.WriteOnceDevice:
                scsiReader     = new Reader(dev, dev.Timeout, null);
                results.Blocks = scsiReader.GetDeviceBlocks();
                if (scsiReader.FindReadCommand())
                {
                    StoppingErrorMessage?.Invoke("Unable to read medium.");
                    return(results);
                }

                blockSize = scsiReader.LogicalBlockSize;

                if (results.Blocks != 0 && blockSize != 0)
                {
                    results.Blocks++;
                    UpdateStatus
                    ?.Invoke($"Media has {results.Blocks} blocks of {blockSize} bytes/each. (for a total of {results.Blocks * (ulong)blockSize} bytes)");
                }

                break;

            case PeripheralDeviceTypes.SequentialAccess:
                StoppingErrorMessage?.Invoke("Scanning will never be supported on SCSI Streaming Devices." +
                                             Environment.NewLine +
                                             "It has no sense to do it, and it will put too much strain on the tape.");
                return(results);
            }

            if (results.Blocks == 0)
            {
                StoppingErrorMessage?.Invoke("Unable to read medium or empty medium present...");
                return(results);
            }

            bool compactDisc = true;

            FullTOC.CDFullTOC?toc = null;

            if (dev.ScsiType == PeripheralDeviceTypes.MultiMediaDevice)
            {
                sense = dev.GetConfiguration(out byte[] cmdBuf, out senseBuf, 0, MmcGetConfigurationRt.Current,
                                             dev.Timeout, out _);
                if (!sense)
                {
                    Features.SeparatedFeatures ftr = Features.Separate(cmdBuf);

                    currentProfile = ftr.CurrentProfile;

                    switch (ftr.CurrentProfile)
                    {
                    case 0x0005:
                    case 0x0008:
                    case 0x0009:
                    case 0x000A:
                    case 0x0020:
                    case 0x0021:
                    case 0x0022: break;

                    default:
                        compactDisc = false;
                        break;
                    }
                }

                if (compactDisc)
                {
                    currentProfile = 0x0008;
                    // We discarded all discs that falsify a TOC before requesting a real TOC
                    // No TOC, no CD (or an empty one)
                    bool tocSense = dev.ReadRawToc(out cmdBuf, out senseBuf, 1, dev.Timeout, out _);
                    if (!tocSense)
                    {
                        toc = FullTOC.Decode(cmdBuf);
                    }
                }
            }
            else
            {
                compactDisc = false;
            }

            uint blocksToRead = 64;

            results.A       = 0; // <3ms
            results.B       = 0; // >=3ms, <10ms
            results.C       = 0; // >=10ms, <50ms
            results.D       = 0; // >=50ms, <150ms
            results.E       = 0; // >=150ms, <500ms
            results.F       = 0; // >=500ms
            results.Errored = 0;
            DateTime start;
            DateTime end;

            results.ProcessingTime = 0;
            results.TotalTime      = 0;
            double currentSpeed = 0;

            results.MaxSpeed          = double.MinValue;
            results.MinSpeed          = double.MaxValue;
            results.UnreadableSectors = new List <ulong>();

            if (compactDisc)
            {
                if (toc == null)
                {
                    StoppingErrorMessage?.Invoke("Error trying to decode TOC...");
                    return(results);
                }

                bool readcd = !dev.ReadCd(out _, out senseBuf, 0, 2352, 1, MmcSectorTypes.AllTypes, false, false, true,
                                          MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None, MmcSubchannel.None,
                                          dev.Timeout, out _);

                if (readcd)
                {
                    UpdateStatus?.Invoke("Using MMC READ CD command.");
                }

                start = DateTime.UtcNow;

                while (true)
                {
                    if (readcd)
                    {
                        sense = dev.ReadCd(out _, out senseBuf, 0, 2352, blocksToRead, MmcSectorTypes.AllTypes, false,
                                           false, true, MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
                                           MmcSubchannel.None, dev.Timeout, out _);
                        if (dev.Error)
                        {
                            blocksToRead /= 2;
                        }
                    }

                    if (!dev.Error || blocksToRead == 1)
                    {
                        break;
                    }
                }

                if (dev.Error)
                {
                    StoppingErrorMessage
                    ?.Invoke($"Device error {dev.LastError} trying to guess ideal transfer length.");
                    return(results);
                }

                UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time.");

                InitBlockMap?.Invoke(results.Blocks, blockSize, blocksToRead, currentProfile);
                mhddLog = new MhddLog(mhddLogPath, dev, results.Blocks, blockSize, blocksToRead);
                ibgLog  = new IbgLog(ibgLogPath, currentProfile);
                DateTime timeSpeedStart   = DateTime.UtcNow;
                ulong    sectorSpeedStart = 0;

                InitProgress?.Invoke();
                for (ulong i = 0; i < results.Blocks; i += blocksToRead)
                {
                    if (aborted)
                    {
                        break;
                    }

                    double cmdDuration = 0;

                    if (results.Blocks - i < blocksToRead)
                    {
                        blocksToRead = (uint)(results.Blocks - i);
                    }

                    #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
                    if (currentSpeed > results.MaxSpeed && currentSpeed != 0)
                    {
                        results.MaxSpeed = currentSpeed;
                    }
                    if (currentSpeed < results.MinSpeed && currentSpeed != 0)
                    {
                        results.MinSpeed = currentSpeed;
                    }
                    #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator

                    UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)",
                                           (long)i, (long)results.Blocks);

                    if (readcd)
                    {
                        sense = dev.ReadCd(out _, out senseBuf, (uint)i, 2352, blocksToRead, MmcSectorTypes.AllTypes,
                                           false, false, true, MmcHeaderCodes.AllHeaders, true, true,
                                           MmcErrorField.None, MmcSubchannel.None, dev.Timeout, out cmdDuration);
                        results.ProcessingTime += cmdDuration;
                    }

                    if (!sense)
                    {
                        if (cmdDuration >= 500)
                        {
                            results.F += blocksToRead;
                        }
                        else if (cmdDuration >= 150)
                        {
                            results.E += blocksToRead;
                        }
                        else if (cmdDuration >= 50)
                        {
                            results.D += blocksToRead;
                        }
                        else if (cmdDuration >= 10)
                        {
                            results.C += blocksToRead;
                        }
                        else if (cmdDuration >= 3)
                        {
                            results.B += blocksToRead;
                        }
                        else
                        {
                            results.A += blocksToRead;
                        }

                        ScanTime?.Invoke(i, cmdDuration);
                        mhddLog.Write(i, cmdDuration);
                        ibgLog.Write(i, currentSpeed * 1024);
                    }
                    else
                    {
                        DicConsole.DebugWriteLine("Media-Scan", "READ CD error:\n{0}", Sense.PrettifySense(senseBuf));

                        FixedSense?senseDecoded = Sense.DecodeFixed(senseBuf);
                        if (senseDecoded.HasValue)
                        {
                            // TODO: This error happens when changing from track type afaik. Need to solve that more cleanly
                            // LOGICAL BLOCK ADDRESS OUT OF RANGE
                            if ((senseDecoded.Value.ASC != 0x21 || senseDecoded.Value.ASCQ != 0x00) &&
                                // ILLEGAL MODE FOR THIS TRACK (requesting sectors as-is, this is a firmware misconception when audio sectors
                                // are in a track where subchannel indicates data)
                                (senseDecoded.Value.ASC != 0x64 || senseDecoded.Value.ASCQ != 0x00))
                            {
                                results.Errored += blocksToRead;
                                for (ulong b = i; b < i + blocksToRead; b++)
                                {
                                    results.UnreadableSectors.Add(b);
                                }

                                ScanUnreadable?.Invoke(i);
                                mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);

                                ibgLog.Write(i, 0);
                            }
                        }
                        else
                        {
                            ScanUnreadable?.Invoke(i);
                            results.Errored += blocksToRead;
                            for (ulong b = i; b < i + blocksToRead; b++)
                            {
                                results.UnreadableSectors.Add(b);
                            }

                            mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);

                            ibgLog.Write(i, 0);
                        }
                    }

                    sectorSpeedStart += blocksToRead;

                    double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
                    if (elapsed < 1)
                    {
                        continue;
                    }

                    currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
                    ScanSpeed?.Invoke(i, currentSpeed * 1024);
                    sectorSpeedStart = 0;
                    timeSpeedStart   = DateTime.UtcNow;
                }

                end = DateTime.UtcNow;
                EndProgress?.Invoke();
                mhddLog.Close();
                ibgLog.Close(dev, results.Blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
                             blockSize * (double)(results.Blocks + 1) / 1024 /
                             (results.ProcessingTime / 1000),
                             devicePath);
            }
            else
            {
                start = DateTime.UtcNow;

                UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time.");

                InitBlockMap?.Invoke(results.Blocks, blockSize, blocksToRead, currentProfile);
                mhddLog = new MhddLog(mhddLogPath, dev, results.Blocks, blockSize, blocksToRead);
                ibgLog  = new IbgLog(ibgLogPath, currentProfile);
                DateTime timeSpeedStart   = DateTime.UtcNow;
                ulong    sectorSpeedStart = 0;

                InitProgress?.Invoke();
                for (ulong i = 0; i < results.Blocks; i += blocksToRead)
                {
                    if (aborted)
                    {
                        break;
                    }

                    if (results.Blocks - i < blocksToRead)
                    {
                        blocksToRead = (uint)(results.Blocks - i);
                    }

                    #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
                    if (currentSpeed > results.MaxSpeed && currentSpeed != 0)
                    {
                        results.MaxSpeed = currentSpeed;
                    }
                    if (currentSpeed < results.MinSpeed && currentSpeed != 0)
                    {
                        results.MinSpeed = currentSpeed;
                    }
                    #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator

                    UpdateProgress?.Invoke($"Reading sector {i} of {results.Blocks} ({currentSpeed:F3} MiB/sec.)",
                                           (long)i, (long)results.Blocks);

                    sense = scsiReader.ReadBlocks(out _, i, blocksToRead, out double cmdDuration);
                    results.ProcessingTime += cmdDuration;

                    if (!sense && !dev.Error)
                    {
                        if (cmdDuration >= 500)
                        {
                            results.F += blocksToRead;
                        }
                        else if (cmdDuration >= 150)
                        {
                            results.E += blocksToRead;
                        }
                        else if (cmdDuration >= 50)
                        {
                            results.D += blocksToRead;
                        }
                        else if (cmdDuration >= 10)
                        {
                            results.C += blocksToRead;
                        }
                        else if (cmdDuration >= 3)
                        {
                            results.B += blocksToRead;
                        }
                        else
                        {
                            results.A += blocksToRead;
                        }

                        ScanTime?.Invoke(i, cmdDuration);
                        mhddLog.Write(i, cmdDuration);
                        ibgLog.Write(i, currentSpeed * 1024);
                    }
                    // TODO: Separate errors on kind of errors.
                    else
                    {
                        ScanUnreadable?.Invoke(i);
                        results.Errored += blocksToRead;
                        for (ulong b = i; b < i + blocksToRead; b++)
                        {
                            results.UnreadableSectors.Add(b);
                        }

                        mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);
                        ibgLog.Write(i, 0);
                    }

                    sectorSpeedStart += blocksToRead;

                    double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;
                    if (elapsed < 1)
                    {
                        continue;
                    }

                    currentSpeed = sectorSpeedStart * blockSize / (1048576 * elapsed);
                    ScanSpeed?.Invoke(i, currentSpeed * 1024);
                    sectorSpeedStart = 0;
                    timeSpeedStart   = DateTime.UtcNow;
                }

                end = DateTime.UtcNow;
                EndProgress?.Invoke();
                mhddLog.Close();
                ibgLog.Close(dev, results.Blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
                             blockSize * (double)(results.Blocks + 1) / 1024 /
                             (results.ProcessingTime / 1000),
                             devicePath);
            }

            results.SeekMax   = double.MinValue;
            results.SeekMin   = double.MaxValue;
            results.SeekTotal = 0;
            const int SEEK_TIMES = 1000;

            Random rnd = new Random();

            InitProgress?.Invoke();
            for (int i = 0; i < SEEK_TIMES; i++)
            {
                if (aborted)
                {
                    break;
                }

                uint seekPos = (uint)rnd.Next((int)results.Blocks);

                PulseProgress?.Invoke($"Seeking to sector {seekPos}...\t\t");

                double seekCur;
                if (scsiReader.CanSeek)
                {
                    scsiReader.Seek(seekPos, out seekCur);
                }
                else
                {
                    scsiReader.ReadBlock(out _, seekPos, out seekCur);
                }

                #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
                if (seekCur > results.SeekMax && seekCur != 0)
                {
                    results.SeekMax = seekCur;
                }
                if (seekCur < results.SeekMin && seekCur != 0)
                {
                    results.SeekMin = seekCur;
                }
                #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator

                results.SeekTotal += seekCur;
                GC.Collect();
            }

            EndProgress?.Invoke();

            results.ProcessingTime /= 1000;
            results.TotalTime       = (end - start).TotalSeconds;
            results.AvgSpeed        = blockSize * (double)(results.Blocks + 1) / 1048576 / results.ProcessingTime;
            results.SeekTimes       = SEEK_TIMES;

            return(results);
        }
Beispiel #18
0
        /// <summary>Dumps a MiniDisc Data device</summary>
        void MiniDisc()
        {
            bool         sense;
            byte         scsiMediumType = 0;
            const ushort sbcProfile     = 0x0001;
            DateTime     start;
            DateTime     end;
            double       totalDuration = 0;
            double       currentSpeed  = 0;
            double       maxSpeed      = double.MinValue;
            double       minSpeed      = double.MaxValue;

            byte[]            readBuffer;
            Modes.DecodedMode?decMode = null;
            Dictionary <MediaTagType, byte[]> mediaTags = new Dictionary <MediaTagType, byte[]>();

            byte[] cmdBuf;
            bool   ret;

            _dumpLog.WriteLine("Initializing reader.");
            var   scsiReader = new Reader(_dev, _dev.Timeout, null, _errorLog);
            ulong blocks     = scsiReader.GetDeviceBlocks();
            uint  blockSize  = scsiReader.LogicalBlockSize;

            _dumpLog.WriteLine("Requesting MODE SENSE (6).");
            UpdateStatus?.Invoke("Requesting MODE SENSE (6).");

            sense = _dev.ModeSense6(out cmdBuf, out _, true, ScsiModeSensePageControl.Current, 0x3F, 5, out _);

            if (!sense &&
                !_dev.Error &&
                Modes.DecodeMode6(cmdBuf, _dev.ScsiType).HasValue)
            {
                decMode = Modes.DecodeMode6(cmdBuf, _dev.ScsiType);
            }

            if (decMode.HasValue)
            {
                scsiMediumType = (byte)decMode.Value.Header.MediumType;
            }

            if (blockSize != 2048)
            {
                _dumpLog.WriteLine("MiniDisc albums, NetMD discs or user-written audio MiniDisc cannot be dumped.");

                StoppingErrorMessage?.
                Invoke("MiniDisc albums, NetMD discs or user-written audio MiniDisc cannot be dumped.");

                return;
            }

            MediaType dskType = MediaType.MDData;

            if (scsiReader.FindReadCommand())
            {
                _dumpLog.WriteLine("ERROR: Cannot find correct read command: {0}.", scsiReader.ErrorMessage);
                StoppingErrorMessage?.Invoke("Unable to read medium.");

                return;
            }

            if (blocks != 0 &&
                blockSize != 0)
            {
                blocks++;

                ulong totalSize = blocks * blockSize;

                if (totalSize > 1099511627776)
                {
                    UpdateStatus?.
                    Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1099511627776d:F3} TiB)");
                }
                else if (totalSize > 1073741824)
                {
                    UpdateStatus?.
                    Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1073741824d:F3} GiB)");
                }
                else if (totalSize > 1048576)
                {
                    UpdateStatus?.
                    Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1048576d:F3} MiB)");
                }
                else if (totalSize > 1024)
                {
                    UpdateStatus?.
                    Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1024d:F3} KiB)");
                }
                else
                {
                    UpdateStatus?.
                    Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize} bytes)");
                }
            }

            // Check how many blocks to read, if error show and return
            // 64 works, gets maximum speed (150KiB/s), slow I know...
            if (scsiReader.GetBlocksToRead())
            {
                _dumpLog.WriteLine("ERROR: Cannot get blocks to read: {0}.", scsiReader.ErrorMessage);
                StoppingErrorMessage?.Invoke(scsiReader.ErrorMessage);

                return;
            }

            uint blocksToRead      = scsiReader.BlocksToRead;
            uint logicalBlockSize  = blockSize;
            uint physicalBlockSize = scsiReader.PhysicalBlockSize;

            if (blocks == 0)
            {
                _dumpLog.WriteLine("ERROR: Unable to read medium or empty medium present...");
                StoppingErrorMessage?.Invoke("Unable to read medium or empty medium present...");

                return;
            }

            UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes).");
            UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time.");
            UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block.");
            UpdateStatus?.Invoke($"Device reports {scsiReader.LongBlockSize} bytes per physical block.");
            UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}.");
            UpdateStatus?.Invoke($"SCSI medium type: {scsiMediumType}.");
            UpdateStatus?.Invoke($"Media identified as {dskType}");

            _dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize);
            _dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
            _dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize);
            _dumpLog.WriteLine("Device reports {0} bytes per physical block.", scsiReader.LongBlockSize);
            _dumpLog.WriteLine("SCSI device type: {0}.", _dev.ScsiType);
            _dumpLog.WriteLine("SCSI medium type: {0}.", scsiMediumType);
            _dumpLog.WriteLine("Media identified as {0}.", dskType);

            sense = _dev.MiniDiscGetType(out cmdBuf, out _, _dev.Timeout, out _);

            if (!sense &&
                !_dev.Error)
            {
                mediaTags.Add(MediaTagType.MiniDiscType, cmdBuf);
            }

            sense = _dev.MiniDiscD5(out cmdBuf, out _, _dev.Timeout, out _);

            if (!sense &&
                !_dev.Error)
            {
                mediaTags.Add(MediaTagType.MiniDiscD5, cmdBuf);
            }

            sense = _dev.MiniDiscReadDataTOC(out cmdBuf, out _, _dev.Timeout, out _);

            if (!sense &&
                !_dev.Error)
            {
                mediaTags.Add(MediaTagType.MiniDiscDTOC, cmdBuf);
            }

            var utocMs = new MemoryStream();

            for (uint i = 0; i < 3; i++)
            {
                sense = _dev.MiniDiscReadUserTOC(out cmdBuf, out _, i, _dev.Timeout, out _);

                if (sense || _dev.Error)
                {
                    break;
                }

                utocMs.Write(cmdBuf, 0, 2336);
            }

            if (utocMs.Length > 0)
            {
                mediaTags.Add(MediaTagType.MiniDiscUTOC, utocMs.ToArray());
            }

            ret = true;

            foreach (MediaTagType tag in mediaTags.Keys.Where(tag => !_outputPlugin.SupportedMediaTags.Contains(tag)))
            {
                ret = false;
                _dumpLog.WriteLine($"Output format does not support {tag}.");
                ErrorMessage?.Invoke($"Output format does not support {tag}.");
            }

            if (!ret)
            {
                if (_force)
                {
                    _dumpLog.WriteLine("Several media tags not supported, continuing...");
                    ErrorMessage?.Invoke("Several media tags not supported, continuing...");
                }
                else
                {
                    _dumpLog.WriteLine("Several media tags not supported, not continuing...");
                    StoppingErrorMessage?.Invoke("Several media tags not supported, not continuing...");

                    return;
                }
            }

            UpdateStatus?.Invoke($"Reading {blocksToRead} sectors at a time.");
            _dumpLog.WriteLine("Reading {0} sectors at a time.", blocksToRead);

            var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private);
            var ibgLog  = new IbgLog(_outputPrefix + ".ibg", sbcProfile);

            ret = _outputPlugin.Create(_outputPath, dskType, _formatOptions, blocks, blockSize);

            // Cannot create image
            if (!ret)
            {
                _dumpLog.WriteLine("Error creating output image, not continuing.");
                _dumpLog.WriteLine(_outputPlugin.ErrorMessage);

                StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine +
                                             _outputPlugin.ErrorMessage);

                return;
            }

            start = DateTime.UtcNow;
            double imageWriteDuration = 0;

            if (decMode?.Pages != null)
            {
                bool setGeometry = false;

                foreach (Modes.ModePage page in decMode.Value.Pages)
                {
                    if (page.Page == 0x04 &&
                        page.Subpage == 0x00)
                    {
                        Modes.ModePage_04?rigidPage = Modes.DecodeModePage_04(page.PageResponse);

                        if (!rigidPage.HasValue || setGeometry)
                        {
                            continue;
                        }

                        _dumpLog.WriteLine("Setting geometry to {0} cylinders, {1} heads, {2} sectors per track",
                                           rigidPage.Value.Cylinders, rigidPage.Value.Heads,
                                           (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads)));

                        UpdateStatus?.
                        Invoke($"Setting geometry to {rigidPage.Value.Cylinders} cylinders, {rigidPage.Value.Heads} heads, {(uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads))} sectors per track");

                        _outputPlugin.SetGeometry(rigidPage.Value.Cylinders, rigidPage.Value.Heads,
                                                  (uint)(blocks / (rigidPage.Value.Cylinders * rigidPage.Value.Heads)));

                        setGeometry = true;
                    }
                    else if (page.Page == 0x05 &&
                             page.Subpage == 0x00)
                    {
                        Modes.ModePage_05?flexiblePage = Modes.DecodeModePage_05(page.PageResponse);

                        if (!flexiblePage.HasValue)
                        {
                            continue;
                        }

                        _dumpLog.WriteLine("Setting geometry to {0} cylinders, {1} heads, {2} sectors per track",
                                           flexiblePage.Value.Cylinders, flexiblePage.Value.Heads,
                                           flexiblePage.Value.SectorsPerTrack);

                        UpdateStatus?.
                        Invoke($"Setting geometry to {flexiblePage.Value.Cylinders} cylinders, {flexiblePage.Value.Heads} heads, {flexiblePage.Value.SectorsPerTrack} sectors per track");

                        _outputPlugin.SetGeometry(flexiblePage.Value.Cylinders, flexiblePage.Value.Heads,
                                                  flexiblePage.Value.SectorsPerTrack);

                        setGeometry = true;
                    }
                }
            }

            DumpHardwareType currentTry = null;
            ExtentsULong     extents    = null;

            ResumeSupport.Process(true, _dev.IsRemovable, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial,
                                  _dev.PlatformId, ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision,
                                  _private);

            if (currentTry == null ||
                extents == null)
            {
                StoppingErrorMessage?.Invoke("Could not process resume file, not continuing...");

                return;
            }

            if (_resume.NextBlock > 0)
            {
                UpdateStatus?.Invoke($"Resuming from block {_resume.NextBlock}.");
                _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock);
            }

            bool     newTrim          = false;
            DateTime timeSpeedStart   = DateTime.UtcNow;
            ulong    sectorSpeedStart = 0;

            InitProgress?.Invoke();

            for (ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
            {
                if (_aborted)
                {
                    currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                    UpdateStatus?.Invoke("Aborted!");
                    _dumpLog.WriteLine("Aborted!");

                    break;
                }

                if (blocks - i < blocksToRead)
                {
                    blocksToRead = (uint)(blocks - i);
                }

                if (currentSpeed > maxSpeed &&
                    currentSpeed > 0)
                {
                    maxSpeed = currentSpeed;
                }

                if (currentSpeed < minSpeed &&
                    currentSpeed > 0)
                {
                    minSpeed = currentSpeed;
                }

                UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
                                       (long)blocks);

                sense = _dev.Read6(out readBuffer, out _, (uint)i, blockSize, (byte)blocksToRead, _dev.Timeout,
                                   out double cmdDuration);

                totalDuration += cmdDuration;

                if (!sense &&
                    !_dev.Error)
                {
                    mhddLog.Write(i, cmdDuration);
                    ibgLog.Write(i, currentSpeed * 1024);
                    DateTime writeStart = DateTime.Now;
                    _outputPlugin.WriteSectors(readBuffer, i, blocksToRead);
                    imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
                    extents.Add(i, blocksToRead, true);
                }
                else
                {
                    // TODO: Reset device after X errors
                    if (_stopOnError)
                    {
                        return; // TODO: Return more cleanly
                    }
                    if (i + _skip > blocks)
                    {
                        _skip = (uint)(blocks - i);
                    }

                    // Write empty data
                    DateTime writeStart = DateTime.Now;
                    _outputPlugin.WriteSectors(new byte[blockSize * _skip], i, _skip);
                    imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;

                    for (ulong b = i; b < i + _skip; b++)
                    {
                        _resume.BadBlocks.Add(b);
                    }

                    mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);

                    ibgLog.Write(i, 0);
                    _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
                    i      += _skip - blocksToRead;
                    newTrim = true;
                }

                sectorSpeedStart += blocksToRead;
                _resume.NextBlock = i + blocksToRead;

                double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;

                if (elapsed < 1)
                {
                    continue;
                }

                currentSpeed     = (sectorSpeedStart * blockSize) / (1048576 * elapsed);
                sectorSpeedStart = 0;
                timeSpeedStart   = DateTime.UtcNow;
            }

            _resume.BadBlocks = _resume.BadBlocks.Distinct().ToList();

            end = DateTime.UtcNow;
            EndProgress?.Invoke();
            mhddLog.Close();

            ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
                         (blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000), _devicePath);

            UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds.");

            UpdateStatus?.
            Invoke($"Average dump speed {((double)blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000):F3} KiB/sec.");

            UpdateStatus?.
            Invoke($"Average write speed {((double)blockSize * (double)(blocks + 1)) / 1024 / imageWriteDuration:F3} KiB/sec.");

            _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);

            _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
                               ((double)blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000));

            _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
                               ((double)blockSize * (double)(blocks + 1)) / 1024 / imageWriteDuration);

            #region Trimming
            if (_resume.BadBlocks.Count > 0 &&
                !_aborted &&
                _trim &&
                newTrim)
            {
                start = DateTime.UtcNow;
                UpdateStatus?.Invoke("Trimming skipped sectors");
                _dumpLog.WriteLine("Trimming skipped sectors");

                ulong[] tmpArray = _resume.BadBlocks.ToArray();
                InitProgress?.Invoke();

                foreach (ulong badSector in tmpArray)
                {
                    if (_aborted)
                    {
                        currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                        UpdateStatus?.Invoke("Aborted!");
                        _dumpLog.WriteLine("Aborted!");

                        break;
                    }

                    PulseProgress?.Invoke($"Trimming sector {badSector}");

                    sense = _dev.Read6(out readBuffer, out _, (uint)badSector, blockSize, 1, _dev.Timeout,
                                       out double _);

                    if (sense || _dev.Error)
                    {
                        continue;
                    }

                    _resume.BadBlocks.Remove(badSector);
                    extents.Add(badSector);
                    _outputPlugin.WriteSector(readBuffer, badSector);
                }

                EndProgress?.Invoke();
                end = DateTime.UtcNow;
                UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds.");
                _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds);
            }
            #endregion Trimming

            #region Error handling
            if (_resume.BadBlocks.Count > 0 &&
                !_aborted &&
                _retryPasses > 0)
            {
                int  pass              = 1;
                bool forward           = true;
                bool runningPersistent = false;

                Modes.ModePage?currentModePage = null;
                byte[]         md6;

                if (_persistent)
                {
                    Modes.ModePage_01 pg;

                    sense = _dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01,
                                            _dev.Timeout, out _);

                    if (!sense)
                    {
                        Modes.DecodedMode?dcMode6 = Modes.DecodeMode6(readBuffer, _dev.ScsiType);

                        if (dcMode6?.Pages != null)
                        {
                            foreach (Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage =>
                                                                                          modePage.Page == 0x01 && modePage.Subpage == 0x00))
                            {
                                currentModePage = modePage;
                            }
                        }
                    }

                    if (currentModePage == null)
                    {
                        pg = new Modes.ModePage_01
                        {
                            PS             = false,
                            AWRE           = true,
                            ARRE           = true,
                            TB             = false,
                            RC             = false,
                            EER            = true,
                            PER            = false,
                            DTE            = true,
                            DCR            = false,
                            ReadRetryCount = 32
                        };

                        currentModePage = new Modes.ModePage
                        {
                            Page         = 0x01,
                            Subpage      = 0x00,
                            PageResponse = Modes.EncodeModePage_01(pg)
                        };
                    }

                    pg = new Modes.ModePage_01
                    {
                        PS             = false,
                        AWRE           = false,
                        ARRE           = false,
                        TB             = true,
                        RC             = false,
                        EER            = true,
                        PER            = false,
                        DTE            = false,
                        DCR            = false,
                        ReadRetryCount = 255
                    };

                    var md = new Modes.DecodedMode
                    {
                        Header = new Modes.ModeHeader(),
                        Pages  = new[]
                        {
                            new Modes.ModePage
                            {
                                Page         = 0x01,
                                Subpage      = 0x00,
                                PageResponse = Modes.EncodeModePage_01(pg)
                            }
                        }
                    };

                    md6 = Modes.EncodeMode6(md, _dev.ScsiType);

                    UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks).");
                    _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks).");
                    sense = _dev.ModeSelect(md6, out byte[] senseBuf, true, false, _dev.Timeout, out _);

                    if (sense)
                    {
                        UpdateStatus?.
                        Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");

                        AaruConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf));

                        _dumpLog.
                        WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
                    }
                    else
                    {
                        runningPersistent = true;
                    }
                }

                InitProgress?.Invoke();
repeatRetry:
                ulong[] tmpArray = _resume.BadBlocks.ToArray();

                foreach (ulong badSector in tmpArray)
                {
                    if (_aborted)
                    {
                        currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                        UpdateStatus?.Invoke("Aborted!");
                        _dumpLog.WriteLine("Aborted!");

                        break;
                    }

                    PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass,
                                                        forward ? "forward" : "reverse",
                                                        runningPersistent ? "recovering partial data, " : ""));

                    sense = _dev.Read6(out readBuffer, out _, (uint)badSector, blockSize, 1, _dev.Timeout,
                                       out double cmdDuration);

                    totalDuration += cmdDuration;

                    if (!sense &&
                        !_dev.Error)
                    {
                        _resume.BadBlocks.Remove(badSector);
                        extents.Add(badSector);
                        _outputPlugin.WriteSector(readBuffer, badSector);
                        UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}.");
                        _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
                    }
                    else if (runningPersistent)
                    {
                        _outputPlugin.WriteSector(readBuffer, badSector);
                    }
                }

                if (pass < _retryPasses &&
                    !_aborted &&
                    _resume.BadBlocks.Count > 0)
                {
                    pass++;
                    forward = !forward;
                    _resume.BadBlocks.Sort();

                    if (!forward)
                    {
                        _resume.BadBlocks.Reverse();
                    }

                    goto repeatRetry;
                }

                if (runningPersistent && currentModePage.HasValue)
                {
                    var md = new Modes.DecodedMode
                    {
                        Header = new Modes.ModeHeader(),
                        Pages  = new[]
                        {
                            currentModePage.Value
                        }
                    };

                    md6 = Modes.EncodeMode6(md, _dev.ScsiType);

                    UpdateStatus?.Invoke("Sending MODE SELECT to drive (return device to previous status).");
                    _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status).");
                    _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _);
                }

                EndProgress?.Invoke();
            }
            #endregion Error handling

            _resume.BadBlocks.Sort();

            foreach (ulong bad in _resume.BadBlocks)
            {
                _dumpLog.WriteLine("Sector {0} could not be read.", bad);
            }

            currentTry.Extents = ExtentsConverter.ToMetadata(extents);

            _outputPlugin.SetDumpHardware(_resume.Tries);

            var metadata = new CommonTypes.Structs.ImageInfo
            {
                Application        = "Aaru",
                ApplicationVersion = Version.GetVersion()
            };

            if (!_outputPlugin.SetMetadata(metadata))
            {
                ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine +
                                     _outputPlugin.ErrorMessage);
            }

            if (_preSidecar != null)
            {
                _outputPlugin.SetCicmMetadata(_preSidecar);
            }

            _dumpLog.WriteLine("Closing output file.");
            UpdateStatus?.Invoke("Closing output file.");
            DateTime closeStart = DateTime.Now;
            _outputPlugin.Close();
            DateTime closeEnd = DateTime.Now;
            UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds.");
            _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds);

            if (_aborted)
            {
                UpdateStatus?.Invoke("Aborted!");
                _dumpLog.WriteLine("Aborted!");

                return;
            }

            double totalChkDuration = 0;

            if (_metadata)
            {
                UpdateStatus?.Invoke("Creating sidecar.");
                _dumpLog.WriteLine("Creating sidecar.");
                var         filters     = new FiltersList();
                IFilter     filter      = filters.GetFilter(_outputPath);
                IMediaImage inputPlugin = ImageFormat.Detect(filter);

                if (!inputPlugin.Open(filter))
                {
                    StoppingErrorMessage?.Invoke("Could not open created image.");

                    return;
                }

                DateTime chkStart = DateTime.UtcNow;
                _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding);
                _sidecarClass.InitProgressEvent    += InitProgress;
                _sidecarClass.UpdateProgressEvent  += UpdateProgress;
                _sidecarClass.EndProgressEvent     += EndProgress;
                _sidecarClass.InitProgressEvent2   += InitProgress2;
                _sidecarClass.UpdateProgressEvent2 += UpdateProgress2;
                _sidecarClass.EndProgressEvent2    += EndProgress2;
                _sidecarClass.UpdateStatusEvent    += UpdateStatus;
                CICMMetadataType sidecar = _sidecarClass.Create();
                end = DateTime.UtcNow;

                totalChkDuration = (end - chkStart).TotalMilliseconds;
                UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds.");

                UpdateStatus?.
                Invoke($"Average checksum speed {((double)blockSize * (double)(blocks + 1)) / 1024 / (totalChkDuration / 1000):F3} KiB/sec.");

                _dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds);

                _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
                                   ((double)blockSize * (double)(blocks + 1)) / 1024 / (totalChkDuration / 1000));

                if (_preSidecar != null)
                {
                    _preSidecar.BlockMedia = sidecar.BlockMedia;
                    sidecar = _preSidecar;
                }

                List <(ulong start, string type)> filesystems = new List <(ulong start, string type)>();

                if (sidecar.BlockMedia[0].FileSystemInformation != null)
                {
                    filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation
                                         where partition.FileSystems != null from fileSystem in partition.FileSystems
                                         select(partition.StartSector, fileSystem.Type));
                }

                if (filesystems.Count > 0)
                {
                    foreach (var filesystem in filesystems.Select(o => new
                    {
                        o.start,
                        o.type
                    }).Distinct())
                    {
                        UpdateStatus?.Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}");
                        _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start);
                    }
                }

                sidecar.BlockMedia[0].Dimensions     = Dimensions.DimensionsFromMediaType(dskType);
                (string type, string subType)xmlType = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType);
                sidecar.BlockMedia[0].DiskType       = xmlType.type;
                sidecar.BlockMedia[0].DiskSubType    = xmlType.subType;

                if (!_dev.IsRemovable ||
                    _dev.IsUsb)
                {
                    if (_dev.Type == DeviceType.ATAPI)
                    {
                        sidecar.BlockMedia[0].Interface = "ATAPI";
                    }
                    else if (_dev.IsUsb)
                    {
                        sidecar.BlockMedia[0].Interface = "USB";
                    }
                    else if (_dev.IsFireWire)
                    {
                        sidecar.BlockMedia[0].Interface = "FireWire";
                    }
                    else
                    {
                        sidecar.BlockMedia[0].Interface = "SCSI";
                    }
                }

                sidecar.BlockMedia[0].LogicalBlocks     = blocks;
                sidecar.BlockMedia[0].PhysicalBlockSize = physicalBlockSize;
                sidecar.BlockMedia[0].LogicalBlockSize  = logicalBlockSize;
                sidecar.BlockMedia[0].Manufacturer      = _dev.Manufacturer;
                sidecar.BlockMedia[0].Model             = _dev.Model;

                if (!_private)
                {
                    sidecar.BlockMedia[0].Serial = _dev.Serial;
                }

                sidecar.BlockMedia[0].Size = blocks * blockSize;

                if (_dev.IsRemovable)
                {
                    sidecar.BlockMedia[0].DumpHardwareArray = _resume.Tries.ToArray();
                }

                UpdateStatus?.Invoke("Writing metadata sidecar");

                var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create);

                var xmlSer = new XmlSerializer(typeof(CICMMetadataType));
                xmlSer.Serialize(xmlFs, sidecar);
                xmlFs.Close();
            }

            UpdateStatus?.Invoke("");

            UpdateStatus?.
            Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing).");

            UpdateStatus?.
            Invoke($"Average speed: {((double)blockSize * (double)(blocks + 1)) / 1048576 / (totalDuration / 1000):F3} MiB/sec.");

            if (maxSpeed > 0)
            {
                UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec.");
            }

            if (minSpeed > 0 &&
                minSpeed < double.MaxValue)
            {
                UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec.");
            }

            UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read.");
            UpdateStatus?.Invoke("");

            Statistics.AddMedia(dskType, true);
        }
Beispiel #19
0
        static void ReadSectorLocation(string devPath, Device dev)
        {
            uint   address  = 0;
            bool   physical = false;
            string strDev;
            int    item;

parameters:
            while (true)
            {
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("Parameters for READ SECTOR LOCATION command:");
                DicConsole.WriteLine("{0} Block Address: {1}", physical ? "Physical" : "Logical", address);
                DicConsole.WriteLine();
                DicConsole.WriteLine("Choose what to do:");
                DicConsole.WriteLine("1.- Change parameters.");
                DicConsole.WriteLine("2.- Send command with these parameters.");
                DicConsole.WriteLine("0.- Return to Plasmon vendor commands menu.");

                strDev = System.Console.ReadLine();
                if (!int.TryParse(strDev, out item))
                {
                    DicConsole.WriteLine("Not a number. Press any key to continue...");
                    System.Console.ReadKey();
                    continue;
                }

                switch (item)
                {
                case 0:
                    DicConsole.WriteLine("Returning to Plasmon vendor commands menu...");
                    return;

                case 1:
                    DicConsole.Write("Physical address?: ");
                    strDev = System.Console.ReadLine();
                    if (!bool.TryParse(strDev, out physical))
                    {
                        DicConsole.WriteLine("Not a boolean. Press any key to continue...");
                        physical = false;
                        System.Console.ReadKey();
                        continue;
                    }

                    DicConsole.Write("{0} Block Address?: ", physical ? "Physical" : "Logical");
                    strDev = System.Console.ReadLine();
                    if (!uint.TryParse(strDev, out address))
                    {
                        DicConsole.WriteLine("Not a numbr. Press any key to continue...");
                        address = 0;
                        System.Console.ReadKey();
                    }

                    break;

                case 2: goto start;
                }
            }

start:
            System.Console.Clear();
            bool sense = dev.PlasmonReadSectorLocation(out byte[] buffer, out byte[] senseBuffer, address, physical,
                                                       dev.Timeout, out double duration);

menu:
            DicConsole.WriteLine("Device: {0}", devPath);
            DicConsole.WriteLine("Sending READ SECTOR LOCATION to the device:");
            DicConsole.WriteLine("Command took {0} ms.", duration);
            DicConsole.WriteLine("Sense is {0}.", sense);
            DicConsole.WriteLine("Buffer is {0} bytes.", buffer?.Length.ToString() ?? "null");
            DicConsole.WriteLine("Buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(buffer));
            DicConsole.WriteLine("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null");
            DicConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer));
            DicConsole.WriteLine();
            DicConsole.WriteLine("Choose what to do:");
            DicConsole.WriteLine("1.- Print buffer.");
            DicConsole.WriteLine("2.- Print sense buffer.");
            DicConsole.WriteLine("3.- Decode sense buffer.");
            DicConsole.WriteLine("4.- Send command again.");
            DicConsole.WriteLine("5.- Change parameters.");
            DicConsole.WriteLine("0.- Return to Plasmon vendor commands menu.");
            DicConsole.Write("Choose: ");

            strDev = System.Console.ReadLine();
            if (!int.TryParse(strDev, out item))
            {
                DicConsole.WriteLine("Not a number. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                goto menu;
            }

            switch (item)
            {
            case 0:
                DicConsole.WriteLine("Returning to Plasmon vendor commands menu...");
                return;

            case 1:
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("READ SECTOR LOCATION response:");
                if (buffer != null)
                {
                    PrintHex.PrintHexArray(buffer, 64);
                }
                DicConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                goto menu;

            case 2:
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("READ SECTOR LOCATION sense:");
                if (senseBuffer != null)
                {
                    PrintHex.PrintHexArray(senseBuffer, 64);
                }
                DicConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                goto menu;

            case 3:
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                DicConsole.WriteLine("READ SECTOR LOCATION decoded sense:");
                DicConsole.Write("{0}", Sense.PrettifySense(senseBuffer));
                DicConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                DicConsole.WriteLine("Device: {0}", devPath);
                goto menu;

            case 4: goto start;

            case 5: goto parameters;

            default:
                DicConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                goto menu;
            }
        }
Beispiel #20
0
        static void RequestBlockAddress(string devPath, Device dev)
        {
            uint   lba = 0;
            string strDev;
            int    item;

parameters:

            while (true)
            {
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("Parameters for REQUEST BLOCK ADDRESS command:");
                AaruConsole.WriteLine("LBA: {0}", lba);
                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 Archive vendor 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 Archive vendor commands menu...");

                    return;

                case 1:
                    AaruConsole.Write("LBA?: ");
                    strDev = System.Console.ReadLine();

                    if (!uint.TryParse(strDev, out lba))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        lba = 0;
                        System.Console.ReadKey();
                    }

                    break;

                case 2: goto start;
                }
            }

start:
            System.Console.Clear();

            bool sense = dev.ArchiveCorpRequestBlockAddress(out byte[] buffer, out byte[] senseBuffer, lba, dev.Timeout,
                                                            out double duration);

menu:
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Sending REQUEST BLOCK ADDRESS 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("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null");
            AaruConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer));
            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print buffer.");
            AaruConsole.WriteLine("2.- Print sense buffer.");
            AaruConsole.WriteLine("3.- Decode sense buffer.");
            AaruConsole.WriteLine("4.- Send command again.");
            AaruConsole.WriteLine("5.- Change parameters.");
            AaruConsole.WriteLine("0.- Return to Archive vendor 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 Archive vendor commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("REQUEST BLOCK ADDRESS 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("REQUEST BLOCK ADDRESS 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 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("REQUEST BLOCK ADDRESS decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);

                goto menu;

            case 4: goto start;

            case 5: goto parameters;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
Beispiel #21
0
        static void ReadLong(string devPath, Device dev)
        {
            bool   relative    = false;
            uint   address     = 0;
            ushort length      = 1;
            ushort bps         = 512;
            bool   physical    = false;
            bool   sectorCount = true;
            string strDev;
            int    item;

parameters:

            while (true)
            {
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("Parameters for READ LONG command:");
                AaruConsole.WriteLine("{0} Block Address: {1}", physical ? "Physical" : "Logical", address);
                AaruConsole.WriteLine("Relative?: {0}", relative);
                AaruConsole.WriteLine("Will transfer {0} {1}", length, sectorCount ? "sectors" : "bytes");

                if (sectorCount)
                {
                    AaruConsole.WriteLine("Expected sector size: {0} bytes", bps);
                }

                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 Hewlett-Packard vendor 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 Hewlett-Packard vendor commands menu...");

                    return;

                case 1:
                    AaruConsole.Write("Physical address?: ");
                    strDev = System.Console.ReadLine();

                    if (!bool.TryParse(strDev, out physical))
                    {
                        AaruConsole.WriteLine("Not a boolean. Press any key to continue...");
                        physical = false;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Relative address?: ");
                    strDev = System.Console.ReadLine();

                    if (!bool.TryParse(strDev, out relative))
                    {
                        AaruConsole.WriteLine("Not a boolean. Press any key to continue...");
                        relative = false;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("{0} Block Address?: ", physical ? "Physical" : "Logical");
                    strDev = System.Console.ReadLine();

                    if (!uint.TryParse(strDev, out address))
                    {
                        AaruConsole.WriteLine("Not a numbr. Press any key to continue...");
                        address = 0;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("Transfer sectors?: ");
                    strDev = System.Console.ReadLine();

                    if (!bool.TryParse(strDev, out sectorCount))
                    {
                        AaruConsole.WriteLine("Not a boolean. Press any key to continue...");
                        sectorCount = true;
                        System.Console.ReadKey();

                        continue;
                    }

                    AaruConsole.Write("How many {0} to transfer?: ", sectorCount ? "sectors" : "bytes");
                    strDev = System.Console.ReadLine();

                    if (!ushort.TryParse(strDev, out length))
                    {
                        AaruConsole.WriteLine("Not a number. Press any key to continue...");
                        length = (ushort)(sectorCount ? 1 : 512);
                        System.Console.ReadKey();

                        continue;
                    }

                    if (sectorCount)
                    {
                        AaruConsole.Write("How many bytes to expect per sector?");
                        strDev = System.Console.ReadLine();

                        if (!ushort.TryParse(strDev, out bps))
                        {
                            AaruConsole.WriteLine("Not a numbr. Press any key to continue...");
                            bps = 512;
                            System.Console.ReadKey();
                        }
                    }

                    break;

                case 2: goto start;
                }
            }

start:
            System.Console.Clear();

            bool sense = dev.HpReadLong(out byte[] buffer, out byte[] senseBuffer, relative, address, length, bps,
                                        physical, sectorCount, dev.Timeout, out double duration);

menu:
            AaruConsole.WriteLine("Device: {0}", devPath);
            AaruConsole.WriteLine("Sending READ LONG 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("Sense buffer is {0} bytes.", senseBuffer?.Length.ToString() ?? "null");
            AaruConsole.WriteLine("Sense buffer is null or empty? {0}", ArrayHelpers.ArrayIsNullOrEmpty(senseBuffer));
            AaruConsole.WriteLine();
            AaruConsole.WriteLine("Choose what to do:");
            AaruConsole.WriteLine("1.- Print buffer.");
            AaruConsole.WriteLine("2.- Print sense buffer.");
            AaruConsole.WriteLine("3.- Decode sense buffer.");
            AaruConsole.WriteLine("4.- Send command again.");
            AaruConsole.WriteLine("5.- Change parameters.");
            AaruConsole.WriteLine("0.- Return to Hewlett-Packard vendor 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 Hewlett-Packard vendor commands menu...");

                return;

            case 1:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ LONG 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 LONG 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 3:
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);
                AaruConsole.WriteLine("READ LONG decoded sense:");
                AaruConsole.Write("{0}", Sense.PrettifySense(senseBuffer));
                AaruConsole.WriteLine("Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();
                AaruConsole.WriteLine("Device: {0}", devPath);

                goto menu;

            case 4: goto start;

            case 5: goto parameters;

            default:
                AaruConsole.WriteLine("Incorrect option. Press any key to continue...");
                System.Console.ReadKey();
                System.Console.Clear();

                goto menu;
            }
        }
Beispiel #22
0
        /// <summary>Reads all CD user data</summary>
        /// <param name="audioExtents">Extents with audio sectors</param>
        /// <param name="blocks">Total number of positive sectors</param>
        /// <param name="blockSize">Size of the read sector in bytes</param>
        /// <param name="currentSpeed">Current read speed</param>
        /// <param name="currentTry">Current dump hardware try</param>
        /// <param name="extents">Extents</param>
        /// <param name="ibgLog">IMGBurn log</param>
        /// <param name="imageWriteDuration">Duration of image write</param>
        /// <param name="lastSector">Last sector number</param>
        /// <param name="leadOutExtents">Lead-out extents</param>
        /// <param name="maxSpeed">Maximum speed</param>
        /// <param name="mhddLog">MHDD log</param>
        /// <param name="minSpeed">Minimum speed</param>
        /// <param name="newTrim">Is trim a new one?</param>
        /// <param name="nextData">Next cluster of sectors is all data</param>
        /// <param name="offsetBytes">Read offset</param>
        /// <param name="read6">Device supports READ(6)</param>
        /// <param name="read10">Device supports READ(10)</param>
        /// <param name="read12">Device supports READ(12)</param>
        /// <param name="read16">Device supports READ(16)</param>
        /// <param name="readcd">Device supports READ CD</param>
        /// <param name="sectorsForOffset">Sectors needed to fix offset</param>
        /// <param name="subSize">Subchannel size in bytes</param>
        /// <param name="supportedSubchannel">Drive's maximum supported subchannel</param>
        /// <param name="supportsLongSectors">Supports reading EDC and ECC</param>
        /// <param name="totalDuration">Total commands duration</param>
        void ReadCdData(ExtentsULong audioExtents, ulong blocks, uint blockSize, ref double currentSpeed,
                        DumpHardwareType currentTry, ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration,
                        long lastSector, ExtentsULong leadOutExtents, ref double maxSpeed, MhddLog mhddLog,
                        ref double minSpeed, out bool newTrim, bool nextData, int offsetBytes, bool read6, bool read10,
                        bool read12, bool read16, bool readcd, int sectorsForOffset, uint subSize,
                        MmcSubchannel supportedSubchannel, bool supportsLongSectors, ref double totalDuration,
                        Track[] tracks)
        {
            ulong    sectorSpeedStart = 0;                 // Used to calculate correct speed
            DateTime timeSpeedStart   = DateTime.UtcNow;   // Time of start for speed calculation
            uint     blocksToRead     = 0;                 // How many sectors to read at once
            bool     sense            = true;              // Sense indicator

            byte[]     cmdBuf      = null;                 // Data buffer
            byte[]     senseBuf    = null;                 // Sense buffer
            double     cmdDuration = 0;                    // Command execution time
            const uint sectorSize  = 2352;                 // Full sector size

            byte[] tmpBuf;                                 // Temporary buffer
            newTrim = false;

            InitProgress?.Invoke();

            bool crossingLeadOut       = false;
            bool failedCrossingLeadOut = false;

            for (ulong i = _resume.NextBlock; (long)i <= lastSector; i += blocksToRead)
            {
                if (_aborted)
                {
                    currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                    UpdateStatus?.Invoke("Aborted!");
                    _dumpLog.WriteLine("Aborted!");

                    break;
                }

                while (leadOutExtents.Contains(i))
                {
                    i++;
                }

                if ((long)i > lastSector)
                {
                    break;
                }

                uint firstSectorToRead = (uint)i;

                Track track = tracks.OrderBy(t => t.TrackStartSector).LastOrDefault(t => i >= t.TrackStartSector);

                blocksToRead = 0;
                bool inData = nextData;

                for (ulong j = i; j < i + _maximumReadable; j++)
                {
                    if (j > (ulong)lastSector)
                    {
                        if (!failedCrossingLeadOut)
                        {
                            blocksToRead += (uint)sectorsForOffset;
                        }

                        if (sectorsForOffset > 0)
                        {
                            crossingLeadOut = true;
                        }

                        break;
                    }

                    if (nextData)
                    {
                        if (audioExtents.Contains(j))
                        {
                            nextData = false;

                            break;
                        }

                        blocksToRead++;
                    }
                    else
                    {
                        if (!audioExtents.Contains(j))
                        {
                            nextData = true;

                            break;
                        }

                        blocksToRead++;
                    }
                }

                if (track.TrackSequence != 0 &&
                    (i + blocksToRead) - (ulong)sectorsForOffset > track.TrackEndSector + 1)
                {
                    blocksToRead = (uint)(((track.TrackEndSector + 1) - i) + (ulong)sectorsForOffset);
                }

                if (blocksToRead == 1)
                {
                    blocksToRead += (uint)sectorsForOffset;
                }

                if (_fixOffset && !inData)
                {
                    // TODO: FreeBSD bug
                    if (offsetBytes < 0)
                    {
                        if (i == 0)
                        {
                            firstSectorToRead = uint.MaxValue - (uint)(sectorsForOffset - 1); // -1
                        }
                        else
                        {
                            firstSectorToRead -= (uint)sectorsForOffset;
                        }
                    }
                }

                #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator

                // ReSharper disable CompareOfFloatsByEqualityOperator
                if (currentSpeed > maxSpeed &&
                    currentSpeed != 0)
                {
                    maxSpeed = currentSpeed;
                }

                if (currentSpeed < minSpeed &&
                    currentSpeed != 0)
                {
                    minSpeed = currentSpeed;
                }

                // ReSharper restore CompareOfFloatsByEqualityOperator

                #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator

                UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
                                       (long)blocks);

                if (readcd)
                {
                    sense = _dev.ReadCd(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, blocksToRead,
                                        MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
                                        true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration);

                    totalDuration += cmdDuration;
                }
                else if (read16)
                {
                    sense = _dev.Read16(out cmdBuf, out senseBuf, 0, false, true, false, firstSectorToRead, blockSize,
                                        0, blocksToRead, false, _dev.Timeout, out cmdDuration);
                }
                else if (read12)
                {
                    sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, firstSectorToRead,
                                        blockSize, 0, blocksToRead, false, _dev.Timeout, out cmdDuration);
                }
                else if (read10)
                {
                    sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, firstSectorToRead,
                                        blockSize, 0, (ushort)blocksToRead, _dev.Timeout, out cmdDuration);
                }
                else if (read6)
                {
                    sense = _dev.Read6(out cmdBuf, out senseBuf, firstSectorToRead, blockSize, (byte)blocksToRead,
                                       _dev.Timeout, out cmdDuration);
                }

                // Because one block has been partially used to fix the offset
                if (_fixOffset &&
                    !inData &&
                    offsetBytes != 0)
                {
                    int offsetFix = offsetBytes < 0 ? (int)(sectorSize - (offsetBytes * -1)) : offsetBytes;

                    if (supportedSubchannel != MmcSubchannel.None)
                    {
                        // De-interleave subchannel
                        byte[] data = new byte[sectorSize * blocksToRead];
                        byte[] sub  = new byte[subSize * blocksToRead];

                        for (int b = 0; b < blocksToRead; b++)
                        {
                            Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);
                            Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
                        }

                        if (failedCrossingLeadOut)
                        {
                            blocksToRead += (uint)sectorsForOffset;

                            tmpBuf = new byte[sectorSize * blocksToRead];
                            Array.Copy(data, 0, tmpBuf, 0, data.Length);
                            data   = tmpBuf;
                            tmpBuf = new byte[subSize * blocksToRead];
                            Array.Copy(sub, 0, tmpBuf, 0, sub.Length);
                            sub = tmpBuf;
                        }

                        tmpBuf = new byte[sectorSize * (blocksToRead - sectorsForOffset)];
                        Array.Copy(data, offsetFix, tmpBuf, 0, tmpBuf.Length);
                        data = tmpBuf;

                        blocksToRead -= (uint)sectorsForOffset;

                        // Re-interleave subchannel
                        cmdBuf = new byte[blockSize * blocksToRead];

                        for (int b = 0; b < blocksToRead; b++)
                        {
                            Array.Copy(data, sectorSize * b, cmdBuf, (int)(0 + (b * blockSize)), sectorSize);
                            Array.Copy(sub, subSize * b, cmdBuf, (int)(sectorSize + (b * blockSize)), subSize);
                        }
                    }
                    else
                    {
                        if (failedCrossingLeadOut)
                        {
                            blocksToRead += (uint)sectorsForOffset;

                            tmpBuf = new byte[blockSize * blocksToRead];
                            Array.Copy(cmdBuf, 0, tmpBuf, 0, cmdBuf.Length);
                            cmdBuf = tmpBuf;
                        }

                        tmpBuf = new byte[blockSize * (blocksToRead - sectorsForOffset)];
                        Array.Copy(cmdBuf, offsetFix, tmpBuf, 0, tmpBuf.Length);
                        cmdBuf        = tmpBuf;
                        blocksToRead -= (uint)sectorsForOffset;
                    }
                }

                if (!sense &&
                    !_dev.Error)
                {
                    mhddLog.Write(i, cmdDuration);
                    ibgLog.Write(i, currentSpeed * 1024);
                    extents.Add(i, blocksToRead, true);
                    DateTime writeStart = DateTime.Now;

                    if (supportedSubchannel != MmcSubchannel.None)
                    {
                        byte[] data = new byte[sectorSize * blocksToRead];
                        byte[] sub  = new byte[subSize * blocksToRead];

                        for (int b = 0; b < blocksToRead; b++)
                        {
                            Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), data, sectorSize * b, sectorSize);

                            Array.Copy(cmdBuf, (int)(sectorSize + (b * blockSize)), sub, subSize * b, subSize);
                        }

                        _outputPlugin.WriteSectorsLong(data, i, blocksToRead);
                        _outputPlugin.WriteSectorsTag(sub, i, blocksToRead, SectorTagType.CdSectorSubchannel);
                    }
                    else
                    {
                        if (supportsLongSectors)
                        {
                            _outputPlugin.WriteSectorsLong(cmdBuf, i, blocksToRead);
                        }
                        else
                        {
                            if (cmdBuf.Length % sectorSize == 0)
                            {
                                byte[] data = new byte[2048 * blocksToRead];

                                for (int b = 0; b < blocksToRead; b++)
                                {
                                    Array.Copy(cmdBuf, (int)(16 + (b * blockSize)), data, 2048 * b, 2048);
                                }

                                _outputPlugin.WriteSectors(data, i, blocksToRead);
                            }
                            else
                            {
                                _outputPlugin.WriteSectorsLong(cmdBuf, i, blocksToRead);
                            }
                        }
                    }

                    imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
                }
                else
                {
                    if (crossingLeadOut && Sense.DecodeFixed(senseBuf)?.ASC == 0x21)
                    {
                        failedCrossingLeadOut = true;
                        blocksToRead          = 0;

                        continue;
                    }

                    // TODO: Reset device after X errors
                    if (_stopOnError)
                    {
                        return; // TODO: Return more cleanly
                    }
                    if (i + _skip > blocks)
                    {
                        _skip = (uint)(blocks - i);
                    }

                    // Write empty data
                    DateTime writeStart = DateTime.Now;

                    if (supportedSubchannel != MmcSubchannel.None)
                    {
                        _outputPlugin.WriteSectorsLong(new byte[sectorSize * _skip], i, _skip);

                        _outputPlugin.WriteSectorsTag(new byte[subSize * _skip], i, _skip,
                                                      SectorTagType.CdSectorSubchannel);
                    }
                    else
                    {
                        if (supportsLongSectors)
                        {
                            _outputPlugin.WriteSectorsLong(new byte[blockSize * _skip], i, _skip);
                        }
                        else
                        {
                            if (cmdBuf.Length % sectorSize == 0)
                            {
                                _outputPlugin.WriteSectors(new byte[2048 * _skip], i, _skip);
                            }
                            else
                            {
                                _outputPlugin.WriteSectorsLong(new byte[blockSize * _skip], i, _skip);
                            }
                        }
                    }

                    imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;

                    for (ulong b = i; b < i + _skip; b++)
                    {
                        _resume.BadBlocks.Add(b);
                    }

                    DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Sense.PrettifySense(senseBuf));
                    mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);

                    ibgLog.Write(i, 0);
                    _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
                    i      += _skip - blocksToRead;
                    newTrim = true;
                }

                sectorSpeedStart += blocksToRead;

                _resume.NextBlock = i + blocksToRead;

                double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;

                if (elapsed < 1)
                {
                    continue;
                }

                currentSpeed     = (sectorSpeedStart * blockSize) / (1048576 * elapsed);
                sectorSpeedStart = 0;
                timeSpeedStart   = DateTime.UtcNow;
            }

            EndProgress?.Invoke();

            if (!failedCrossingLeadOut)
            {
                return;
            }

            _dumpLog.WriteLine("Failed crossing into Lead-Out, dump may not be correct.");
            UpdateStatus?.Invoke("Failed crossing into Lead-Out, dump may not be correct.");
        }
Beispiel #23
0
        void DumpUmd()
        {
            const uint      blockSize     = 2048;
            const MediaType dskType       = MediaType.UMD;
            uint            blocksToRead  = 16;
            double          totalDuration = 0;
            double          currentSpeed  = 0;
            double          maxSpeed      = double.MinValue;
            double          minSpeed      = double.MaxValue;
            DateTime        start;
            DateTime        end;

            byte[] senseBuf;

            bool sense = _dev.Read12(out byte[] readBuffer, out _, 0, false, true, false, false, 0, 512, 0, 1, false,
                                     _dev.Timeout, out _);

            if (sense)
            {
                _dumpLog.WriteLine("Could not read...");
                StoppingErrorMessage?.Invoke("Could not read...");

                return;
            }

            ushort fatStart      = (ushort)((readBuffer[0x0F] << 8) + readBuffer[0x0E]);
            ushort sectorsPerFat = (ushort)((readBuffer[0x17] << 8) + readBuffer[0x16]);
            ushort rootStart     = (ushort)((sectorsPerFat * 2) + fatStart);
            ushort rootSize      = (ushort)((((readBuffer[0x12] << 8) + readBuffer[0x11]) * 32) / 512);
            ushort umdStart      = (ushort)(rootStart + rootSize);

            UpdateStatus?.Invoke($"Reading root directory in sector {rootStart}...");
            _dumpLog.WriteLine("Reading root directory in sector {0}...", rootStart);

            sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, rootStart, 512, 0, 1, false,
                                _dev.Timeout, out _);

            if (sense)
            {
                _dumpLog.WriteLine("Could not read...");
                StoppingErrorMessage?.Invoke("Could not read...");

                return;
            }

            uint   umdSizeInBytes  = BitConverter.ToUInt32(readBuffer, 0x3C);
            ulong  blocks          = umdSizeInBytes / blockSize;
            string mediaPartNumber = Encoding.ASCII.GetString(readBuffer, 0, 11).Trim();

            ulong totalSize = blocks * blockSize;

            if (totalSize > 1099511627776)
            {
                UpdateStatus?.
                Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1099511627776d:F3} TiB)");
            }
            else if (totalSize > 1073741824)
            {
                UpdateStatus?.
                Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1073741824d:F3} GiB)");
            }
            else if (totalSize > 1048576)
            {
                UpdateStatus?.
                Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1048576d:F3} MiB)");
            }
            else if (totalSize > 1024)
            {
                UpdateStatus?.
                Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize / 1024d:F3} KiB)");
            }
            else
            {
                UpdateStatus?.
                Invoke($"Media has {blocks} blocks of {blockSize} bytes/each. (for a total of {totalSize} bytes)");
            }

            UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * blockSize} bytes).");
            UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time.");
            UpdateStatus?.Invoke($"Device reports {blockSize} bytes per logical block.");
            UpdateStatus?.Invoke($"Device reports {2048} bytes per physical block.");
            UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}.");
            UpdateStatus?.Invoke($"Media identified as {dskType}.");
            UpdateStatus?.Invoke($"Media part number is {mediaPartNumber}.");
            _dumpLog.WriteLine("Device reports {0} blocks ({1} bytes).", blocks, blocks * blockSize);
            _dumpLog.WriteLine("Device can read {0} blocks at a time.", blocksToRead);
            _dumpLog.WriteLine("Device reports {0} bytes per logical block.", blockSize);
            _dumpLog.WriteLine("Device reports {0} bytes per physical block.", 2048);
            _dumpLog.WriteLine("SCSI device type: {0}.", _dev.ScsiType);
            _dumpLog.WriteLine("Media identified as {0}.", dskType);
            _dumpLog.WriteLine("Media part number is {0}.", mediaPartNumber);

            bool ret;

            var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, blockSize, blocksToRead, _private);
            var ibgLog  = new IbgLog(_outputPrefix + ".ibg", 0x0010);

            ret = _outputPlugin.Create(_outputPath, dskType, _formatOptions, blocks, blockSize);

            // Cannot create image
            if (!ret)
            {
                _dumpLog.WriteLine("Error creating output image, not continuing.");
                _dumpLog.WriteLine(_outputPlugin.ErrorMessage);

                StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine +
                                             _outputPlugin.ErrorMessage);

                return;
            }

            start = DateTime.UtcNow;
            double imageWriteDuration = 0;

            (_outputPlugin as IWritableOpticalImage)?.SetTracks(new List <Track>
            {
                new Track
                {
                    TrackBytesPerSector    = (int)blockSize,
                    TrackEndSector         = blocks - 1,
                    TrackSequence          = 1,
                    TrackRawBytesPerSector = (int)blockSize,
                    TrackSubchannelType    = TrackSubchannelType.None,
                    TrackSession           = 1,
                    TrackType = TrackType.Data
                }
            });

            DumpHardwareType currentTry = null;
            ExtentsULong     extents    = null;

            ResumeSupport.Process(true, _dev.IsRemovable, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial,
                                  _dev.PlatformId, ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision,
                                  _private);

            if (currentTry == null ||
                extents == null)
            {
                StoppingErrorMessage?.Invoke("Could not process resume file, not continuing...");

                return;
            }

            if (_resume.NextBlock > 0)
            {
                _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock);
            }

            bool newTrim = false;

            DateTime timeSpeedStart   = DateTime.UtcNow;
            ulong    sectorSpeedStart = 0;

            InitProgress?.Invoke();

            for (ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
            {
                if (_aborted)
                {
                    currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                    UpdateStatus?.Invoke("Aborted!");
                    _dumpLog.WriteLine("Aborted!");

                    break;
                }

                if (blocks - i < blocksToRead)
                {
                    blocksToRead = (uint)(blocks - i);
                }

                if (currentSpeed > maxSpeed &&
                    currentSpeed > 0)
                {
                    maxSpeed = currentSpeed;
                }

                if (currentSpeed < minSpeed &&
                    currentSpeed > 0)
                {
                    minSpeed = currentSpeed;
                }

                UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i,
                                       (long)blocks);

                sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false,
                                    (uint)(umdStart + (i * 4)), 512, 0, blocksToRead * 4, false, _dev.Timeout,
                                    out double cmdDuration);

                totalDuration += cmdDuration;

                if (!sense &&
                    !_dev.Error)
                {
                    mhddLog.Write(i, cmdDuration);
                    ibgLog.Write(i, currentSpeed * 1024);
                    DateTime writeStart = DateTime.Now;
                    _outputPlugin.WriteSectors(readBuffer, i, blocksToRead);
                    imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
                    extents.Add(i, blocksToRead, true);
                }
                else
                {
                    _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf);

                    // TODO: Reset device after X errors
                    if (_stopOnError)
                    {
                        return; // TODO: Return more cleanly
                    }
                    if (i + _skip > blocks)
                    {
                        _skip = (uint)(blocks - i);
                    }

                    // Write empty data
                    DateTime writeStart = DateTime.Now;
                    _outputPlugin.WriteSectors(new byte[blockSize * _skip], i, _skip);
                    imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;

                    for (ulong b = i; b < i + _skip; b++)
                    {
                        _resume.BadBlocks.Add(b);
                    }

                    mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);

                    ibgLog.Write(i, 0);
                    _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
                    i      += _skip - blocksToRead;
                    newTrim = true;
                }

                sectorSpeedStart += blocksToRead;
                _resume.NextBlock = i + blocksToRead;

                double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;

                if (elapsed < 1)
                {
                    continue;
                }

                currentSpeed     = (sectorSpeedStart * blockSize) / (1048576 * elapsed);
                sectorSpeedStart = 0;
                timeSpeedStart   = DateTime.UtcNow;
            }

            end = DateTime.UtcNow;
            EndProgress?.Invoke();
            mhddLog.Close();

            ibgLog.Close(_dev, blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024,
                         (blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000), _devicePath);

            UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds.");

            UpdateStatus?.
            Invoke($"Average dump speed {((double)blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000):F3} KiB/sec.");

            UpdateStatus?.
            Invoke($"Average write speed {((double)blockSize * (double)(blocks + 1)) / 1024 / imageWriteDuration:F3} KiB/sec.");

            _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);

            _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
                               ((double)blockSize * (double)(blocks + 1)) / 1024 / (totalDuration / 1000));

            _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
                               ((double)blockSize * (double)(blocks + 1)) / 1024 / imageWriteDuration);

            #region Trimming
            if (_resume.BadBlocks.Count > 0 &&
                !_aborted &&
                _trim &&
                newTrim)
            {
                start = DateTime.UtcNow;
                _dumpLog.WriteLine("Trimming skipped sectors");

                ulong[] tmpArray = _resume.BadBlocks.ToArray();
                InitProgress?.Invoke();

                foreach (ulong badSector in tmpArray)
                {
                    if (_aborted)
                    {
                        currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                        _dumpLog.WriteLine("Aborted!");

                        break;
                    }

                    PulseProgress?.Invoke($"Trimming sector {badSector}");

                    sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false,
                                        (uint)(umdStart + (badSector * 4)), 512, 0, 4, false, _dev.Timeout,
                                        out double _);

                    if (sense || _dev.Error)
                    {
                        _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf);

                        continue;
                    }

                    _resume.BadBlocks.Remove(badSector);
                    extents.Add(badSector);
                    _outputPlugin.WriteSector(readBuffer, badSector);
                }

                EndProgress?.Invoke();
                end = DateTime.UtcNow;
                _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds);
            }
            #endregion Trimming

            #region Error handling
            if (_resume.BadBlocks.Count > 0 &&
                !_aborted &&
                _retryPasses > 0)
            {
                int  pass              = 1;
                bool forward           = true;
                bool runningPersistent = false;

                Modes.ModePage?currentModePage = null;
                byte[]         md6;

                if (_persistent)
                {
                    Modes.ModePage_01 pg;

                    sense = _dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01,
                                            _dev.Timeout, out _);

                    if (!sense)
                    {
                        Modes.DecodedMode?dcMode6 = Modes.DecodeMode6(readBuffer, _dev.ScsiType);

                        if (dcMode6.HasValue)
                        {
                            foreach (Modes.ModePage modePage in dcMode6.Value.Pages.Where(modePage =>
                                                                                          modePage.Page == 0x01 &&
                                                                                          modePage.Subpage == 0x00))
                            {
                                currentModePage = modePage;
                            }
                        }
                    }

                    if (currentModePage == null)
                    {
                        pg = new Modes.ModePage_01
                        {
                            PS             = false,
                            AWRE           = true,
                            ARRE           = true,
                            TB             = false,
                            RC             = false,
                            EER            = true,
                            PER            = false,
                            DTE            = true,
                            DCR            = false,
                            ReadRetryCount = 32
                        };

                        currentModePage = new Modes.ModePage
                        {
                            Page         = 0x01,
                            Subpage      = 0x00,
                            PageResponse = Modes.EncodeModePage_01(pg)
                        };
                    }

                    pg = new Modes.ModePage_01
                    {
                        PS             = false,
                        AWRE           = false,
                        ARRE           = false,
                        TB             = true,
                        RC             = false,
                        EER            = true,
                        PER            = false,
                        DTE            = false,
                        DCR            = false,
                        ReadRetryCount = 255
                    };

                    var md = new Modes.DecodedMode
                    {
                        Header = new Modes.ModeHeader(),
                        Pages  = new[]
                        {
                            new Modes.ModePage
                            {
                                Page         = 0x01,
                                Subpage      = 0x00,
                                PageResponse = Modes.EncodeModePage_01(pg)
                            }
                        }
                    };

                    md6 = Modes.EncodeMode6(md, _dev.ScsiType);

                    _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks).");
                    sense = _dev.ModeSelect(md6, 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();
repeatRetry:
                ulong[] tmpArray = _resume.BadBlocks.ToArray();

                foreach (ulong badSector in tmpArray)
                {
                    if (_aborted)
                    {
                        currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                        _dumpLog.WriteLine("Aborted!");

                        break;
                    }

                    PulseProgress?.
                    Invoke($"Retrying sector {badSector}, pass {pass}, {(runningPersistent ? "recovering partial data, " : "")}{(forward ? "forward" : "reverse")}");

                    sense = _dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false,
                                        (uint)(umdStart + (badSector * 4)), 512, 0, 4, false, _dev.Timeout,
                                        out double cmdDuration);

                    totalDuration += cmdDuration;

                    if (sense || _dev.Error)
                    {
                        _errorLog?.WriteLine(badSector, _dev.Error, _dev.LastError, senseBuf);
                    }

                    if (!sense &&
                        !_dev.Error)
                    {
                        _resume.BadBlocks.Remove(badSector);
                        extents.Add(badSector);
                        _outputPlugin.WriteSector(readBuffer, badSector);

                        UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}.");

                        _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
                    }
                    else if (runningPersistent)
                    {
                        _outputPlugin.WriteSector(readBuffer, badSector);
                    }
                }

                if (pass < _retryPasses &&
                    !_aborted &&
                    _resume.BadBlocks.Count > 0)
                {
                    pass++;
                    forward = !forward;
                    _resume.BadBlocks.Sort();

                    if (!forward)
                    {
                        _resume.BadBlocks.Reverse();
                    }

                    goto repeatRetry;
                }

                if (runningPersistent && currentModePage.HasValue)
                {
                    var md = new Modes.DecodedMode
                    {
                        Header = new Modes.ModeHeader(),
                        Pages  = new[]
                        {
                            currentModePage.Value
                        }
                    };

                    md6 = Modes.EncodeMode6(md, _dev.ScsiType);

                    _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status).");
                    _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _);
                }

                EndProgress?.Invoke();
                AaruConsole.WriteLine();
            }
            #endregion Error handling

            _resume.BadBlocks.Sort();

            foreach (ulong bad in _resume.BadBlocks)
            {
                _dumpLog.WriteLine("Sector {0} could not be read.", bad);
            }

            currentTry.Extents = ExtentsConverter.ToMetadata(extents);

            var metadata = new CommonTypes.Structs.ImageInfo
            {
                Application        = "Aaru",
                ApplicationVersion = Version.GetVersion(),
                MediaPartNumber    = mediaPartNumber
            };

            if (!_outputPlugin.SetMetadata(metadata))
            {
                ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine +
                                     _outputPlugin.ErrorMessage);
            }

            _outputPlugin.SetDumpHardware(_resume.Tries);

            if (_preSidecar != null)
            {
                _outputPlugin.SetCicmMetadata(_preSidecar);
            }

            _dumpLog.WriteLine("Closing output file.");
            UpdateStatus?.Invoke("Closing output file.");
            DateTime closeStart = DateTime.Now;
            _outputPlugin.Close();
            DateTime closeEnd = DateTime.Now;
            _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds);

            if (_aborted)
            {
                UpdateStatus?.Invoke("Aborted!");
                _dumpLog.WriteLine("Aborted!");

                return;
            }

            double totalChkDuration = 0;

            if (_metadata)
            {
                WriteOpticalSidecar(blockSize, blocks, dskType, null, null, 1, out totalChkDuration, null);
            }

            UpdateStatus?.Invoke("");

            UpdateStatus?.
            Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing).");

            UpdateStatus?.
            Invoke($"Average speed: {((double)blockSize * (double)(blocks + 1)) / 1048576 / (totalDuration / 1000):F3} MiB/sec.");

            if (maxSpeed > 0)
            {
                UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec.");
            }

            if (minSpeed > 0 &&
                minSpeed < double.MaxValue)
            {
                UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec.");
            }

            UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read.");
            UpdateStatus?.Invoke("");

            Statistics.AddMedia(dskType, true);
        }
Beispiel #24
0
        void DumpMs()
        {
            const ushort SBC_PROFILE   = 0x0001;
            const uint   BLOCK_SIZE    = 512;
            double       totalDuration = 0;
            double       currentSpeed  = 0;
            double       maxSpeed      = double.MinValue;
            double       minSpeed      = double.MaxValue;
            uint         blocksToRead  = 64;
            DateTime     start;
            DateTime     end;
            MediaType    dskType;
            bool         sense;

            sense = _dev.ReadCapacity(out byte[] readBuffer, out _, _dev.Timeout, out _);

            if (sense)
            {
                _dumpLog.WriteLine("Could not detect capacity...");
                StoppingErrorMessage?.Invoke("Could not detect capacity...");

                return;
            }

            uint blocks = (uint)((readBuffer[0] << 24) + (readBuffer[1] << 16) + (readBuffer[2] << 8) + readBuffer[3]);

            blocks++;

            UpdateStatus?.
            Invoke($"Media has {blocks} blocks of {BLOCK_SIZE} bytes/each. (for a total of {blocks * (ulong)BLOCK_SIZE} bytes)");

            if (blocks == 0)
            {
                _dumpLog.WriteLine("ERROR: Unable to read medium or empty medium present...");
                StoppingErrorMessage?.Invoke("Unable to read medium or empty medium present...");

                return;
            }

            UpdateStatus?.Invoke($"Device reports {blocks} blocks ({blocks * BLOCK_SIZE} bytes).");
            UpdateStatus?.Invoke($"Device can read {blocksToRead} blocks at a time.");
            UpdateStatus?.Invoke($"Device reports {BLOCK_SIZE} bytes per logical block.");
            UpdateStatus?.Invoke($"SCSI device type: {_dev.ScsiType}.");

            if (blocks > 262144)
            {
                dskType = MediaType.MemoryStickProDuo;
                _dumpLog.WriteLine("Media detected as MemoryStick Pro Duo...");
                UpdateStatus?.Invoke("Media detected as MemoryStick Pro Duo...");
            }
            else
            {
                dskType = MediaType.MemoryStickDuo;
                _dumpLog.WriteLine("Media detected as MemoryStick Duo...");
                UpdateStatus?.Invoke("Media detected as MemoryStick Duo...");
            }

            bool ret;

            var mhddLog = new MhddLog(_outputPrefix + ".mhddlog.bin", _dev, blocks, BLOCK_SIZE, blocksToRead, _private);
            var ibgLog  = new IbgLog(_outputPrefix + ".ibg", SBC_PROFILE);

            ret = _outputPlugin.Create(_outputPath, dskType, _formatOptions, blocks, BLOCK_SIZE);

            // Cannot create image
            if (!ret)
            {
                _dumpLog.WriteLine("Error creating output image, not continuing.");
                _dumpLog.WriteLine(_outputPlugin.ErrorMessage);

                StoppingErrorMessage?.Invoke("Error creating output image, not continuing." + Environment.NewLine +
                                             _outputPlugin.ErrorMessage);

                return;
            }

            start = DateTime.UtcNow;
            double imageWriteDuration = 0;

            DumpHardwareType currentTry = null;
            ExtentsULong     extents    = null;

            ResumeSupport.Process(true, _dev.IsRemovable, blocks, _dev.Manufacturer, _dev.Model, _dev.Serial,
                                  _dev.PlatformId, ref _resume, ref currentTry, ref extents, _dev.FirmwareRevision,
                                  _private);

            if (currentTry == null ||
                extents == null)
            {
                StoppingErrorMessage?.Invoke("Could not process resume file, not continuing...");

                return;
            }

            if (_resume.NextBlock > 0)
            {
                _dumpLog.WriteLine("Resuming from block {0}.", _resume.NextBlock);
            }

            bool newTrim = false;

            DateTime timeSpeedStart   = DateTime.UtcNow;
            ulong    sectorSpeedStart = 0;

            InitProgress?.Invoke();

            for (ulong i = _resume.NextBlock; i < blocks; i += blocksToRead)
            {
                if (_aborted)
                {
                    currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                    UpdateStatus?.Invoke("Aborted!");
                    _dumpLog.WriteLine("Aborted!");

                    break;
                }

                if (blocks - i < blocksToRead)
                {
                    blocksToRead = (uint)(blocks - i);
                }

                #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator
                if (currentSpeed > maxSpeed &&
                    currentSpeed != 0)
                {
                    maxSpeed = currentSpeed;
                }

                if (currentSpeed < minSpeed &&
                    currentSpeed != 0)
                {
                    minSpeed = currentSpeed;
                }
                #pragma warning restore RECS0018 // Comparison of floating point numbers with equality operator

                UpdateProgress?.Invoke($"Reading sector {i} of {blocks} ({currentSpeed:F3} MiB/sec.)", (long)i, blocks);

                sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)i, BLOCK_SIZE, 0,
                                    blocksToRead, false, _dev.Timeout, out double cmdDuration);

                totalDuration += cmdDuration;

                if (!sense &&
                    !_dev.Error)
                {
                    mhddLog.Write(i, cmdDuration);
                    ibgLog.Write(i, currentSpeed * 1024);
                    DateTime writeStart = DateTime.Now;
                    _outputPlugin.WriteSectors(readBuffer, i, blocksToRead);
                    imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
                    extents.Add(i, blocksToRead, true);
                }
                else
                {
                    // TODO: Reset device after X errors
                    if (_stopOnError)
                    {
                        return; // TODO: Return more cleanly
                    }
                    if (i + _skip > blocks)
                    {
                        _skip = (uint)(blocks - i);
                    }

                    // Write empty data
                    DateTime writeStart = DateTime.Now;
                    _outputPlugin.WriteSectors(new byte[BLOCK_SIZE * _skip], i, _skip);
                    imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;

                    for (ulong b = i; b < i + _skip; b++)
                    {
                        _resume.BadBlocks.Add(b);
                    }

                    mhddLog.Write(i, cmdDuration < 500 ? 65535 : cmdDuration);

                    ibgLog.Write(i, 0);
                    _dumpLog.WriteLine("Skipping {0} blocks from errored block {1}.", _skip, i);
                    i      += _skip - blocksToRead;
                    newTrim = true;
                }

                sectorSpeedStart += blocksToRead;
                _resume.NextBlock = i + blocksToRead;

                double elapsed = (DateTime.UtcNow - timeSpeedStart).TotalSeconds;

                if (elapsed < 1)
                {
                    continue;
                }

                currentSpeed     = (sectorSpeedStart * BLOCK_SIZE) / (1048576 * elapsed);
                sectorSpeedStart = 0;
                timeSpeedStart   = DateTime.UtcNow;
            }

            end = DateTime.UtcNow;
            EndProgress?.Invoke();
            mhddLog.Close();

            ibgLog.Close(_dev, blocks, BLOCK_SIZE, (end - start).TotalSeconds, currentSpeed * 1024,
                         (BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalDuration / 1000),
                         _devicePath);

            UpdateStatus?.Invoke($"Dump finished in {(end - start).TotalSeconds} seconds.");

            UpdateStatus?.
            Invoke($"Average dump speed {((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalDuration / 1000):F3} KiB/sec.");

            UpdateStatus?.
            Invoke($"Average write speed {((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / imageWriteDuration:F3} KiB/sec.");

            _dumpLog.WriteLine("Dump finished in {0} seconds.", (end - start).TotalSeconds);

            _dumpLog.WriteLine("Average dump speed {0:F3} KiB/sec.",
                               ((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalDuration / 1000));

            _dumpLog.WriteLine("Average write speed {0:F3} KiB/sec.",
                               ((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / imageWriteDuration);

            #region Trimming
            if (_resume.BadBlocks.Count > 0 &&
                !_aborted &&
                _trim &&
                newTrim)
            {
                start = DateTime.UtcNow;
                UpdateStatus?.Invoke("Trimming skipped sectors");
                _dumpLog.WriteLine("Trimming skipped sectors");

                ulong[] tmpArray = _resume.BadBlocks.ToArray();
                InitProgress?.Invoke();

                foreach (ulong badSector in tmpArray)
                {
                    if (_aborted)
                    {
                        currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                        UpdateStatus?.Invoke("Aborted!");
                        _dumpLog.WriteLine("Aborted!");

                        break;
                    }

                    PulseProgress?.Invoke($"Trimming sector {badSector}");

                    sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)badSector,
                                        BLOCK_SIZE, 0, 1, false, _dev.Timeout, out double cmdDuration);

                    if (sense || _dev.Error)
                    {
                        continue;
                    }

                    _resume.BadBlocks.Remove(badSector);
                    extents.Add(badSector);
                    _outputPlugin.WriteSector(readBuffer, badSector);
                }

                EndProgress?.Invoke();
                end = DateTime.UtcNow;
                _dumpLog.WriteLine("Trimmming finished in {0} seconds.", (end - start).TotalSeconds);
            }
            #endregion Trimming

            #region Error handling
            if (_resume.BadBlocks.Count > 0 &&
                !_aborted &&
                _retryPasses > 0)
            {
                int  pass              = 1;
                bool forward           = true;
                bool runningPersistent = false;

                Modes.ModePage?currentModePage = null;
                byte[]         md6;

                if (_persistent)
                {
                    Modes.ModePage_01 pg;

                    sense = _dev.ModeSense6(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01,
                                            _dev.Timeout, out _);

                    if (sense)
                    {
                        sense = _dev.ModeSense10(out readBuffer, out _, false, ScsiModeSensePageControl.Current, 0x01,
                                                 _dev.Timeout, out _);

                        if (!sense)
                        {
                            Modes.DecodedMode?dcMode10 = Modes.DecodeMode10(readBuffer, _dev.ScsiType);

                            if (dcMode10.HasValue)
                            {
                                foreach (Modes.ModePage modePage in dcMode10.Value.Pages)
                                {
                                    if (modePage.Page == 0x01 &&
                                        modePage.Subpage == 0x00)
                                    {
                                        currentModePage = modePage;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        Modes.DecodedMode?dcMode6 = Modes.DecodeMode6(readBuffer, _dev.ScsiType);

                        if (dcMode6.HasValue)
                        {
                            foreach (Modes.ModePage modePage in dcMode6.Value.Pages)
                            {
                                if (modePage.Page == 0x01 &&
                                    modePage.Subpage == 0x00)
                                {
                                    currentModePage = modePage;
                                }
                            }
                        }
                    }

                    if (currentModePage == null)
                    {
                        pg = new Modes.ModePage_01
                        {
                            PS  = false, AWRE = true, ARRE = true, TB = false,
                            RC  = false, EER = true, PER = false, DTE = true,
                            DCR = false, ReadRetryCount = 32
                        };

                        currentModePage = new Modes.ModePage
                        {
                            Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01(pg)
                        };
                    }

                    pg = new Modes.ModePage_01
                    {
                        PS  = false, AWRE = false, ARRE = false, TB = true,
                        RC  = false, EER = true, PER = false, DTE = false,
                        DCR = false, ReadRetryCount = 255
                    };

                    var md = new Modes.DecodedMode
                    {
                        Header = new Modes.ModeHeader(), Pages = new[]
                        {
                            new Modes.ModePage
                            {
                                Page = 0x01, Subpage = 0x00, PageResponse = Modes.EncodeModePage_01(pg)
                            }
                        }
                    };

                    md6 = Modes.EncodeMode6(md, _dev.ScsiType);

                    UpdateStatus?.Invoke("Sending MODE SELECT to drive (return damaged blocks).");
                    _dumpLog.WriteLine("Sending MODE SELECT to drive (return damaged blocks).");
                    sense = _dev.ModeSelect(md6, out byte[] senseBuf, true, false, _dev.Timeout, out _);

                    if (sense)
                    {
                        UpdateStatus?.
                        Invoke("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");

                        AaruConsole.DebugWriteLine("Error: {0}", Sense.PrettifySense(senseBuf));

                        _dumpLog.
                        WriteLine("Drive did not accept MODE SELECT command for persistent error reading, try another drive.");
                    }
                    else
                    {
                        runningPersistent = true;
                    }
                }

                InitProgress?.Invoke();
repeatRetry:
                ulong[] tmpArray = _resume.BadBlocks.ToArray();

                foreach (ulong badSector in tmpArray)
                {
                    if (_aborted)
                    {
                        currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                        _dumpLog.WriteLine("Aborted!");

                        break;
                    }

                    PulseProgress?.Invoke(string.Format("Retrying sector {0}, pass {1}, {3}{2}", badSector, pass,
                                                        forward ? "forward" : "reverse",
                                                        runningPersistent ? "recovering partial data, " : ""));

                    sense = _dev.Read12(out readBuffer, out _, 0, false, true, false, false, (uint)badSector,
                                        BLOCK_SIZE, 0, 1, false, _dev.Timeout, out double cmdDuration);

                    totalDuration += cmdDuration;

                    if (!sense &&
                        !_dev.Error)
                    {
                        _resume.BadBlocks.Remove(badSector);
                        extents.Add(badSector);
                        _outputPlugin.WriteSector(readBuffer, badSector);
                        UpdateStatus?.Invoke($"Correctly retried block {badSector} in pass {pass}.");
                        _dumpLog.WriteLine("Correctly retried block {0} in pass {1}.", badSector, pass);
                    }
                    else if (runningPersistent)
                    {
                        _outputPlugin.WriteSector(readBuffer, badSector);
                    }
                }

                if (pass < _retryPasses &&
                    !_aborted &&
                    _resume.BadBlocks.Count > 0)
                {
                    pass++;
                    forward = !forward;
                    _resume.BadBlocks.Sort();
                    _resume.BadBlocks.Reverse();

                    goto repeatRetry;
                }

                if (runningPersistent && currentModePage.HasValue)
                {
                    var md = new Modes.DecodedMode
                    {
                        Header = new Modes.ModeHeader(), Pages = new[]
                        {
                            currentModePage.Value
                        }
                    };

                    md6 = Modes.EncodeMode6(md, _dev.ScsiType);

                    UpdateStatus?.Invoke("Sending MODE SELECT to drive (return device to previous status).");
                    _dumpLog.WriteLine("Sending MODE SELECT to drive (return device to previous status).");
                    sense = _dev.ModeSelect(md6, out _, true, false, _dev.Timeout, out _);
                }

                EndProgress?.Invoke();
            }
            #endregion Error handling

            _resume.BadBlocks.Sort();

            foreach (ulong bad in _resume.BadBlocks)
            {
                _dumpLog.WriteLine("Sector {0} could not be read.", bad);
            }

            currentTry.Extents = ExtentsConverter.ToMetadata(extents);

            var metadata = new CommonTypes.Structs.ImageInfo
            {
                Application = "Aaru", ApplicationVersion = Version.GetVersion()
            };

            if (!_outputPlugin.SetMetadata(metadata))
            {
                ErrorMessage?.Invoke("Error {0} setting metadata, continuing..." + Environment.NewLine +
                                     _outputPlugin.ErrorMessage);
            }

            _outputPlugin.SetDumpHardware(_resume.Tries);

            if (_preSidecar != null)
            {
                _outputPlugin.SetCicmMetadata(_preSidecar);
            }

            _dumpLog.WriteLine("Closing output file.");
            UpdateStatus?.Invoke("Closing output file.");
            DateTime closeStart = DateTime.Now;
            _outputPlugin.Close();
            DateTime closeEnd = DateTime.Now;
            UpdateStatus?.Invoke($"Closed in {(closeEnd - closeStart).TotalSeconds} seconds.");
            _dumpLog.WriteLine("Closed in {0} seconds.", (closeEnd - closeStart).TotalSeconds);

            if (_aborted)
            {
                UpdateStatus?.Invoke("Aborted!");
                _dumpLog.WriteLine("Aborted!");

                return;
            }

            double totalChkDuration = 0;

            if (_metadata)
            {
                UpdateStatus?.Invoke("Creating sidecar.");
                _dumpLog.WriteLine("Creating sidecar.");
                var         filters     = new FiltersList();
                IFilter     filter      = filters.GetFilter(_outputPath);
                IMediaImage inputPlugin = ImageFormat.Detect(filter);

                if (!inputPlugin.Open(filter))
                {
                    StoppingErrorMessage?.Invoke("Could not open created image.");

                    return;
                }

                DateTime chkStart = DateTime.UtcNow;
                _sidecarClass = new Sidecar(inputPlugin, _outputPath, filter.Id, _encoding);
                _sidecarClass.InitProgressEvent    += InitProgress;
                _sidecarClass.UpdateProgressEvent  += UpdateProgress;
                _sidecarClass.EndProgressEvent     += EndProgress;
                _sidecarClass.InitProgressEvent2   += InitProgress2;
                _sidecarClass.UpdateProgressEvent2 += UpdateProgress2;
                _sidecarClass.EndProgressEvent2    += EndProgress2;
                _sidecarClass.UpdateStatusEvent    += UpdateStatus;
                CICMMetadataType sidecar = _sidecarClass.Create();
                end = DateTime.UtcNow;

                totalChkDuration = (end - chkStart).TotalMilliseconds;
                UpdateStatus?.Invoke($"Sidecar created in {(end - chkStart).TotalSeconds} seconds.");

                UpdateStatus?.
                Invoke($"Average checksum speed {((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalChkDuration / 1000):F3} KiB/sec.");

                _dumpLog.WriteLine("Sidecar created in {0} seconds.", (end - chkStart).TotalSeconds);

                _dumpLog.WriteLine("Average checksum speed {0:F3} KiB/sec.",
                                   ((double)BLOCK_SIZE * (double)(blocks + 1)) / 1024 / (totalChkDuration / 1000));

                if (_preSidecar != null)
                {
                    _preSidecar.BlockMedia = sidecar.BlockMedia;
                    sidecar = _preSidecar;
                }

                List <(ulong start, string type)> filesystems = new List <(ulong start, string type)>();

                if (sidecar.BlockMedia[0].FileSystemInformation != null)
                {
                    filesystems.AddRange(from partition in sidecar.BlockMedia[0].FileSystemInformation
                                         where partition.FileSystems != null from fileSystem in partition.FileSystems
                                         select(partition.StartSector, fileSystem.Type));
                }

                if (filesystems.Count > 0)
                {
                    foreach (var filesystem in filesystems.Select(o => new
                    {
                        o.start, o.type
                    }).Distinct())
                    {
                        UpdateStatus?.Invoke($"Found filesystem {filesystem.type} at sector {filesystem.start}");
                        _dumpLog.WriteLine("Found filesystem {0} at sector {1}", filesystem.type, filesystem.start);
                    }
                }

                sidecar.BlockMedia[0].Dimensions        = Dimensions.DimensionsFromMediaType(dskType);
                (string type, string subType)xmlType    = CommonTypes.Metadata.MediaType.MediaTypeToString(dskType);
                sidecar.BlockMedia[0].DiskType          = xmlType.type;
                sidecar.BlockMedia[0].DiskSubType       = xmlType.subType;
                sidecar.BlockMedia[0].Interface         = "USB";
                sidecar.BlockMedia[0].LogicalBlocks     = blocks;
                sidecar.BlockMedia[0].PhysicalBlockSize = (int)BLOCK_SIZE;
                sidecar.BlockMedia[0].LogicalBlockSize  = (int)BLOCK_SIZE;
                sidecar.BlockMedia[0].Manufacturer      = _dev.Manufacturer;
                sidecar.BlockMedia[0].Model             = _dev.Model;

                if (!_private)
                {
                    sidecar.BlockMedia[0].Serial = _dev.Serial;
                }

                sidecar.BlockMedia[0].Size = blocks * BLOCK_SIZE;

                if (_dev.IsRemovable)
                {
                    sidecar.BlockMedia[0].DumpHardwareArray = _resume.Tries.ToArray();
                }

                UpdateStatus?.Invoke("Writing metadata sidecar");

                var xmlFs = new FileStream(_outputPrefix + ".cicm.xml", FileMode.Create);

                var xmlSer = new XmlSerializer(typeof(CICMMetadataType));
                xmlSer.Serialize(xmlFs, sidecar);
                xmlFs.Close();
            }

            UpdateStatus?.Invoke("");

            UpdateStatus?.
            Invoke($"Took a total of {(end - start).TotalSeconds:F3} seconds ({totalDuration / 1000:F3} processing commands, {totalChkDuration / 1000:F3} checksumming, {imageWriteDuration:F3} writing, {(closeEnd - closeStart).TotalSeconds:F3} closing).");

            UpdateStatus?.
            Invoke($"Average speed: {((double)BLOCK_SIZE * (double)(blocks + 1)) / 1048576 / (totalDuration / 1000):F3} MiB/sec.");

            UpdateStatus?.Invoke($"Fastest speed burst: {maxSpeed:F3} MiB/sec.");
            UpdateStatus?.Invoke($"Slowest speed burst: {minSpeed:F3} MiB/sec.");
            UpdateStatus?.Invoke($"{_resume.BadBlocks.Count} sectors could not be read.");
            UpdateStatus?.Invoke("");

            Statistics.AddMedia(dskType, true);
        }