mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
3e92b635fb
When you change this to true, you may need to add more tests. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53141 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
124 lines
2.4 KiB
Ruby
124 lines
2.4 KiB
Ruby
# -*- coding: utf-8 -*-
|
|
# frozen_string_literal: false
|
|
#--
|
|
# Copyright (C) 2004 Mauricio Julio Fernández Pradier
|
|
# See LICENSE.txt for additional licensing information.
|
|
#++
|
|
|
|
##
|
|
# TarReader reads tar files and allows iteration over their items
|
|
|
|
class Gem::Package::TarReader
|
|
|
|
include Enumerable
|
|
|
|
##
|
|
# Raised if the tar IO is not seekable
|
|
|
|
class UnexpectedEOF < StandardError; end
|
|
|
|
##
|
|
# Creates a new TarReader on +io+ and yields it to the block, if given.
|
|
|
|
def self.new(io)
|
|
reader = super
|
|
|
|
return reader unless block_given?
|
|
|
|
begin
|
|
yield reader
|
|
ensure
|
|
reader.close
|
|
end
|
|
|
|
nil
|
|
end
|
|
|
|
##
|
|
# Creates a new tar file reader on +io+ which needs to respond to #pos,
|
|
# #eof?, #read, #getc and #pos=
|
|
|
|
def initialize(io)
|
|
@io = io
|
|
@init_pos = io.pos
|
|
end
|
|
|
|
##
|
|
# Close the tar file
|
|
|
|
def close
|
|
end
|
|
|
|
##
|
|
# Iterates over files in the tarball yielding each entry
|
|
|
|
def each
|
|
return enum_for __method__ unless block_given?
|
|
|
|
until @io.eof? do
|
|
header = Gem::Package::TarHeader.from @io
|
|
return if header.empty?
|
|
|
|
entry = Gem::Package::TarReader::Entry.new header, @io
|
|
size = entry.header.size
|
|
|
|
yield entry
|
|
|
|
skip = (512 - (size % 512)) % 512
|
|
pending = size - entry.bytes_read
|
|
|
|
begin
|
|
# avoid reading...
|
|
@io.seek pending, IO::SEEK_CUR
|
|
pending = 0
|
|
rescue Errno::EINVAL, NameError
|
|
while pending > 0 do
|
|
bytes_read = @io.read([pending, 4096].min).size
|
|
raise UnexpectedEOF if @io.eof?
|
|
pending -= bytes_read
|
|
end
|
|
end
|
|
|
|
@io.read skip # discard trailing zeros
|
|
|
|
# make sure nobody can use #read, #getc or #rewind anymore
|
|
entry.close
|
|
end
|
|
end
|
|
|
|
alias each_entry each
|
|
|
|
##
|
|
# NOTE: Do not call #rewind during #each
|
|
|
|
def rewind
|
|
if @init_pos == 0 then
|
|
raise Gem::Package::NonSeekableIO unless @io.respond_to? :rewind
|
|
@io.rewind
|
|
else
|
|
raise Gem::Package::NonSeekableIO unless @io.respond_to? :pos=
|
|
@io.pos = @init_pos
|
|
end
|
|
end
|
|
|
|
##
|
|
# Seeks through the tar file until it finds the +entry+ with +name+ and
|
|
# yields it. Rewinds the tar file to the beginning when the block
|
|
# terminates.
|
|
|
|
def seek name # :yields: entry
|
|
found = find do |entry|
|
|
entry.full_name == name
|
|
end
|
|
|
|
return unless found
|
|
|
|
return yield found
|
|
ensure
|
|
rewind
|
|
end
|
|
|
|
end
|
|
|
|
require 'rubygems/package/tar_reader/entry'
|
|
|