コード例 #1
0
        // 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 TarHeader?TryGetNextEntryHeader(bool copyData)
        {
            Debug.Assert(!_reachedEndMarkers);

            TarHeader?header = TarHeader.TryGetNextHeader(_archiveStream, copyData, TarEntryFormat.Unknown);

            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)
            {
                if (!TryProcessExtendedAttributesHeader(header, copyData, out TarHeader? mainHeader))
                {
                    return(null);
                }
                header = mainHeader;
            }
            // GNU metadata
            else if (header._typeFlag is TarEntryType.LongLink or TarEntryType.LongPath)
            {
                if (!TryProcessGnuMetadataHeader(header, copyData, out TarHeader mainHeader))
                {
                    return(null);
                }
                header = mainHeader;
            }

            return(header);
        }
コード例 #2
0
ファイル: TarReader.cs プロジェクト: dotnet/runtime
        private bool TryProcessExtendedAttributesHeader(TarHeader firstHeader, bool copyData, out TarHeader secondHeader)
        {
            secondHeader         = default;
            secondHeader._format = TarEntryFormat.Pax;

            // Now get the actual entry
            if (!secondHeader.TryGetNextHeader(_archiveStream, copyData))
            {
                return(false);
            }

            // Should never read a GEA entry at this point
            if (secondHeader._typeFlag == TarEntryType.GlobalExtendedAttributes)
            {
                throw new FormatException(SR.TarTooManyGlobalExtendedAttributesEntries);
            }

            // Can't have two metadata entries in a row, no matter the archive format
            if (secondHeader._typeFlag is TarEntryType.ExtendedAttributes)
            {
                throw new FormatException(string.Format(SR.TarUnexpectedMetadataEntry, TarEntryType.ExtendedAttributes, TarEntryType.ExtendedAttributes));
            }

            Debug.Assert(firstHeader._extendedAttributes != null);
            if (GlobalExtendedAttributes != null)
            {
                // First, replace some of the entry's standard attributes with the global ones
                secondHeader.ReplaceNormalAttributesWithGlobalExtended(GlobalExtendedAttributes);
            }
            // Then replace all the standard attributes with the extended attributes ones,
            // overwriting the previous global replacements if needed
            secondHeader.ReplaceNormalAttributesWithExtended(firstHeader._extendedAttributes);

            return(true);
        }
コード例 #3
0
ファイル: TarReader.cs プロジェクト: mikem8361/runtime
        // 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 bool TryProcessExtendedAttributesHeader(TarHeader extendedAttributesHeader, bool copyData, [NotNullWhen(returnValue: true)] out TarHeader?actualHeader)
        {
            // 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
            actualHeader = TarHeader.TryGetNextHeader(_archiveStream, copyData, TarEntryFormat.Pax, processDataBlock: false);

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

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

            // 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(true);
        }
コード例 #4
0
        // 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 bool TryGetNextEntryHeader(out TarHeader header, bool copyData)
        {
            Debug.Assert(!_reachedEndMarkers);

            header = default;

            if (!header.TryGetNextHeader(_archiveStream, copyData))
            {
                return(false);
            }

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

            // PAX metadata
            if (header._typeFlag is TarEntryType.ExtendedAttributes)
            {
                if (!TryProcessExtendedAttributesHeader(header, copyData, out TarHeader mainHeader))
                {
                    return(false);
                }
                header = mainHeader;
            }
            // GNU metadata
            else if (header._typeFlag is TarEntryType.LongLink or TarEntryType.LongPath)
            {
                if (!TryProcessGnuMetadataHeader(header, copyData, out TarHeader mainHeader))
                {
                    return(false);
                }
                header = mainHeader;
            }

            // Common fields should always acquire a value
            Debug.Assert(header._name != null);
            Debug.Assert(header._linkName != null);

            // Initialize non-common string fields if necessary
            header._magic ??= string.Empty;
            header._version ??= string.Empty;
            header._gName ??= string.Empty;
            header._uName ??= string.Empty;
            header._prefix ??= string.Empty;

            return(true);
        }
コード例 #5
0
        // 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 bool TryProcessExtendedAttributesHeader(TarHeader extendedAttributesHeader, bool copyData, [NotNullWhen(returnValue: true)] out TarHeader?actualHeader)
        {
            actualHeader = TarHeader.TryGetNextHeader(_archiveStream, copyData, TarEntryFormat.Pax);

            // Now get the actual entry
            if (actualHeader == null)
            {
                return(false);
            }

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

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

            return(true);
        }
コード例 #6
0
        // 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 bool TryProcessGnuMetadataHeader(TarHeader header, bool copyData, out TarHeader finalHeader)
        {
            finalHeader = new(TarEntryFormat.Gnu);

            TarHeader?secondHeader = TarHeader.TryGetNextHeader(_archiveStream, copyData, TarEntryFormat.Gnu);

            // Get the second entry, which is the actual entry
            if (secondHeader == null)
            {
                return(false);
            }

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

            // 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))
            {
                TarHeader?thirdHeader = TarHeader.TryGetNextHeader(_archiveStream, copyData, TarEntryFormat.Gnu);

                // Get the third entry, which is the actual entry
                if (thirdHeader == null)
                {
                    return(false);
                }

                // 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(true);
        }
コード例 #7
0
ファイル: TarReader.cs プロジェクト: dotnet/runtime
        // 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 bool TryGetNextEntryHeader(out TarHeader header, bool copyData)
        {
            Debug.Assert(!_reachedEndMarkers);

            header = default;

            // Set the initial format that is expected to be retrieved when calling TarHeader.TryReadAttributes.
            // If the archive format is set to unknown here, it means this is the first entry we read and the value will be changed as fields get discovered.
            // If the archive format is initially detected as pax, then any subsequent entries detected as ustar will be assumed to be pax.
            header._format = Format;

            if (!header.TryGetNextHeader(_archiveStream, copyData))
            {
                return(false);
            }

            // Special case: First header. Collect GEA from data section, then get next entry.
            if (header._typeFlag is TarEntryType.GlobalExtendedAttributes)
            {
                if (GlobalExtendedAttributes != null)
                {
                    // We can only have one extended attributes entry.
                    throw new FormatException(SR.TarTooManyGlobalExtendedAttributesEntries);
                }

                GlobalExtendedAttributes = header._extendedAttributes?.AsReadOnly();

                header         = default;
                header._format = TarEntryFormat.Pax;
                try
                {
                    if (!header.TryGetNextHeader(_archiveStream, copyData))
                    {
                        return(false);
                    }
                }
                catch (EndOfStreamException)
                {
                    // Edge case: The only entry in the archive was a Global Extended Attributes entry
                    Format = TarEntryFormat.Pax;
                    return(false);
                }
                if (header._typeFlag == TarEntryType.GlobalExtendedAttributes)
                {
                    throw new FormatException(SR.TarTooManyGlobalExtendedAttributesEntries);
                }
            }

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

            // PAX metadata
            if (header._typeFlag is TarEntryType.ExtendedAttributes)
            {
                if (!TryProcessExtendedAttributesHeader(header, copyData, out TarHeader mainHeader))
                {
                    return(false);
                }
                header = mainHeader;
            }
            // GNU metadata
            else if (header._typeFlag is TarEntryType.LongLink or TarEntryType.LongPath)
            {
                if (!TryProcessGnuMetadataHeader(header, copyData, out TarHeader mainHeader))
                {
                    return(false);
                }
                header = mainHeader;
            }

            // Common fields should always acquire a value
            Debug.Assert(header._name != null);
            Debug.Assert(header._linkName != null);

            // Initialize non-common string fields if necessary
            header._magic ??= string.Empty;
            header._version ??= string.Empty;
            header._gName ??= string.Empty;
            header._uName ??= string.Empty;
            header._prefix ??= string.Empty;

            return(true);
        }