Esempio n. 1
0
        // Asynchronously tries to read the contents of the PAX metadata entry as extended attributes, tries to also read the actual entry that follows,
        // and returns the actual entry with the processed extended attributes saved in the _extendedAttributes dictionary.
        private async ValueTask <TarHeader?> TryProcessExtendedAttributesHeaderAsync(TarHeader extendedAttributesHeader, bool copyData, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Now get the actual entry
            TarHeader?actualHeader = await TarHeader.TryGetNextHeaderAsync(_archiveStream, copyData, TarEntryFormat.Pax, cancellationToken).ConfigureAwait(false);

            if (actualHeader == null)
            {
                return(null);
            }

            // We're currently processing an extended attributes header, so we can never have two extended entries in a row
            if (actualHeader._typeFlag is TarEntryType.GlobalExtendedAttributes or
                TarEntryType.ExtendedAttributes or
                TarEntryType.LongLink or
                TarEntryType.LongPath)
            {
                throw new FormatException(string.Format(SR.TarUnexpectedMetadataEntry, actualHeader._typeFlag, TarEntryType.ExtendedAttributes));
            }

            // Can't have two extended attribute metadata entries in a row
            if (actualHeader._typeFlag is TarEntryType.ExtendedAttributes)
            {
                throw new FormatException(string.Format(SR.TarUnexpectedMetadataEntry, TarEntryType.ExtendedAttributes, TarEntryType.ExtendedAttributes));
            }

            // Replace all the attributes representing standard fields with the extended ones, if any
            actualHeader.ReplaceNormalAttributesWithExtended(extendedAttributesHeader.ExtendedAttributes);

            return(actualHeader);
        }
Esempio n. 2
0
        // Asynchronously attempts to read the next tar archive entry header.
        // Returns true if an entry header was collected successfully, false otherwise.
        // An entry header represents any typeflag that is contains metadata.
        // Metadata typeflags: ExtendedAttributes, GlobalExtendedAttributes, LongLink, LongPath.
        // Metadata typeflag entries get handled internally by this method until a valid header entry can be returned.
        private async ValueTask <(bool, TarHeader)> TryGetNextEntryHeaderAsync(bool copyData, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            Debug.Assert(!_reachedEndMarkers);

            (bool result, TarHeader header) = await TarHeader.TryGetNextHeaderAsync(_archiveStream, copyData, TarEntryFormat.Unknown, cancellationToken).ConfigureAwait(false);

            if (!result)
            {
                return(false, default);
Esempio n. 3
0
        // Asynchronously attempts to read the next tar archive entry header.
        // Returns true if an entry header was collected successfully, false otherwise.
        // An entry header represents any typeflag that is contains metadata.
        // Metadata typeflags: ExtendedAttributes, GlobalExtendedAttributes, LongLink, LongPath.
        // Metadata typeflag entries get handled internally by this method until a valid header entry can be returned.
        private async ValueTask <TarHeader?> TryGetNextEntryHeaderAsync(bool copyData, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            Debug.Assert(!_reachedEndMarkers);

            TarHeader?header = await TarHeader.TryGetNextHeaderAsync(_archiveStream, copyData, TarEntryFormat.Unknown, cancellationToken).ConfigureAwait(false);

            if (header == null)
            {
                return(null);
            }

            // If a metadata typeflag entry is retrieved, handle it here, then read the next entry

            // PAX metadata
            if (header._typeFlag is TarEntryType.ExtendedAttributes)
            {
                TarHeader?mainHeader = await TryProcessExtendedAttributesHeaderAsync(header, copyData, cancellationToken).ConfigureAwait(false);

                if (mainHeader == null)
                {
                    return(null);
                }
                header = mainHeader;
            }
            // GNU metadata
            else if (header._typeFlag is TarEntryType.LongLink or TarEntryType.LongPath)
            {
                TarHeader?mainHeader = await TryProcessGnuMetadataHeaderAsync(header, copyData, cancellationToken).ConfigureAwait(false);

                if (mainHeader == null)
                {
                    return(null);
                }
                header = mainHeader;
            }

            return(header);
        }
Esempio n. 4
0
        // Asynchronously tries to read the contents of the PAX metadata entry as extended attributes, tries to also read the actual entry that follows,
        // and returns the actual entry with the processed extended attributes saved in the _extendedAttributes dictionary.
        private async ValueTask <TarHeader?> TryProcessExtendedAttributesHeaderAsync(TarHeader extendedAttributesHeader, bool copyData, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Don't process the data block of the actual entry just yet, because there's a slim chance
            // that the extended attributes contain a size that we need to override in the header
            TarHeader?actualHeader = await TarHeader.TryGetNextHeaderAsync(_archiveStream, copyData, TarEntryFormat.Pax, processDataBlock : false, cancellationToken).ConfigureAwait(false);

            if (actualHeader == null)
            {
                return(null);
            }

            // We're currently processing an extended attributes header, so we can never have two extended entries in a row
            if (actualHeader._typeFlag is TarEntryType.GlobalExtendedAttributes or
                TarEntryType.ExtendedAttributes or
                TarEntryType.LongLink or
                TarEntryType.LongPath)
            {
                throw new FormatException(string.Format(SR.TarUnexpectedMetadataEntry, actualHeader._typeFlag, TarEntryType.ExtendedAttributes));
            }

            // Can't have two extended attribute metadata entries in a row
            if (actualHeader._typeFlag is TarEntryType.ExtendedAttributes)
            {
                throw new FormatException(string.Format(SR.TarUnexpectedMetadataEntry, TarEntryType.ExtendedAttributes, TarEntryType.ExtendedAttributes));
            }

            // Replace all the attributes representing standard fields with the extended ones, if any
            actualHeader.ReplaceNormalAttributesWithExtended(extendedAttributesHeader.ExtendedAttributes);

            // We retrieved the extended attributes, now we can read the data, and always with the right size
            actualHeader.ProcessDataBlock(_archiveStream, copyData);

            return(actualHeader);
        }
Esempio n. 5
0
        // Asynchronously tries to read the contents of the GNU metadata entry, then tries to read the next entry, which could either be another GNU metadata entry
        // or the actual entry. Processes them all and returns the actual entry updating its path and/or linkpath fields as needed.
        private async ValueTask <TarHeader?> TryProcessGnuMetadataHeaderAsync(TarHeader header, bool copyData, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            // Get the second entry, which is the actual entry
            TarHeader?secondHeader = await TarHeader.TryGetNextHeaderAsync(_archiveStream, copyData, TarEntryFormat.Gnu, cancellationToken).ConfigureAwait(false);

            if (secondHeader == null)
            {
                return(null);
            }

            // Can't have two identical metadata entries in a row
            if (secondHeader._typeFlag == header._typeFlag)
            {
                throw new FormatException(string.Format(SR.TarUnexpectedMetadataEntry, secondHeader._typeFlag, header._typeFlag));
            }

            TarHeader finalHeader;

            // It's possible to have the two different metadata entries in a row
            if ((header._typeFlag is TarEntryType.LongLink && secondHeader._typeFlag is TarEntryType.LongPath) ||
                (header._typeFlag is TarEntryType.LongPath && secondHeader._typeFlag is TarEntryType.LongLink))
            {
                // Get the third entry, which is the actual entry
                TarHeader?thirdHeader = await TarHeader.TryGetNextHeaderAsync(_archiveStream, copyData, TarEntryFormat.Gnu, cancellationToken).ConfigureAwait(false);

                if (thirdHeader == null)
                {
                    return(null);
                }

                // Can't have three GNU metadata entries in a row
                if (thirdHeader._typeFlag is TarEntryType.LongLink or TarEntryType.LongPath)
                {
                    throw new FormatException(string.Format(SR.TarUnexpectedMetadataEntry, thirdHeader._typeFlag, secondHeader._typeFlag));
                }

                if (header._typeFlag is TarEntryType.LongLink)
                {
                    Debug.Assert(header._linkName != null);
                    Debug.Assert(secondHeader._name != null);

                    thirdHeader._linkName = header._linkName;
                    thirdHeader._name     = secondHeader._name;
                }
                else if (header._typeFlag is TarEntryType.LongPath)
                {
                    Debug.Assert(header._name != null);
                    Debug.Assert(secondHeader._linkName != null);
                    thirdHeader._name     = header._name;
                    thirdHeader._linkName = secondHeader._linkName;
                }

                finalHeader = thirdHeader;
            }
            // Only one metadata entry was found
            else
            {
                if (header._typeFlag is TarEntryType.LongLink)
                {
                    Debug.Assert(header._linkName != null);
                    secondHeader._linkName = header._linkName;
                }
                else if (header._typeFlag is TarEntryType.LongPath)
                {
                    Debug.Assert(header._name != null);
                    secondHeader._name = header._name;
                }

                finalHeader = secondHeader;
            }

            return(finalHeader);
        }