Пример #1
0
        /// <summary>
        /// Write an archive record to the archive, where the record may be
        /// inside of a larger array buffer. The buffer must be "offset plus
        /// record size" long.
        /// </summary>
        /// <param name="buffer">
        /// The buffer containing the record data to write.
        /// </param>
        /// <param name="offset">
        /// The offset of the record data within buffer.
        /// </param>
        public void WriteBlock(byte[] buffer, int offset)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            if (outputStream == null)
            {
                throw TarException.UnKnown("TarBuffer.WriteBlock - no output stream stream defined");
            }

            if ((offset < 0) || (offset >= buffer.Length))
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            if ((offset + BlockSize) > buffer.Length)
            {
                string errorText = string.Format("TarBuffer.WriteBlock - record has length '{0}' with offset '{1}' which is less than the record size of '{2}'",
                                                 buffer.Length, offset, recordSize);
                throw TarException.UnKnown(errorText);
            }

            if (currentBlockIndex >= BlockFactor)
            {
                WriteRecord();
            }

            Array.Copy(buffer, offset, recordBuffer, (currentBlockIndex * BlockSize), BlockSize);

            currentBlockIndex++;
        }
Пример #2
0
        /// <summary>
        /// Write a block of data to the archive.
        /// </summary>
        /// <param name="block">
        /// The data to write to the archive.
        /// </param>
        public void WriteBlock(byte[] block)
        {
            if (block == null)
            {
                throw new ArgumentNullException(nameof(block));
            }

            if (outputStream == null)
            {
                throw TarException.UnKnown("TarBuffer.WriteBlock - no output stream defined");
            }

            if (block.Length != BlockSize)
            {
                string errorText = string.Format("TarBuffer.WriteBlock - block to write has length '{0}' which is not the block size of '{1}'",
                                                 block.Length, BlockSize);
                throw TarException.UnKnown(errorText);
            }

            if (currentBlockIndex >= BlockFactor)
            {
                WriteRecord();
            }

            Array.Copy(block, 0, recordBuffer, (currentBlockIndex * BlockSize), BlockSize);
            currentBlockIndex++;
        }
Пример #3
0
        /// <summary>
        /// Write a TarBuffer record to the archive.
        /// </summary>
        void WriteRecord()
        {
            if (outputStream == null)
            {
                throw TarException.UnKnown("TarBuffer.WriteRecord no output stream defined");
            }

            outputStream.Write(recordBuffer, 0, RecordSize);
            outputStream.Flush();

            currentBlockIndex = 0;
            currentRecordIndex++;
        }
Пример #4
0
        /// <summary>
        /// WriteFinalRecord writes the current record buffer to output any unwritten data is present.
        /// </summary>
        /// <remarks>Any trailing bytes are set to zero which is by definition correct behaviour
        /// for the end of a tar stream.</remarks>
        void WriteFinalRecord()
        {
            if (outputStream == null)
            {
                throw TarException.UnKnown("TarBuffer.WriteFinalRecord no output stream defined");
            }

            if (currentBlockIndex > 0)
            {
                int dataBytes = currentBlockIndex * BlockSize;
                Array.Clear(recordBuffer, dataBytes, RecordSize - dataBytes);
                WriteRecord();
            }

            outputStream.Flush();
        }
Пример #5
0
        /// <summary>
        /// Skip over a block on the input stream.
        /// </summary>
        public void SkipBlock()
        {
            if (inputStream == null)
            {
                throw TarException.UnKnown("no input stream defined");
            }

            if (currentBlockIndex >= BlockFactor)
            {
                if (!ReadRecord())
                {
                    throw TarException.UnKnown("Failed to read a record");
                }
            }

            currentBlockIndex++;
        }
Пример #6
0
        /// <summary>
        /// Read a record from data stream.
        /// </summary>
        /// <returns>
        /// false if End-Of-File, else true.
        /// </returns>
        bool ReadRecord()
        {
            if (inputStream == null)
            {
                throw TarException.UnKnown("no input stream stream defined");
            }

            currentBlockIndex = 0;

            int offset      = 0;
            int bytesNeeded = RecordSize;

            while (bytesNeeded > 0)
            {
                long numBytes = inputStream.Read(recordBuffer, offset, bytesNeeded);

                //
                // NOTE
                // We have found EOF, and the record is not full!
                //
                // This is a broken archive. It does not follow the standard
                // blocking algorithm. However, because we are generous, and
                // it requires little effort, we will simply ignore the error
                // and continue as if the entire record were read. This does
                // not appear to break anything upstream. We used to return
                // false in this case.
                //
                // Thanks to '*****@*****.**' for this fix.
                //
                if (numBytes <= 0)
                {
                    break;
                }

                offset      += (int)numBytes;
                bytesNeeded -= (int)numBytes;
            }

            currentRecordIndex++;
            return(true);
        }
Пример #7
0
        /// <summary>
        /// Read a block from the input stream.
        /// </summary>
        /// <returns>
        /// The block of data read.
        /// </returns>
        public byte[] ReadBlock()
        {
            if (inputStream == null)
            {
                throw TarException.UnKnown("TarBuffer.ReadBlock - no input stream defined");
            }

            if (currentBlockIndex >= BlockFactor)
            {
                if (!ReadRecord())
                {
                    throw TarException.UnKnown("Failed to read a record");
                }
            }

            byte[] result = new byte[BlockSize];

            Array.Copy(recordBuffer, (currentBlockIndex * BlockSize), result, 0, BlockSize);
            currentBlockIndex++;
            return(result);
        }
Пример #8
0
        /// <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 (hasHitEOF)
            {
                return(null);
            }

            if (currentEntry != null)
            {
                SkipToNextEntry();
            }

            byte[] headerBuf = tarBuffer.ReadBlock();

            if (headerBuf == null)
            {
                hasHitEOF = true;
            }
            else
            {
                hasHitEOF |= TarBuffer.IsEndOfArchiveBlock(headerBuf);
            }

            if (hasHitEOF)
            {
                currentEntry = null;
            }
            else
            {
                try
                {
                    var header = new TarHeader();
                    header.ParseBuffer(headerBuf);
                    if (!header.IsChecksumValid)
                    {
                        throw TarException.InvalidHeader("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 TarException.UnKnown("Failed to read long name entry");
                            }

                            longName.Append(TarHeader.ParseName(nameBuffer, 0, numRead).ToString());
                            numToRead -= numRead;
                        }

                        SkipToNextEntry();
                        headerBuf = this.tarBuffer.ReadBlock();
                    }
                    else if (header.TypeFlag == TarHeader.LF_GHDR)
                    {                      // POSIX global extended header
                        // Ignore things we dont understand completely for now
                        SkipToNextEntry();
                        headerBuf = this.tarBuffer.ReadBlock();
                    }
                    else if (header.TypeFlag == TarHeader.LF_XHDR)
                    {                      // POSIX extended header
                        // Ignore things we dont understand completely for now
                        SkipToNextEntry();
                        headerBuf = this.tarBuffer.ReadBlock();
                    }
                    else if (header.TypeFlag == TarHeader.LF_GNU_VOLHDR)
                    {
                        // TODO: could show volume name when verbose
                        SkipToNextEntry();
                        headerBuf = this.tarBuffer.ReadBlock();
                    }
                    else if (header.TypeFlag != TarHeader.LF_NORMAL &&
                             header.TypeFlag != TarHeader.LF_OLDNORM &&
                             header.TypeFlag != TarHeader.LF_LINK &&
                             header.TypeFlag != TarHeader.LF_SYMLINK &&
                             header.TypeFlag != TarHeader.LF_DIR)
                    {
                        // Ignore things we dont understand completely for now
                        SkipToNextEntry();
                        headerBuf = tarBuffer.ReadBlock();
                    }

                    if (entryFactory == null)
                    {
                        currentEntry = new TarEntry(headerBuf);
                        if (longName != null)
                        {
                            currentEntry.Name = longName.ToString();
                        }
                    }
                    else
                    {
                        currentEntry = entryFactory.CreateEntry(headerBuf);
                    }

                    // Magic was checked here for 'ustar' but there are multiple valid possibilities
                    // so this is not done anymore.

                    entryOffset = 0;

                    // TODO: Review How do we resolve this discrepancy?!
                    entrySize = this.currentEntry.Size;
                }
                catch (TarException ex)
                {
                    entrySize    = 0;
                    entryOffset  = 0;
                    currentEntry = null;
                    string errorText = string.Format("Bad header in record {0} block {1} {2}",
                                                     tarBuffer.CurrentRecord, tarBuffer.CurrentBlock, ex.Message);
                    throw TarException.UnKnown(errorText);
                }
            }
            return(currentEntry);
        }