class Minitar::Reader::InvalidEntryStream::EntryStream
EntryStreams are pseudo-streams on top of the main data stream.
Public Class Methods
Source
# File lib/minitar/reader.rb, line 165 def self.each_entry(io) return to_enum(__method__, io) unless block_given? Input.open(io) do |reader| reader.each_entry do |entry| yield entry end end end
Iterates over each entry in the provided input. This wraps the common pattern of:
Minitar::Input.open(io) do |i| inp.each do |entry| # ... end end
If a block is not provided, an enumerator will be created with the same behaviour.
Source
# File lib/minitar/reader.rb, line 28 def initialize(header, io) @io = io @name = header.name @mode = header.mode @uid = header.uid @gid = header.gid @size = header.size @mtime = header.mtime @checksum = header.checksum @typeflag = header.typeflag @linkname = header.linkname @magic = header.magic @version = header.version @uname = header.uname @gname = header.gname @devmajor = header.devmajor @devminor = header.devminor @prefix = header.prefix @read = 0 @orig_pos = if Minitar.seekable?(@io) @io.pos else 0 end end
Source
# File lib/minitar/reader.rb, line 139 def self.open(io) reader = new(io) return reader unless block_given? # This exception context must remain, otherwise the stream closes on open even if # a block is not given. begin yield reader ensure reader.close end end
With no associated block, Reader::open is a synonym for Reader::new. If the optional code block is given, it will be passed the new writer as an argument and the Reader object will automatically be closed when the block terminates. In this instance, Reader::open returns the value of the block.
Public Instance Methods
Source
# File lib/minitar/reader.rb, line 126 def close = invalidate private def invalidate extend InvalidEntryStream end end
Closes the entry.
Source
# File lib/minitar/reader.rb, line 123 def closed? = false # Closes the entry. def close = invalidate private def invalidate extend InvalidEntryStream end end # With no associated block, +Reader::open+ is a synonym for +Reader::new+. If the # optional code block is given, it will be passed the new _writer_ as an argument and # the Reader object will automatically be closed when the block terminates. In this # instance, +Reader::open+ returns the value of the block. def self.open(io) reader = new(io) return reader unless block_given? # This exception context must remain, otherwise the stream closes on open even if # a block is not given. begin yield reader ensure reader.close end end # Iterates over each entry in the provided input. This wraps the common pattern of: # # Minitar::Input.open(io) do |i| # inp.each do |entry| # # ... # end # end # # If a block is not provided, an enumerator will be created with the same behaviour. # # :call-seq: # Minitar::Reader.each_entry(io) -> enumerator # Minitar::Reader.each_entry(io) { |entry| block } -> obj def self.each_entry(io) return to_enum(__method__, io) unless block_given? Input.open(io) do |reader| reader.each_entry do |entry| yield entry end end end # Creates and returns a new Reader object. def initialize(io) @io = io @init_pos = begin io.pos rescue nil end end # Resets the read pointer to the beginning of data stream. Do not call this during # a #each or #each_entry iteration. This only works with random access data streams # that respond to #rewind and #pos. def rewind if @init_pos.zero? raise Minitar::NonSeekableStream unless Minitar.seekable?(@io, :rewind) @io.rewind else raise Minitar::NonSeekableStream unless Minitar.seekable?(@io, :pos=) @io.pos = @init_pos end end # Iterates through each entry in the data stream. def each_entry return to_enum unless block_given? loop do return if @io.eof? header = Minitar::PosixHeader.from_stream(@io) raise Minitar::InvalidTarStream unless header.valid? return if header.empty? raise Minitar::InvalidTarStream if header.size < 0 if header.long_name? name_block = (header.size / 512.0).ceil * 512 long_name = @io.read(name_block).rstrip header = PosixHeader.from_stream(@io) return if header.empty? header.long_name = long_name elsif header.pax_header? pax_header = PaxHeader.from_stream(@io, header) header = PosixHeader.from_stream(@io) return if header.empty? header.size = pax_header.size if pax_header.size end entry = EntryStream.new(header, @io) size = entry.size yield entry skip = (512 - (size % 512)) % 512 if Minitar.seekable?(@io, :seek) # avoid reading... try_seek(size - entry.bytes_read) else pending = size - entry.bytes_read while pending > 0 bread = @io.read([pending, 4096].min).bytesize raise UnexpectedEOF if @io.eof? pending -= bread end end @io.read(skip) # discard trailing zeros # make sure nobody can use #read, #getc or #rewind anymore entry.close end end alias_method :each, :each_entry # Returns false if the reader is open (it never closes). def closed? = false def close end private def try_seek(bytes) @io.seek(bytes, IO::SEEK_CUR) rescue RangeError # This happens when skipping the large entry and the skipping entry size exceeds # maximum allowed size (varies by platform and underlying IO object). max = RbConfig::LIMITS.fetch("INT_MAX", 2147483647) skipped = 0 while skipped < bytes to_skip = [bytes - skipped, max].min @io.seek(to_skip, IO::SEEK_CUR) skipped += to_skip end end end end
Returns false if the entry stream is valid.
Source
# File lib/minitar/reader.rb, line 75 def directory? case @typeflag when "5" true when "0", "\0" # If the name ends with a slash, treat it as a directory. This is what other # major tar implementations do for interoperability and compatibility with older # tar variants and some new ones. @name.end_with?("/") else false end end
Returns true if the entry represents a directory.
Source
# File lib/minitar/reader.rb, line 199 def each_entry return to_enum unless block_given? loop do return if @io.eof? header = Minitar::PosixHeader.from_stream(@io) raise Minitar::InvalidTarStream unless header.valid? return if header.empty? raise Minitar::InvalidTarStream if header.size < 0 if header.long_name? name_block = (header.size / 512.0).ceil * 512 long_name = @io.read(name_block).rstrip header = PosixHeader.from_stream(@io) return if header.empty? header.long_name = long_name elsif header.pax_header? pax_header = PaxHeader.from_stream(@io, header) header = PosixHeader.from_stream(@io) return if header.empty? header.size = pax_header.size if pax_header.size end entry = EntryStream.new(header, @io) size = entry.size yield entry skip = (512 - (size % 512)) % 512 if Minitar.seekable?(@io, :seek) # avoid reading... try_seek(size - entry.bytes_read) else pending = size - entry.bytes_read while pending > 0 bread = @io.read([pending, 4096].min).bytesize raise UnexpectedEOF if @io.eof? pending -= bread end end @io.read(skip) # discard trailing zeros # make sure nobody can use #read, #getc or #rewind anymore entry.close end end
Iterates through each entry in the data stream.
Source
# File lib/minitar/reader.rb, line 97 def eof? = @read >= @size # Returns the current read pointer in the EntryStream. def pos = @read alias_method :bytes_read, :pos # Sets the current read pointer to the beginning of the EntryStream. def rewind unless Minitar.seekable?(@io, :pos=) raise Minitar::NonSeekableStream end @io.pos = @orig_pos @read = 0 end # Returns the full and proper name of the entry. def full_name if @prefix != "" File.join(@prefix, @name) else @name end end # Returns false if the entry stream is valid. def closed? = false # Closes the entry. def close = invalidate private def invalidate extend InvalidEntryStream end end # With no associated block, +Reader::open+ is a synonym for +Reader::new+. If the # optional code block is given, it will be passed the new _writer_ as an argument and # the Reader object will automatically be closed when the block terminates. In this # instance, +Reader::open+ returns the value of the block. def self.open(io) reader = new(io) return reader unless block_given? # This exception context must remain, otherwise the stream closes on open even if # a block is not given. begin yield reader ensure reader.close end end # Iterates over each entry in the provided input. This wraps the common pattern of: # # Minitar::Input.open(io) do |i| # inp.each do |entry| # # ... # end # end # # If a block is not provided, an enumerator will be created with the same behaviour. # # :call-seq: # Minitar::Reader.each_entry(io) -> enumerator # Minitar::Reader.each_entry(io) { |entry| block } -> obj def self.each_entry(io) return to_enum(__method__, io) unless block_given? Input.open(io) do |reader| reader.each_entry do |entry| yield entry end end end # Creates and returns a new Reader object. def initialize(io) @io = io @init_pos = begin io.pos rescue nil end end # Resets the read pointer to the beginning of data stream. Do not call this during # a #each or #each_entry iteration. This only works with random access data streams # that respond to #rewind and #pos. def rewind if @init_pos.zero? raise Minitar::NonSeekableStream unless Minitar.seekable?(@io, :rewind) @io.rewind else raise Minitar::NonSeekableStream unless Minitar.seekable?(@io, :pos=) @io.pos = @init_pos end end # Iterates through each entry in the data stream. def each_entry return to_enum unless block_given? loop do return if @io.eof? header = Minitar::PosixHeader.from_stream(@io) raise Minitar::InvalidTarStream unless header.valid? return if header.empty? raise Minitar::InvalidTarStream if header.size < 0 if header.long_name? name_block = (header.size / 512.0).ceil * 512 long_name = @io.read(name_block).rstrip header = PosixHeader.from_stream(@io) return if header.empty? header.long_name = long_name elsif header.pax_header? pax_header = PaxHeader.from_stream(@io, header) header = PosixHeader.from_stream(@io) return if header.empty? header.size = pax_header.size if pax_header.size end entry = EntryStream.new(header, @io) size = entry.size yield entry skip = (512 - (size % 512)) % 512 if Minitar.seekable?(@io, :seek) # avoid reading... try_seek(size - entry.bytes_read) else pending = size - entry.bytes_read while pending > 0 bread = @io.read([pending, 4096].min).bytesize raise UnexpectedEOF if @io.eof? pending -= bread end end @io.read(skip) # discard trailing zeros # make sure nobody can use #read, #getc or #rewind anymore entry.close end end alias_method :each, :each_entry # Returns false if the reader is open (it never closes). def closed? = false def close end private def try_seek(bytes) @io.seek(bytes, IO::SEEK_CUR) rescue RangeError # This happens when skipping the large entry and the skipping entry size exceeds # maximum allowed size (varies by platform and underlying IO object). max = RbConfig::LIMITS.fetch("INT_MAX", 2147483647) skipped = 0 while skipped < bytes to_skip = [bytes - skipped, max].min @io.seek(to_skip, IO::SEEK_CUR) skipped += to_skip end end
Returns true if the current read pointer is at the end of the EntryStream data.
Source
# File lib/minitar/reader.rb, line 91 def file? (@typeflag == "0" || @typeflag == "\0") && !@name.end_with?("/") end
Returns true if the entry represents a plain file.
Source
# File lib/minitar/reader.rb, line 114 def full_name if @prefix != "" File.join(@prefix, @name) else @name end end
Returns the full and proper name of the entry.
Source
# File lib/minitar/reader.rb, line 67 def getc return nil if @read >= @size ret = @io.getc @read += 1 if ret ret end
Reads one byte from the entry. Returns nil if there is no more data to read.
Source
# File lib/minitar/reader.rb, line 130 def invalidate extend InvalidEntryStream end
Source
# File lib/minitar/reader.rb, line 100 def pos = @read alias_method :bytes_read, :pos # Sets the current read pointer to the beginning of the EntryStream. def rewind unless Minitar.seekable?(@io, :pos=) raise Minitar::NonSeekableStream end @io.pos = @orig_pos @read = 0 end # Returns the full and proper name of the entry. def full_name if @prefix != "" File.join(@prefix, @name) else @name end end # Returns false if the entry stream is valid. def closed? = false # Closes the entry. def close = invalidate private def invalidate extend InvalidEntryStream end end # With no associated block, +Reader::open+ is a synonym for +Reader::new+. If the # optional code block is given, it will be passed the new _writer_ as an argument and # the Reader object will automatically be closed when the block terminates. In this # instance, +Reader::open+ returns the value of the block. def self.open(io) reader = new(io) return reader unless block_given? # This exception context must remain, otherwise the stream closes on open even if # a block is not given. begin yield reader ensure reader.close end end # Iterates over each entry in the provided input. This wraps the common pattern of: # # Minitar::Input.open(io) do |i| # inp.each do |entry| # # ... # end # end # # If a block is not provided, an enumerator will be created with the same behaviour. # # :call-seq: # Minitar::Reader.each_entry(io) -> enumerator # Minitar::Reader.each_entry(io) { |entry| block } -> obj def self.each_entry(io) return to_enum(__method__, io) unless block_given? Input.open(io) do |reader| reader.each_entry do |entry| yield entry end end end # Creates and returns a new Reader object. def initialize(io) @io = io @init_pos = begin io.pos rescue nil end end # Resets the read pointer to the beginning of data stream. Do not call this during # a #each or #each_entry iteration. This only works with random access data streams # that respond to #rewind and #pos. def rewind if @init_pos.zero? raise Minitar::NonSeekableStream unless Minitar.seekable?(@io, :rewind) @io.rewind else raise Minitar::NonSeekableStream unless Minitar.seekable?(@io, :pos=) @io.pos = @init_pos end end # Iterates through each entry in the data stream. def each_entry return to_enum unless block_given? loop do return if @io.eof? header = Minitar::PosixHeader.from_stream(@io) raise Minitar::InvalidTarStream unless header.valid? return if header.empty? raise Minitar::InvalidTarStream if header.size < 0 if header.long_name? name_block = (header.size / 512.0).ceil * 512 long_name = @io.read(name_block).rstrip header = PosixHeader.from_stream(@io) return if header.empty? header.long_name = long_name elsif header.pax_header? pax_header = PaxHeader.from_stream(@io, header) header = PosixHeader.from_stream(@io) return if header.empty? header.size = pax_header.size if pax_header.size end entry = EntryStream.new(header, @io) size = entry.size yield entry skip = (512 - (size % 512)) % 512 if Minitar.seekable?(@io, :seek) # avoid reading... try_seek(size - entry.bytes_read) else pending = size - entry.bytes_read while pending > 0 bread = @io.read([pending, 4096].min).bytesize raise UnexpectedEOF if @io.eof? pending -= bread end end @io.read(skip) # discard trailing zeros # make sure nobody can use #read, #getc or #rewind anymore entry.close end end alias_method :each, :each_entry # Returns false if the reader is open (it never closes). def closed? = false def close end private def try_seek(bytes) @io.seek(bytes, IO::SEEK_CUR) rescue RangeError # This happens when skipping the large entry and the skipping entry size exceeds # maximum allowed size (varies by platform and underlying IO object). max = RbConfig::LIMITS.fetch("INT_MAX", 2147483647) skipped = 0 while skipped < bytes to_skip = [bytes - skipped, max].min @io.seek(to_skip, IO::SEEK_CUR) skipped += to_skip end end end
Returns the current read pointer in the EntryStream.
Source
# File lib/minitar/reader.rb, line 57 def read(len = nil) return nil if @read >= @size len ||= @size - @read max_read = [len, @size - @read].min ret = @io.read(max_read) @read += ret.bytesize ret end
Reads len bytes (or all remaining data) from the entry. Returns nil if there is no more data to read.
Source
# File lib/minitar/reader.rb, line 105 def rewind unless Minitar.seekable?(@io, :pos=) raise Minitar::NonSeekableStream end @io.pos = @orig_pos @read = 0 end
Sets the current read pointer to the beginning of the EntryStream.
Source
# File lib/minitar/reader.rb, line 262 def try_seek(bytes) @io.seek(bytes, IO::SEEK_CUR) rescue RangeError # This happens when skipping the large entry and the skipping entry size exceeds # maximum allowed size (varies by platform and underlying IO object). max = RbConfig::LIMITS.fetch("INT_MAX", 2147483647) skipped = 0 while skipped < bytes to_skip = [bytes - skipped, max].min @io.seek(to_skip, IO::SEEK_CUR) skipped += to_skip end end