// Reads attributes specific to the GNU format. // Throws if any conversion fails. private void ReadGnuAttributes(Span <byte> buffer) { // Convert byte arrays long aTime = (long)TarHelpers.ParseOctal <ulong>(buffer.Slice(FieldLocations.ATime, FieldLengths.ATime)); _aTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(aTime); long cTime = (long)TarHelpers.ParseOctal <ulong>(buffer.Slice(FieldLocations.CTime, FieldLengths.CTime)); _cTime = TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch(cTime); // TODO: Read the bytes of the currently unsupported GNU fields, in case user wants to write this entry into another GNU archive, they need to be preserved. https://github.com/dotnet/runtime/issues/68230 }
// Reads the attributes shared by the POSIX and GNU formats. // Throws if converting the bytes to their expected data type fails. private void ReadPosixAndGnuSharedAttributes(Span <byte> buffer) { // Convert the byte arrays _uName = TarHelpers.GetTrimmedAsciiString(buffer.Slice(FieldLocations.UName, FieldLengths.UName)); _gName = TarHelpers.GetTrimmedAsciiString(buffer.Slice(FieldLocations.GName, FieldLengths.GName)); // DevMajor and DevMinor only have values with character devices and block devices. // For all other typeflags, the values in these fields are irrelevant. if (_typeFlag is TarEntryType.CharacterDevice or TarEntryType.BlockDevice) { // Major number for a character device or block device entry. _devMajor = (int)TarHelpers.ParseOctal <uint>(buffer.Slice(FieldLocations.DevMajor, FieldLengths.DevMajor)); // Minor number for a character device or block device entry. _devMinor = (int)TarHelpers.ParseOctal <uint>(buffer.Slice(FieldLocations.DevMinor, FieldLengths.DevMinor)); } }
// Attempts to read the fields shared by all formats and stores them in their expected data type. // Throws if any data type conversion fails. // Returns true on success, false if checksum is zero. private static TarHeader?TryReadCommonAttributes(Span <byte> buffer, TarEntryFormat initialFormat) { // Start by collecting fields that need special checks that return early when data is wrong // Empty checksum means this is an invalid (all blank) entry, finish early Span <byte> spanChecksum = buffer.Slice(FieldLocations.Checksum, FieldLengths.Checksum); if (TarHelpers.IsAllNullBytes(spanChecksum)) { return(null); } int checksum = (int)TarHelpers.ParseOctal <uint>(spanChecksum); // Zero checksum means the whole header is empty if (checksum == 0) { return(null); } long size = (int)TarHelpers.ParseOctal <uint>(buffer.Slice(FieldLocations.Size, FieldLengths.Size)); if (size < 0) { throw new FormatException(string.Format(SR.TarSizeFieldNegative)); } // Continue with the rest of the fields that require no special checks TarHeader header = new(initialFormat, name : TarHelpers.GetTrimmedUtf8String(buffer.Slice(FieldLocations.Name, FieldLengths.Name)), mode : (int)TarHelpers.ParseOctal <uint>(buffer.Slice(FieldLocations.Mode, FieldLengths.Mode)), mTime : TarHelpers.GetDateTimeOffsetFromSecondsSinceEpoch((long)TarHelpers.ParseOctal <ulong>(buffer.Slice(FieldLocations.MTime, FieldLengths.MTime))), typeFlag : (TarEntryType)buffer[FieldLocations.TypeFlag]) { _checksum = checksum, _size = size, _uid = (int)TarHelpers.ParseOctal <uint>(buffer.Slice(FieldLocations.Uid, FieldLengths.Uid)), _gid = (int)TarHelpers.ParseOctal <uint>(buffer.Slice(FieldLocations.Gid, FieldLengths.Gid)), _linkName = TarHelpers.GetTrimmedUtf8String(buffer.Slice(FieldLocations.LinkName, FieldLengths.LinkName)) }; if (header._format == TarEntryFormat.Unknown) { header._format = header._typeFlag switch { TarEntryType.ExtendedAttributes or TarEntryType.GlobalExtendedAttributes => TarEntryFormat.Pax, TarEntryType.DirectoryList or TarEntryType.LongLink or TarEntryType.LongPath or TarEntryType.MultiVolume or TarEntryType.RenamedOrSymlinked or TarEntryType.TapeVolume => TarEntryFormat.Gnu, // V7 is the only one that uses 'V7RegularFile'. TarEntryType.V7RegularFile => TarEntryFormat.V7, TarEntryType.SparseFile => throw new NotSupportedException(string.Format(SR.TarEntryTypeNotSupported, header._typeFlag)), // We can quickly determine the *minimum* possible format if the entry type // is the POSIX 'RegularFile', although later we could upgrade it to PAX or GNU _ => (header._typeFlag == TarEntryType.RegularFile) ? TarEntryFormat.Ustar : TarEntryFormat.V7 }; } return(header); }