示例#1
0
        // TODO: Set pregap for Track 1
        // TODO: Detect errors in sectors
        /// <summary>Reads all CD user data</summary>
        /// <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="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="offsetBytes">Read offset</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="totalDuration">Total commands duration</param>
        /// <param name="cdiReadyReadAsAudio">Is the drive returning CD-i Ready hidden track as audio?</param>
        /// <param name="tracks">Disc tracks</param>
        /// <param name="subLog">Subchannel log</param>
        /// <param name="desiredSubchannel">Subchannel desired to save</param>
        /// <param name="isrcs">List of disc ISRCs</param>
        /// <param name="mcn">Disc media catalogue number</param>
        /// <param name="subchannelExtents">List of subchannels not yet dumped correctly</param>
        /// <param name="smallestPregapLbaPerTrack">List of smallest pregap relative address per track</param>
        void ReadCdiReady(uint blockSize, ref double currentSpeed, DumpHardwareType currentTry, ExtentsULong extents,
                          IbgLog ibgLog, ref double imageWriteDuration, ExtentsULong leadOutExtents,
                          ref double maxSpeed, MhddLog mhddLog, ref double minSpeed, uint subSize,
                          MmcSubchannel supportedSubchannel, ref double totalDuration, Track[] tracks,
                          SubchannelLog subLog, MmcSubchannel desiredSubchannel, Dictionary <byte, string> isrcs,
                          ref string mcn, HashSet <int> subchannelExtents, ulong blocks, bool cdiReadyReadAsAudio,
                          int offsetBytes, int sectorsForOffset, Dictionary <byte, int> smallestPregapLbaPerTrack)
        {
            ulong    sectorSpeedStart = 0;               // Used to calculate correct speed
            DateTime timeSpeedStart   = DateTime.UtcNow; // Time of start for speed calculation
            bool     sense;                              // Sense indicator

            byte[]     cmdBuf;                           // Data buffer
            byte[]     senseBuf;                         // Sense buffer
            double     cmdDuration;                      // Command execution time
            const uint sectorSize = 2352;                // Full sector size
            Track      firstTrack = tracks.FirstOrDefault(t => t.TrackSequence == 1);
            uint       blocksToRead;                     // How many sectors to read at once

            if (firstTrack is null)
            {
                return;
            }

            if (cdiReadyReadAsAudio)
            {
                _dumpLog.WriteLine("Setting speed to 8x for CD-i Ready reading as audio.");
                UpdateStatus?.Invoke("Setting speed to 8x for CD-i Ready reading as audio.");

                _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _);
            }

            InitProgress?.Invoke();

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

                    break;
                }

                uint firstSectorToRead = (uint)i;

                blocksToRead = _maximumReadable;

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

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

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

                double elapsed;

                // Overcome the track mode change drive error
                if (sense)
                {
                    for (uint r = 0; r < _maximumReadable; r++)
                    {
                        UpdateProgress?.Invoke($"Reading sector {i + r} of {blocks} ({currentSpeed:F3} MiB/sec.)",
                                               (long)i + r, (long)blocks);

                        sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)(i + r), blockSize,
                                            (uint)sectorsForOffset + 1, MmcSectorTypes.AllTypes, false, false, true,
                                            MmcHeaderCodes.AllHeaders, true, true, MmcErrorField.None,
                                            supportedSubchannel, _dev.Timeout, out cmdDuration);

                        totalDuration += cmdDuration;

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

                            if (cdiReadyReadAsAudio)
                            {
                                FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel,
                                              ref blocksToRead, subSize, ref cmdBuf, blockSize, false);
                            }

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

                                if (cdiReadyReadAsAudio)
                                {
                                    data = Sector.Scramble(data);
                                }

                                _outputPlugin.WriteSectorsLong(data, i + r, 1);

                                bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
                                                                                               desiredSubchannel, sub,
                                                                                               i + r, 1, subLog, isrcs,
                                                                                               1, ref mcn, tracks,
                                                                                               subchannelExtents,
                                                                                               _fixSubchannelPosition,
                                                                                               _outputPlugin,
                                                                                               _fixSubchannel,
                                                                                               _fixSubchannelCrc,
                                                                                               _dumpLog, UpdateStatus,
                                                                                               smallestPregapLbaPerTrack);

                                // Set tracks and go back
                                if (indexesChanged)
                                {
                                    (_outputPlugin as IWritableOpticalImage).SetTracks(tracks.ToList());
                                    i -= _maximumReadable;

                                    continue;
                                }
                            }
                            else
                            {
                                _outputPlugin.WriteSectorsLong(cmdBuf, i + r, 1);
                            }

                            imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
                        }
                        else
                        {
                            _errorLog?.WriteLine(i + r, _dev.Error, _dev.LastError, senseBuf);

                            leadOutExtents.Add(i + r, firstTrack.TrackStartSector - 1);

                            UpdateStatus?.
                            Invoke($"Adding CD-i Ready hole from LBA {i + r} to {firstTrack.TrackStartSector - 1} inclusive.");

                            _dumpLog.WriteLine("Adding CD-i Ready hole from LBA {0} to {1} inclusive.", i + r,
                                               firstTrack.TrackStartSector - 1);

                            break;
                        }

                        sectorSpeedStart += r;

                        _resume.NextBlock = i + r;

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

                        if (elapsed < 1)
                        {
                            continue;
                        }

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

                if (!sense &&
                    !_dev.Error)
                {
                    if (cdiReadyReadAsAudio)
                    {
                        FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead,
                                      subSize, ref cmdBuf, blockSize, false);
                    }

                    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];
                        byte[] tmpData = new byte[sectorSize];

                        for (int b = 0; b < blocksToRead; b++)
                        {
                            if (cdiReadyReadAsAudio)
                            {
                                Array.Copy(cmdBuf, (int)(0 + (b * blockSize)), tmpData, 0, sectorSize);
                                tmpData = Sector.Scramble(tmpData);
                                Array.Copy(tmpData, 0, data, sectorSize * b, sectorSize);
                            }
                            else
                            {
                                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);

                        bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
                                                                                       desiredSubchannel, sub, i,
                                                                                       blocksToRead, subLog, isrcs, 1,
                                                                                       ref mcn, tracks,
                                                                                       subchannelExtents,
                                                                                       _fixSubchannelPosition,
                                                                                       _outputPlugin, _fixSubchannel,
                                                                                       _fixSubchannelCrc, _dumpLog,
                                                                                       UpdateStatus,
                                                                                       smallestPregapLbaPerTrack);

                        // Set tracks and go back
                        if (indexesChanged)
                        {
                            (_outputPlugin as IWritableOpticalImage).SetTracks(tracks.ToList());
                            i -= blocksToRead;

                            continue;
                        }
                    }
                    else
                    {
                        if (cdiReadyReadAsAudio)
                        {
                            byte[] tmpData = new byte[sectorSize];
                            byte[] data    = new byte[sectorSize * blocksToRead];

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

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

                    imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
                }
                else
                {
                    _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf);

                    _resume.NextBlock = firstTrack.TrackStartSector;

                    break;
                }

                sectorSpeedStart += blocksToRead;

                _resume.NextBlock = i + blocksToRead;

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

                if (elapsed < 1)
                {
                    continue;
                }

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

            EndProgress?.Invoke();
        }
示例#2
0
文件: Trim.cs 项目: FakeShemp/Aaru
        void TrimCdUserData(ExtentsULong audioExtents, uint blockSize, DumpHardwareType currentTry,
                            ExtentsULong extents, bool newTrim, int offsetBytes, bool read6, bool read10, bool read12,
                            bool read16, bool readcd, int sectorsForOffset, uint subSize,
                            MmcSubchannel supportedSubchannel, bool supportsLongSectors, ref double totalDuration,
                            SubchannelLog subLog, MmcSubchannel desiredSubchannel, Track[] tracks,
                            Dictionary <byte, string> isrcs, ref string mcn, HashSet <int> subchannelExtents)
        {
            DateTime start;
            DateTime end;
            bool     sense = true;                // Sense indicator

            byte[]            cmdBuf      = null; // Data buffer
            double            cmdDuration = 0;    // Command execution time
            const uint        sectorSize  = 2352; // Full sector size
            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 ||
                !_trim ||
                !newTrim)
            {
                return;
            }

            start = DateTime.UtcNow;
            UpdateStatus?.Invoke("Trimming skipped sectors");
            _dumpLog.WriteLine("Trimming skipped sectors");

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

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

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

                    break;
                }

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

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

                byte sectorsToTrim   = 1;
                uint badSectorToRead = (uint)badSector;

                if (_fixOffset &&
                    audioExtents.Contains(badSector) &&
                    offsetBytes != 0)
                {
                    if (offsetBytes > 0)
                    {
                        badSectorToRead -= (uint)sectorsForOffset;
                    }

                    sectorsToTrim = (byte)(sectorsForOffset + 1);
                }

                if (_supportsPlextorD8 && audioExtents.Contains(badSector))
                {
                    sense = ReadPlextorWithSubchannel(out cmdBuf, out _, badSectorToRead, blockSize, sectorsToTrim,
                                                      supportedPlextorSubchannel, out cmdDuration);

                    totalDuration += cmdDuration;
                }
                else if (readcd)
                {
                    sense = _dev.ReadCd(out cmdBuf, out _, badSectorToRead, blockSize, sectorsToTrim,
                                        MmcSectorTypes.AllTypes, false, false, true, MmcHeaderCodes.AllHeaders, true,
                                        true, MmcErrorField.None, supportedSubchannel, _dev.Timeout, out cmdDuration);
                }
                else if (read16)
                {
                    sense = _dev.Read16(out cmdBuf, out _, 0, false, true, false, badSectorToRead, blockSize, 0,
                                        sectorsToTrim, false, _dev.Timeout, out cmdDuration);
                }
                else if (read12)
                {
                    sense = _dev.Read12(out cmdBuf, out _, 0, false, true, false, false, badSectorToRead, blockSize, 0,
                                        sectorsToTrim, false, _dev.Timeout, out cmdDuration);
                }
                else if (read10)
                {
                    sense = _dev.Read10(out cmdBuf, out _, 0, false, true, false, false, badSectorToRead, blockSize, 0,
                                        sectorsToTrim, _dev.Timeout, out cmdDuration);
                }
                else if (read6)
                {
                    sense = _dev.Read6(out cmdBuf, out _, badSectorToRead, blockSize, sectorsToTrim, _dev.Timeout,
                                       out cmdDuration);
                }

                totalDuration += cmdDuration;

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

                if (!sense &&
                    !_dev.Error)
                {
                    _resume.BadBlocks.Remove(badSector);
                    extents.Add(badSector);
                }

                // Because one block has been partially used to fix the offset
                if (_fixOffset &&
                    audioExtents.Contains(badSector) &&
                    offsetBytes != 0)
                {
                    uint blocksToRead = sectorsToTrim;

                    FixOffsetData(offsetBytes, sectorSize, sectorsForOffset, supportedSubchannel, ref blocksToRead,
                                  subSize, ref cmdBuf, blockSize, false);
                }

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

                    // Set tracks and go back
                    if (!indexesChanged)
                    {
                        continue;
                    }

                    (_outputPlugin as IWritableOpticalImage).SetTracks(tracks.ToList());
                    b--;

                    continue;
                }

                if (supportsLongSectors)
                {
                    _outputPlugin.WriteSectorLong(cmdBuf, badSector);
                }
                else
                {
                    if (cmdBuf.Length % sectorSize == 0)
                    {
                        byte[] data = new byte[2048];
                        Array.Copy(cmdBuf, 16, data, 0, 2048);

                        _outputPlugin.WriteSector(data, badSector);
                    }
                    else
                    {
                        _outputPlugin.WriteSectorLong(cmdBuf, badSector);
                    }
                }
            }

            EndProgress?.Invoke();
            end = DateTime.UtcNow;
            UpdateStatus?.Invoke($"Trimming finished in {(end - start).TotalSeconds} seconds.");
            _dumpLog.WriteLine("Trimming finished in {0} seconds.", (end - start).TotalSeconds);
        }
示例#3
0
文件: Data.cs 项目: SilasLaspada/Aaru
        /// <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>
        /// <param name="tracks">Disc tracks</param>
        /// <param name="subLog">Subchannel log</param>
        /// <param name="desiredSubchannel">Subchannel desired to save</param>
        /// <param name="isrcs">List of disc ISRCs</param>
        /// <param name="mcn">Disc media catalogue number</param>
        /// <param name="subchannelExtents">List of subchannels not yet dumped correctly</param>
        /// <param name="smallestPregapLbaPerTrack">List of smallest pregap relative address per track</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, SubchannelLog subLog, MmcSubchannel desiredSubchannel,
                        Dictionary <byte, string> isrcs, ref string mcn, HashSet <int> subchannelExtents,
                        Dictionary <byte, int> smallestPregapLbaPerTrack)
        {
            ulong    sectorSpeedStart = 0;                 // Used to calculate correct speed
            DateTime timeSpeedStart   = DateTime.UtcNow;   // Time of start for speed calculation
            uint     blocksToRead;                         // 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

            newTrim = false;
            PlextorSubchannel supportedPlextorSubchannel;

            switch (supportedSubchannel)
            {
            case MmcSubchannel.None:
                supportedPlextorSubchannel = PlextorSubchannel.None;

                break;

            case MmcSubchannel.Raw:
                supportedPlextorSubchannel = PlextorSubchannel.Pack;

                break;

            case MmcSubchannel.Q16:
                supportedPlextorSubchannel = PlextorSubchannel.Q16;

                break;

            default:
                supportedPlextorSubchannel = PlextorSubchannel.None;

                break;
            }

            InitProgress?.Invoke();

            int  currentReadSpeed      = _speed;
            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 &&
                    !inData)
                {
                    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;
                        }

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

                if (!inData &&
                    currentReadSpeed == 0xFFFF)
                {
                    _dumpLog.WriteLine("Setting speed to 8x for audio reading.");
                    UpdateStatus?.Invoke("Setting speed to 8x for audio reading.");

                    _dev.SetCdSpeed(out _, RotationalControl.ClvAndImpureCav, 1416, 0, _dev.Timeout, out _);

                    currentReadSpeed = 1200;
                }

                if (inData && currentReadSpeed != _speed)
                {
                    _dumpLog.WriteLine($"Setting speed to {(_speed == 0xFFFF ? "MAX for data reading" : $"{_speed}x")}.");
示例#4
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, HashSet <int> subchannelExtents)
        {
            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, subchannelExtents);

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

                if (!forward)
                {
                    _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,
                                                                         subchannelExtents);

                            // 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();
        }
示例#5
0
        void RetrySubchannel(bool readcd, uint subSize, MmcSubchannel supportedSubchannel, ref double totalDuration,
                             SubchannelLog subLog, MmcSubchannel desiredSubchannel, Track[] tracks,
                             Dictionary <byte, string> isrcs, ref string mcn, HashSet <int> subchannelExtents)
        {
            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;

            if (supportedSubchannel == MmcSubchannel.None ||
                desiredSubchannel == MmcSubchannel.None)
            {
                return;
            }

            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 (_aborted)
            {
                return;
            }

            int  pass    = 1;
            bool forward = true;

            InitProgress?.Invoke();

cdRepeatRetry:

            _resume.BadSubchannels = new List <int>();
            _resume.BadSubchannels.AddRange(subchannelExtents);
            _resume.BadSubchannels.Sort();

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

            int[] tmpArray = _resume.BadSubchannels.ToArray();

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

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

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

                    break;
                }

                PulseProgress?.
                Invoke($"Retrying sector {badSector} subchannel, pass {pass}, {(forward ? "forward" : "reverse")}");

                uint startSector = badSector - 2;

                if (_supportsPlextorD8)
                {
                    sense = _dev.PlextorReadCdDa(out cmdBuf, out senseBuf, startSector, subSize, 5,
                                                 supportedPlextorSubchannel, 0, out cmdDuration);

                    totalDuration += cmdDuration;
                }
                else if (readcd)
                {
                    sense = _dev.ReadCd(out cmdBuf, out senseBuf, startSector, subSize, 5, MmcSectorTypes.AllTypes,
                                        false, false, false, MmcHeaderCodes.None, false, false, MmcErrorField.None,
                                        supportedSubchannel, _dev.Timeout, out cmdDuration);

                    totalDuration += cmdDuration;
                }

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

                WriteSubchannelToImage(supportedSubchannel, desiredSubchannel, cmdBuf, badSector, 5, subLog, isrcs,
                                       (byte)track.TrackSequence, ref mcn, tracks, subchannelExtents);

                if (subchannelExtents.Contains(tmpArray[i]))
                {
                    continue;
                }

                UpdateStatus?.Invoke($"Correctly retried sector {badSector} subchannel in pass {pass}.");
                _dumpLog.WriteLine("Correctly retried sector {0} subchannel in pass {1}.", badSector, pass);
            }

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

                goto cdRepeatRetry;
            }

            EndProgress?.Invoke();
        }
示例#6
0
文件: LeadOuts.cs 项目: paulyc/Aaru
        /// <summary>Dumps inter-session lead-outs</summary>
        /// <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="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="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="supportedSubchannel">Drive's maximum supported subchannel</param>
        /// <param name="subSize">Subchannel size in bytes</param>
        /// <param name="totalDuration">Total commands duration</param>
        /// <param name="tracks">Disc tracks</param>
        /// <param name="subLog">Subchannel log</param>
        /// <param name="desiredSubchannel">Subchannel desired to save</param>
        /// <param name="isrcs">List of disc ISRCs</param>
        /// <param name="mcn">Disc media catalogue number</param>
        /// <param name="subchannelExtents">List of subchannels not yet dumped correctly</param>
        /// <param name="smallestPregapLbaPerTrack">List of smallest pregap relative address per track</param>
        void DumpCdLeadOuts(uint blockSize, ref double currentSpeed, DumpHardwareType currentTry, ExtentsULong extents,
                            IbgLog ibgLog, ref double imageWriteDuration, ExtentsULong leadOutExtents,
                            ref double maxSpeed, MhddLog mhddLog, ref double minSpeed, bool read6, bool read10,
                            bool read12, bool read16, bool readcd, MmcSubchannel supportedSubchannel, uint subSize,
                            ref double totalDuration, SubchannelLog subLog, MmcSubchannel desiredSubchannel,
                            Dictionary <byte, string> isrcs, ref string mcn, Track[] tracks,
                            HashSet <int> subchannelExtents, Dictionary <byte, int> smallestPregapLbaPerTrack)
        {
            byte[]     cmdBuf     = null; // Data buffer
            const uint sectorSize = 2352; // Full sector size
            bool       sense      = true; // Sense indicator

            byte[] senseBuf = null;

            UpdateStatus?.Invoke("Reading lead-outs");
            _dumpLog.WriteLine("Reading lead-outs");

            InitProgress?.Invoke();

            foreach ((ulong item1, ulong item2) in leadOutExtents.ToArray())
            {
                for (ulong i = item1; i <= item2; i++)
                {
                    if (_aborted)
                    {
                        currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                        _dumpLog.WriteLine("Aborted!");

                        break;
                    }

                    double cmdDuration = 0;

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

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

                    PulseProgress?.Invoke($"Reading sector {i} at lead-out ({currentSpeed:F3} MiB/sec.)");

                    if (readcd)
                    {
                        sense = _dev.ReadCd(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, 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, i, blockSize, 0, 1, false,
                                            _dev.Timeout, out cmdDuration);
                    }
                    else if (read12)
                    {
                        sense = _dev.Read12(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize,
                                            0, 1, false, _dev.Timeout, out cmdDuration);
                    }
                    else if (read10)
                    {
                        sense = _dev.Read10(out cmdBuf, out senseBuf, 0, false, true, false, false, (uint)i, blockSize,
                                            0, 1, _dev.Timeout, out cmdDuration);
                    }
                    else if (read6)
                    {
                        sense = _dev.Read6(out cmdBuf, out senseBuf, (uint)i, blockSize, 1, _dev.Timeout,
                                           out cmdDuration);
                    }

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

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

                            for (int b = 0; b < _maximumReadable; 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, _maximumReadable);

                            bool indexesChanged = Media.CompactDisc.WriteSubchannelToImage(supportedSubchannel,
                                                                                           desiredSubchannel, sub, i, _maximumReadable, subLog, isrcs, 0xAA, ref mcn, tracks,
                                                                                           subchannelExtents, _fixSubchannelPosition, _outputPlugin, _fixSubchannel,
                                                                                           _fixSubchannelCrc, _dumpLog, UpdateStatus, smallestPregapLbaPerTrack, true);

                            // Set tracks and go back
                            if (indexesChanged)
                            {
                                (_outputPlugin as IWritableOpticalImage).SetTracks(tracks.ToList());
                                i--;

                                continue;
                            }
                        }
                        else
                        {
                            _outputPlugin.WriteSectors(cmdBuf, i, _maximumReadable);
                        }

                        imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
                    }
                    else
                    {
                        _errorLog?.WriteLine(i, _dev.Error, _dev.LastError, senseBuf);

                        // TODO: Reset device after X errors
                        if (_stopOnError)
                        {
                            return; // TODO: Return more cleanly
                        }
                        // Write empty data
                        DateTime writeStart = DateTime.Now;

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

                            _outputPlugin.WriteSectorsTag(new byte[subSize * _skip], i, 1,
                                                          SectorTagType.CdSectorSubchannel);
                        }
                        else
                        {
                            _outputPlugin.WriteSectors(new byte[blockSize * _skip], i, 1);
                        }

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

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

                        ibgLog.Write(i, 0);
                    }

                    double newSpeed = ((double)blockSize * _maximumReadable) / 1048576 / (cmdDuration / 1000);

                    if (!double.IsInfinity(newSpeed))
                    {
                        currentSpeed = newSpeed;
                    }

                    _resume.NextBlock = i + 1;
                }
            }

            EndProgress?.Invoke();
        }
示例#7
0
文件: Subchannel.cs 项目: radtek/Aaru
        // Return true if indexes have changed
        bool WriteSubchannelToImage(MmcSubchannel supportedSubchannel, MmcSubchannel desiredSubchannel, byte[] sub,
                                    ulong sectorAddress, uint length, SubchannelLog subLog,
                                    Dictionary <byte, string> isrcs, byte currentTrack, ref string mcn, Track[] tracks)
        {
            if (supportedSubchannel == MmcSubchannel.Q16)
            {
                sub = Subchannel.ConvertQToRaw(sub);
            }

            if (desiredSubchannel != MmcSubchannel.None)
            {
                _outputPlugin.WriteSectorsTag(sub, sectorAddress, length, SectorTagType.CdSectorSubchannel);
            }

            subLog?.WriteEntry(sub, supportedSubchannel == MmcSubchannel.Raw, (long)sectorAddress, length);

            byte[] deSub = Subchannel.Deinterleave(sub);

            // Check subchannel
            for (int subPos = 0; subPos < deSub.Length; subPos += 96)
            {
                byte[] q = new byte[12];
                Array.Copy(deSub, subPos + 12, q, 0, 12);

                CRC16CCITTContext.Data(q, 10, out byte[] crc);
                bool crcOk = crc[0] == q[10] && crc[1] == q[11];

                // ISRC
                if ((q[0] & 0x3) == 3)
                {
                    string isrc = Subchannel.DecodeIsrc(q);

                    if (isrc == null ||
                        isrc == "000000000000")
                    {
                        continue;
                    }

                    if (!crcOk)
                    {
                        continue;
                    }

                    if (!isrcs.ContainsKey(currentTrack))
                    {
                        _dumpLog?.WriteLine($"Found new ISRC {isrc} for track {currentTrack}.");
                        UpdateStatus?.Invoke($"Found new ISRC {isrc} for track {currentTrack}.");
                    }
                    else if (isrcs[currentTrack] != isrc)
                    {
                        _dumpLog?.
                        WriteLine($"ISRC for track {currentTrack} changed from {isrcs[currentTrack]} to {isrc}.");

                        UpdateStatus?.
                        Invoke($"ISRC for track {currentTrack} changed from {isrcs[currentTrack]} to {isrc}.");
                    }

                    isrcs[currentTrack] = isrc;
                }
                else if ((q[0] & 0x3) == 2)
                {
                    string newMcn = Subchannel.DecodeMcn(q);

                    if (newMcn == null ||
                        newMcn == "0000000000000")
                    {
                        continue;
                    }

                    if (!crcOk)
                    {
                        continue;
                    }

                    if (mcn is null)
                    {
                        _dumpLog?.WriteLine($"Found new MCN {newMcn}.");
                        UpdateStatus?.Invoke($"Found new MCN {newMcn}.");
                    }
                    else if (mcn != newMcn)
                    {
                        _dumpLog?.WriteLine($"MCN changed from {mcn} to {newMcn}.");
                        UpdateStatus?.Invoke($"MCN changed from {mcn} to {newMcn}.");
                    }

                    mcn = newMcn;
                }
                else if ((q[0] & 0x3) == 1)
                {
                    // TODO: Indexes

                    // Pregap
                    if (q[2] != 0)
                    {
                        continue;
                    }

                    if (!crcOk)
                    {
                        continue;
                    }

                    byte trackNo = (byte)(((q[1] / 16) * 10) + (q[1] & 0x0F));

                    for (int i = 0; i < tracks.Length; i++)
                    {
                        if (tracks[i].TrackSequence != trackNo ||
                            trackNo == 1)
                        {
                            continue;
                        }

                        byte pmin   = (byte)(((q[3] / 16) * 10) + (q[3] & 0x0F));
                        byte psec   = (byte)(((q[4] / 16) * 10) + (q[4] & 0x0F));
                        byte pframe = (byte)(((q[5] / 16) * 10) + (q[5] & 0x0F));
                        int  qPos   = (pmin * 60 * 75) + (psec * 75) + pframe;

                        if (tracks[i].TrackPregap >= (ulong)(qPos + 1))
                        {
                            continue;
                        }

                        tracks[i].TrackPregap       = (ulong)(qPos + 1);
                        tracks[i].TrackStartSector -= tracks[i].TrackPregap;

                        if (i > 0)
                        {
                            tracks[i - 1].TrackEndSector = tracks[i].TrackStartSector - 1;
                        }

                        _dumpLog?.WriteLine($"Pregap for track {trackNo} set to {tracks[i].TrackPregap} sectors.");
                        UpdateStatus?.Invoke($"Pregap for track {trackNo} set to {tracks[i].TrackPregap} sectors.");

                        return(true);
                    }
                }
            }

            return(false);
        }
示例#8
0
文件: LeadOuts.cs 项目: radtek/Aaru
        /// <summary>Retries inter-session lead-outs</summary>
        /// <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="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="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="supportedSubchannel">Drive's maximum supported subchannel</param>
        /// <param name="subSize">Subchannel size in bytes</param>
        /// <param name="totalDuration">Total commands duration</param>
        void RetryCdLeadOuts(ulong blocks, uint blockSize, ref double currentSpeed, DumpHardwareType currentTry,
                             ExtentsULong extents, IbgLog ibgLog, ref double imageWriteDuration,
                             ExtentsULong leadOutExtents, ref double maxSpeed, MhddLog mhddLog, ref double minSpeed,
                             bool read6, bool read10, bool read12, bool read16, bool readcd,
                             MmcSubchannel supportedSubchannel, uint subSize, ref double totalDuration,
                             SubchannelLog subLog, MmcSubchannel desiredSubchannel, Dictionary <byte, string> isrcs,
                             ref string mcn, Track[] tracks)
        {
            byte[]     cmdBuf     = null; // Data buffer
            const uint sectorSize = 2352; // Full sector size
            bool       sense      = true; // Sense indicator

            _dumpLog.WriteLine("Retrying lead-outs");

            InitProgress?.Invoke();

            foreach ((ulong item1, ulong item2) in leadOutExtents.ToArray())
            {
                for (ulong i = item1; i <= item2; i++)
                {
                    if (_aborted)
                    {
                        currentTry.Extents = ExtentsConverter.ToMetadata(extents);
                        _dumpLog.WriteLine("Aborted!");

                        break;
                    }

                    double cmdDuration = 0;

                    #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

                    PulseProgress?.Invoke(string.Format("Reading sector {0} at lead-out ({1:F3} MiB/sec.)", i, blocks,
                                                        currentSpeed));

                    if (readcd)
                    {
                        sense = _dev.ReadCd(out cmdBuf, out _, (uint)i, blockSize, 1, 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 _, 0, false, true, false, i, blockSize, 0, 1, false,
                                            _dev.Timeout, out cmdDuration);
                    }
                    else if (read12)
                    {
                        sense = _dev.Read12(out cmdBuf, out _, 0, false, true, false, false, (uint)i, blockSize, 0, 1,
                                            false, _dev.Timeout, out cmdDuration);
                    }
                    else if (read10)
                    {
                        sense = _dev.Read10(out cmdBuf, out _, 0, false, true, false, false, (uint)i, blockSize, 0, 1,
                                            _dev.Timeout, out cmdDuration);
                    }
                    else if (read6)
                    {
                        sense = _dev.Read6(out cmdBuf, out _, (uint)i, blockSize, 1, _dev.Timeout, out cmdDuration);
                    }

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

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

                            for (int b = 0; b < _maximumReadable; 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, _maximumReadable);

                            bool indexesChanged = WriteSubchannelToImage(supportedSubchannel, desiredSubchannel, sub, i,
                                                                         _maximumReadable, subLog, isrcs, 0xAA, ref mcn,
                                                                         tracks);

                            // Set tracks and go back
                            if (indexesChanged)
                            {
                                (_outputPlugin as IWritableOpticalImage).SetTracks(tracks.ToList());
                                i--;

                                continue;
                            }
                        }
                        else
                        {
                            _outputPlugin.WriteSectors(cmdBuf, i, _maximumReadable);
                        }

                        imageWriteDuration += (DateTime.Now - writeStart).TotalSeconds;
                    }
                    else
                    {
                        // TODO: Reset device after X errors
                        if (_stopOnError)
                        {
                            return; // TODO: Return more cleanly
                        }
                        // Write empty data
                        DateTime writeStart = DateTime.Now;

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

                            if (desiredSubchannel != MmcSubchannel.None)
                            {
                                _outputPlugin.WriteSectorsTag(new byte[subSize * _skip], i, 1,
                                                              SectorTagType.CdSectorSubchannel);
                            }
                        }
                        else
                        {
                            _outputPlugin.WriteSectors(new byte[blockSize * _skip], i, 1);
                        }

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

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

                        ibgLog.Write(i, 0);
                    }

                    double newSpeed = ((double)blockSize * _maximumReadable) / 1048576 / (cmdDuration / 1000);

                    if (!double.IsInfinity(newSpeed))
                    {
                        currentSpeed = newSpeed;
                    }
                }
            }

            EndProgress?.Invoke();
        }