8000 Fix loading extra fields by hainesr · Pull Request #459 · rubyzip/rubyzip · GitHub
[go: up one dir, main page]

Skip to content

Fix loading extra fields #459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion lib/zip/central_directory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,37 @@ def read_central_directory_entries(io) #:nodoc:
end
@entry_set = EntrySet.new
@size.times do
@entry_set << Entry.read_c_dir_entry(io)
entry = Entry.read_c_dir_entry(io)
next unless entry

offset = if entry.extra['Zip64']
entry.extra['Zip64'].relative_header_offset
else
entry.local_header_offset
end

unless offset.nil?
io_save = io.tell
io.seek(offset, IO::SEEK_SET)
entry.read_extra_field(read_local_extra_field(io))
io.seek(io_save, IO::SEEK_SET)
end

@entry_set << entry
end
end

def read_local_extra_field(io)
buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH) || ''
return '' unless buf.bytesize == ::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH

head, _, _, _, _, _, _, _, _, _, n_len, e_len = buf.unpack('VCCvvvvVVVvv')
return '' unless head == ::Zip::LOCAL_ENTRY_SIGNATURE

io.seek(n_len, IO::SEEK_CUR) # Skip over the entry name.
io.read(e_len)
end

def read_from_stream(io) #:nodoc:
buf = start_buf(io)
if zip64_file?(buf)
Expand Down
15 changes: 5 additions & 10 deletions lib/zip/entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,12 +271,7 @@ def read_local_entry(io) #:nodoc:all
raise ::Zip::Error, 'Truncated local zip entry header'
end

if @extra.kind_of?(::Zip::ExtraField)
@extra.merge(extra) if extra
else
@extra = ::Zip::ExtraField.new(extra)
end

read_extra_field(extra)
parse_zip64_extra(true)
@local_header_size = calculate_local_header_size
end
Expand Down Expand Up @@ -379,11 +374,11 @@ def check_c_dir_entry_comment_size
raise ::Zip::Error, 'Truncated cdir zip entry header'
end

def read_c_dir_extra_field(io)
def read_extra_field(buf)
if @extra.kind_of?(::Zip::ExtraField)
@extra.merge(io.read(@extra_length))
@extra.merge(buf) if buf
else
@extra = ::Zip::ExtraField.new(io.read(@extra_length))
@extra = ::Zip::ExtraField.new(buf)
end
end

Expand All @@ -397,7 +392,7 @@ def read_c_dir_entry(io) #:nodoc:all
if ::Zip.force_entry_names_encoding
@name.force_encoding(::Zip.force_entry_names_encoding)
end
read_c_dir_extra_field(io)
read_extra_field(io.read(@extra_length))
@comment = io.read(@comment_length)
check_c_dir_entry_comment_size
set_ftype_from_c_dir_entry
Expand Down
9 changes: 0 additions & 9 deletions lib/zip/extra_field/generic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,6 @@ def initial_parse(binstr)
[binstr[2, 2].unpack1('v'), binstr[4..-1]]
end

def ==(other)
return false if self.class != other.class

each do |k, v|
return false if v != other[k]
end
true
end

def to_local_bin
s = pack_for_local
self.class.const_get(:HEADER_ID) + [s.bytesize].pack('v') << s
Expand Down
4 changes: 2 additions & 2 deletions lib/zip/extra_field/unix.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ def merge(binstr)
return if !size || size == 0

uid, gid = content.unpack('vv')
@uid ||= uid
@gid ||= gid # rubocop:disable Naming/MemoizedInstanceVariableName
@uid = uid
@gid = gid
end

def ==(other)
Expand Down
Binary file added test/data/local_extra_field.zip
Binary file not shown.
24 changes: 24 additions & 0 deletions test/extra_field_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ def test_unknownfield
assert_equal(extra.to_s, 'fooabarbaz')
end

def test_bad_header_id
str = "ut\x5\0\x3\250$\r@"
ut = nil
assert_output('', /WARNING/) do
ut = ::Zip::ExtraField::UniversalTime.new(str)
end
assert_instance_of(::Zip::ExtraField::UniversalTime, ut)
assert_nil(ut.mtime)
end

def test_ntfs
str = "\x0A\x00 \x00\x00\x00\x00\x00\x01\x00\x18\x00\xC0\x81\x17\xE8B\xCE\xCF\x01\xC0\x81\x17\xE8B\xCE\xCF\x01\xC0\x81\x17\xE8B\xCE\xCF\x01"
extra = ::Zip::ExtraField.new(str)
Expand All @@ -25,6 +35,8 @@ def test_ntfs
assert_equal(t, extra['NTFS'].mtime)
assert_equal(t, extra['NTFS'].atime)
assert_equal(t, extra['NTFS'].ctime)

assert_equal(str.force_encoding('BINARY'), extra.to_local_bin)
end

def test_merge
Expand Down Expand Up @@ -73,4 +85,16 @@ def test_equality
extra1.create('IUnix')
assert_equal(extra1, extra3)
end

def test_read_local_extra_field
::Zip::File.open('test/data/local_extra_field.zip') do |zf|
['file1.txt', 'file2.txt'].each do |file|
entry = zf.get_entry(file)

assert_instance_of(::Zip::ExtraField, entry.extra)
assert_equal(1_000, entry.extra['IUnix'].uid)
assert_equal(1_000, entry.extra['IUnix'].gid)
end
end
end
end
6 changes: 4 additions & 2 deletions test/filesystem/file_nonmutating_test.rb
Original file line number Diff line number Diff line change
9E88 Expand Up @@ -295,8 +295,10 @@ def test_ctime
end

def test_atime
assert_nil(@zip_file.file.atime('file1'))
assert_nil(@zip_file.file.stat('file1').atime)
assert_equal(::Zip::DOSTime.at(1_027_694_306),
@zip_file.file.atime('file1'))
assert_equal(::Zip::DOSTime.at(1_027_694_306),
@zip_file.file.stat('file1').atime)
end

def test_ntfs_time
Expand Down
4 changes: 2 additions & 2 deletions test/filesystem/file_stat_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ def test_ino
end

def test_uid
assert_equal(0, @zip_file.file.stat('file1').uid)
assert_equal(500, @zip_file.file.stat('file1').uid)
end

def test_gid
assert_equal(0, @zip_file.file.stat('file1').gid)
assert_equal(500, @zip_file.file.stat('file1').gid)
end

def test_ftype
Expand Down
0