/// <summary> /// Parse TarHeader information from a header buffer. /// </summary> /// <param name = "header"> /// The tar entry header buffer to get information from. /// </param> public void ParseBuffer(byte[] header) { if (header == null) { throw new ArgumentNullException("header"); } int offset = 0; name = TarHeader.ParseName(header, offset, TarHeader.NAMELEN).ToString(); offset += TarHeader.NAMELEN; mode = (int)TarHeader.ParseOctal(header, offset, TarHeader.MODELEN); offset += TarHeader.MODELEN; UserId = (int)TarHeader.ParseOctal(header, offset, TarHeader.UIDLEN); offset += TarHeader.UIDLEN; GroupId = (int)TarHeader.ParseOctal(header, offset, TarHeader.GIDLEN); offset += TarHeader.GIDLEN; Size = TarHeader.ParseOctal(header, offset, TarHeader.SIZELEN); offset += TarHeader.SIZELEN; ModTime = GetDateTimeFromCTime(TarHeader.ParseOctal(header, offset, TarHeader.MODTIMELEN)); offset += TarHeader.MODTIMELEN; checksum = (int)TarHeader.ParseOctal(header, offset, TarHeader.CHKSUMLEN); offset += TarHeader.CHKSUMLEN; TypeFlag = header[offset++]; LinkName = TarHeader.ParseName(header, offset, TarHeader.NAMELEN).ToString(); offset += TarHeader.NAMELEN; Magic = TarHeader.ParseName(header, offset, TarHeader.MAGICLEN).ToString(); offset += TarHeader.MAGICLEN; Version = TarHeader.ParseName(header, offset, TarHeader.VERSIONLEN).ToString(); offset += TarHeader.VERSIONLEN; UserName = TarHeader.ParseName(header, offset, TarHeader.UNAMELEN).ToString(); offset += TarHeader.UNAMELEN; GroupName = TarHeader.ParseName(header, offset, TarHeader.GNAMELEN).ToString(); offset += TarHeader.GNAMELEN; DevMajor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN); offset += TarHeader.DEVLEN; DevMinor = (int)TarHeader.ParseOctal(header, offset, TarHeader.DEVLEN); // Fields past this point not currently parsed or used... isChecksumValid = Checksum == TarHeader.MakeCheckSum(header); }
/// <summary> /// Get the next entry in this tar archive. This will skip /// over any remaining data in the current entry, if there /// is one, and place the input stream at the header of the /// next entry, and read the header and instantiate a new /// TarEntry from the header bytes and return that entry. /// If there are no more entries in the archive, null will /// be returned to indicate that the end of the archive has /// been reached. /// </summary> /// <returns> /// The next TarEntry in the archive, or null. /// </returns> public TarEntry GetNextEntry() { if (this.hasHitEOF) { return(null); } if (this.currentEntry != null) { SkipToNextEntry(); } byte[] headerBuf = this.buffer.ReadBlock(); if (headerBuf == null) { this.hasHitEOF = true; } else if (TarBuffer.IsEndOfArchiveBlock(headerBuf)) { this.hasHitEOF = true; } if (this.hasHitEOF) { this.currentEntry = null; } else { try { TarHeader header = new TarHeader(); header.ParseBuffer(headerBuf); if (!header.IsChecksumValid) { throw new TarException("Header checksum is invalid"); } this.entryOffset = 0; this.entrySize = header.Size; StringBuilder longName = null; if (header.TypeFlag == TarHeader.LF_GNU_LONGNAME) { byte[] nameBuffer = new byte[TarBuffer.BlockSize]; long numToRead = this.entrySize; longName = new StringBuilder(); while (numToRead > 0) { int numRead = this.Read(nameBuffer, 0, (numToRead > nameBuffer.Length ? nameBuffer.Length : (int)numToRead)); if (numRead == -1) { throw new InvalidHeaderException("Failed to read long name entry"); } longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString()); numToRead -= numRead; } SkipToNextEntry(); headerBuf = this.buffer.ReadBlock(); } else if (header.TypeFlag == TarHeader.LF_GHDR) // POSIX global extended header // Ignore things we dont understand completely for now { SkipToNextEntry(); headerBuf = this.buffer.ReadBlock(); } else if (header.TypeFlag == TarHeader.LF_XHDR) // POSIX extended header // Ignore things we dont understand completely for now { SkipToNextEntry(); headerBuf = this.buffer.ReadBlock(); } else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR) { // TODO: could show volume name when verbose SkipToNextEntry(); headerBuf = this.buffer.ReadBlock(); } else if (header.TypeFlag != TarHeader.LF_NORMAL && header.TypeFlag != TarHeader.LF_OLDNORM && header.TypeFlag != TarHeader.LF_DIR) { // Ignore things we dont understand completely for now SkipToNextEntry(); headerBuf = this.buffer.ReadBlock(); } if (this.entryFactory == null) { this.currentEntry = new TarEntry(headerBuf); if (longName != null) { currentEntry.Name = longName.ToString(); } } else { this.currentEntry = this.entryFactory.CreateEntry(headerBuf); } // Magic was checked here for 'ustar' but there are multiple valid possibilities // so this is not done anymore. this.entryOffset = 0; // TODO: Review How do we resolve this discrepancy?! this.entrySize = this.currentEntry.Size; } catch (InvalidHeaderException ex) { this.entrySize = 0; this.entryOffset = 0; this.currentEntry = null; string errorText = string.Format("Bad header in record {0} block {1} {2}", buffer.CurrentRecord, buffer.CurrentBlock, ex.Message); throw new InvalidHeaderException(errorText); } } return(this.currentEntry); }