summaryrefslogtreecommitdiff
path: root/lib/rubygems/package/tar_reader
diff options
context:
space:
mode:
authorMartin Emde <martin.emde@gmail.com>2023-08-15 10:39:46 -0700
committergit <svn-admin@ruby-lang.org>2023-08-17 23:16:57 +0000
commite913431687f2fffb1a8cc435e60c95eea887b087 (patch)
tree1df72eed6c68958b0d38efe6d9600541a446da4e /lib/rubygems/package/tar_reader
parente504c368943acd489c9be5bc249425e885605ff1 (diff)
[rubygems/rubygems] Raise Gem::Package::FormatError on EOF, indicating corrupt gem
Gem::Package::TarReader::Entry now raises EOFError or returns nil appropriately based on Ruby core IO.read and IO.readpartial behavior. Zlib will respond accordingly by raising Zlib::GzipFile::Error on EOF. When verifying a gem or extracting contents, raise FormatError similar to other cases of corrupt gems. Addresses a bug where Gem::Package would attempt to call size on nil instead of raising a more descriptive and useful error, leading users to assume the problem is internal to rubygems. Remove unused error class TarReader::UnexpectedEOF that was never raised since the NoMethodError on nil would happen first. Use EOFError instead. https://github.com/rubygems/rubygems/commit/dc6129644b
Diffstat (limited to 'lib/rubygems/package/tar_reader')
-rw-r--r--lib/rubygems/package/tar_reader/entry.rb38
1 files changed, 18 insertions, 20 deletions
diff --git a/lib/rubygems/package/tar_reader/entry.rb b/lib/rubygems/package/tar_reader/entry.rb
index e22efa95b3..5e9d9af5c6 100644
--- a/lib/rubygems/package/tar_reader/entry.rb
+++ b/lib/rubygems/package/tar_reader/entry.rb
@@ -102,9 +102,7 @@ class Gem::Package::TarReader::Entry
# Read one byte from the tar entry
def getc
- check_closed
-
- return nil if @read >= @header.size
+ return nil if eof?
ret = @io.getc
@read += 1 if ret
@@ -156,30 +154,28 @@ class Gem::Package::TarReader::Entry
alias_method :length, :size
##
- # Reads +len+ bytes from the tar file entry, or the rest of the entry if
- # nil
-
- def read(len = nil)
- check_closed
-
- len ||= @header.size - @read
+ # Reads +maxlen+ bytes from the tar file entry, or the rest of the entry if nil
- return nil if len > 0 && @read >= @header.size
+ def read(maxlen = nil)
+ if eof?
+ return maxlen.to_i.zero? ? "" : nil
+ end
- max_read = [len, @header.size - @read].min
+ max_read = [maxlen, @header.size - @read].compact.min
ret = @io.read max_read
+ if ret.nil?
+ return maxlen ? nil : "" # IO.read returns nil on EOF with len argument
+ end
@read += ret.size
ret
end
- def readpartial(maxlen = nil, outbuf = "".b)
- check_closed
-
- maxlen ||= @header.size - @read
-
- raise EOFError if maxlen > 0 && @read >= @header.size
+ def readpartial(maxlen, outbuf = "".b)
+ if eof? && maxlen > 0
+ raise EOFError, "end of file reached"
+ end
max_read = [maxlen, @header.size - @read].min
@@ -213,6 +209,8 @@ class Gem::Package::TarReader::Entry
pending = new_pos - @io.pos
+ return 0 if pending == 0
+
if @io.respond_to?(:seek)
begin
# avoid reading if the @io supports seeking
@@ -230,8 +228,8 @@ class Gem::Package::TarReader::Entry
end
while pending > 0 do
- size_read = @io.read([pending, 4096].min).size
- raise UnexpectedEOF if @io.eof?
+ size_read = @io.read([pending, 4096].min)&.size
+ raise(EOFError, "end of file reached") if size_read.nil?
pending -= size_read
end