示例#1
0
        // Determines what kind of stream needs to be saved for the data section.
        // - Metadata typeflag entries (Extended Attributes and Global Extended Attributes in PAX, LongLink and LongPath in GNU)
        //   will get all the data section read and the stream pointer positioned at the beginning of the next header.
        // - Block, Character, Directory, Fifo, HardLink and SymbolicLink typeflag entries have no data section so the archive stream pointer will be positioned at the beginning of the next header.
        // - All other typeflag entries with a data section will generate a stream wrapping the data section: SeekableSubReadStream for seekable archive streams, and SubReadStream for unseekable archive streams.
        private void ProcessDataBlock(Stream archiveStream, bool copyData)
        {
            bool skipBlockAlignmentPadding = true;

            switch (_typeFlag)
            {
            case TarEntryType.ExtendedAttributes or TarEntryType.GlobalExtendedAttributes:
                ReadExtendedAttributesBlock(archiveStream);
                break;

            case TarEntryType.LongLink or TarEntryType.LongPath:
                ReadGnuLongPathDataBlock(archiveStream);
                break;

            case TarEntryType.BlockDevice:
            case TarEntryType.CharacterDevice:
            case TarEntryType.Directory:
            case TarEntryType.Fifo:
            case TarEntryType.HardLink:
            case TarEntryType.SymbolicLink:
                // No data section
                break;

            case TarEntryType.RegularFile:
            case TarEntryType.V7RegularFile:      // Treated as regular file
            case TarEntryType.ContiguousFile:     // Treated as regular file
            case TarEntryType.DirectoryList:      // Contains the list of filesystem entries in the data section
            case TarEntryType.MultiVolume:        // Contains portion of a file
            case TarEntryType.RenamedOrSymlinked: // Might contain data
            case TarEntryType.SparseFile:         // Contains portion of a file
            case TarEntryType.TapeVolume:         // Might contain data
            default:                              // Unrecognized entry types could potentially have a data section
                _dataStream = GetDataStream(archiveStream, copyData);
                if (_dataStream is SeekableSubReadStream)
                {
                    TarHelpers.AdvanceStream(archiveStream, _size);
                }
                else if (_dataStream is SubReadStream)
                {
                    // This stream gives the user the chance to optionally read the data section
                    // when the underlying archive stream is unseekable
                    skipBlockAlignmentPadding = false;
                }

                break;
            }

            if (skipBlockAlignmentPadding)
            {
                if (_size > 0)
                {
                    TarHelpers.SkipBlockAlignmentPadding(archiveStream, _size);
                }

                if (archiveStream.CanSeek)
                {
                    _endOfHeaderAndDataAndBlockAlignment = archiveStream.Position;
                }
            }
        }
示例#2
0
        // Moves the underlying archive stream position pointer to the beginning of the next header.
        internal void AdvanceDataStreamIfNeeded()
        {
            if (_previouslyReadEntry == null)
            {
                return;
            }

            if (_archiveStream.CanSeek)
            {
                Debug.Assert(_previouslyReadEntry._header._endOfHeaderAndDataAndBlockAlignment > 0);
                _archiveStream.Position = _previouslyReadEntry._header._endOfHeaderAndDataAndBlockAlignment;
            }
            else if (_previouslyReadEntry._header._size > 0)
            {
                // When working with seekable streams, every time we return an entry, we avoid advancing the pointer beyond the data section
                // This is so the user can read the data if desired. But if the data was not read by the user, we need to advance the pointer
                // here until it's located at the beginning of the next entry header.
                // This should only be done if the previous entry came from a TarReader and it still had its original SubReadStream or SeekableSubReadStream.

                if (_previouslyReadEntry._header._dataStream is not SubReadStream dataStream)
                {
                    return;
                }

                if (!dataStream.HasReachedEnd)
                {
                    // If the user did not advance the position, we need to make sure the position
                    // pointer is located at the beginning of the next header.
                    if (dataStream.Position < (_previouslyReadEntry._header._size - 1))
                    {
                        long bytesToSkip = _previouslyReadEntry._header._size - dataStream.Position;
                        TarHelpers.AdvanceStream(_archiveStream, bytesToSkip);
                        TarHelpers.SkipBlockAlignmentPadding(_archiveStream, _previouslyReadEntry._header._size);
                        dataStream.HasReachedEnd = true; // Now the pointer is beyond the limit, so any read attempts should throw
                    }
                }
            }
        }