-
Notifications
You must be signed in to change notification settings - Fork 313
Updating to version 3.x
- Version 3.x requires at least ruby 2.5.
- Zip64 extensions support is turned on by default. This should not affect reading files at all, but if you really need to ensure that Zip64 extensions are not used (say, because you need to support a really old version of ZIP) then you can turn them off. See the Configuration section of the README for details of this.
There are a number of places where the API has changed between version 2.x and 3.x
Most changes are due to methods now using named parameters.
No changes in functionality, but now uses named parameters for readability:
- def initialize(path_or_io, create = false, buffer = false, options = {})
+ def initialize(path_or_io, create: false, buffer: false, **options)
In general, use of File::new
is discouraged; favour ::open
and ::open_buffer
if possible.
This method has been removed. Please use ::open_buffer
instead.
This is a new method. Use this to count the number of entries in an archive without reading in the whole central directory, or stepping through all the entries with InputStream
.
No changes in functionality, but now uses named parameters for readability:
- def open(file_name, create = false, options = {})
+ def open(file_name, create: false, **options)
Don't assume that opening a buffer is to create a new archive in it. Also now uses named parameters for readability:
- def open_buffer(io, **options)
+ def open_buffer(io = ::StringIO.new, create: false, **options)
No changes in functionality, but now uses named parameters for readability:
- def split(zip_file_name, segment_size = MAX_SEGMENT_SIZE, delete_zip_file = true, partial_zip_file_name = nil)
+ def split(zip_file_name, segment_size: MAX_SEGMENT_SIZE, delete_original: true, partial_zip_file_name: nil)
Major Update!
This method now forces extraction into the current working directory unless this is overridden by supplying a different directory via destination_directory
.
- def extract(entry, dest_path, &block)
+ def extract(entry, entry_path = nil, destination_directory: '.', &block)
This effectively splits the final location of an extracted entry into two parts:
- the base directory (controlled by
destination_directory
and.
by default); and - the entry path (controlled by
entry_path
and the entry's name by default).
So, if the current working directory is /tmp
, then the following holds for various combinations of entry name and the parameters supplied to #extract
:
entry name | entry_path |
destination_directory |
resulting path |
---|---|---|---|
foo/bar.txt |
<not set> |
<not set> |
/tmp/foo/bar.txt |
foo/bar.txt |
<not set> |
/home/me/work |
/home/me/work/foo/bar.txt |
foo/bar.txt |
<not set> |
files |
/tmp/files/foo/bar.txt |
foo/bar.txt |
baz.txt |
<not set> |
/tmp/baz.txt |
foo/bar.txt |
baz.txt |
/home/me/work |
/home/me/work/baz.txt |
foo/bar.txt |
baz.txt |
files |
/tmp/files/baz.txt |
../bar.txt |
<not set> |
<not set> |
Extraction is skipped and a warning printed to stderr
|
../bar.txt |
<not set> |
/home/me/work |
Extraction is skipped and a warning printed to stderr
|
../bar.txt |
<not set> |
files |
Extraction is skipped and a warning printed to stderr
|
../bar.txt |
baz.txt |
<not set> |
/tmp/baz.txt |
../bar.txt |
baz.txt |
/home/me/work |
/home/me/work/baz.txt |
../bar.txt |
baz.txt |
files |
/tmp/files/baz.txt |
The rationale for this change is to mitigate against so called 'path traversal' hacks. For example, a Zip file may contain an entry called ../etc/passwd
in the hope that someone would unpack it in /tmp
with raised privileges - without path traversal protection this would overwrite /etc/passwd
.
The combination of destination_directory
and the entry name (possibly overridden/replaced by entry_path
) is checked for safety before extraction.
If previously you were doing something like this when using Zip::File#extract
dest_dir = '\tmp\my_app'
::Zip::File.open('zipfile.zip') do |zip|
zip.extract('known_entry.txt', "#{dest_dir}/known_entry.txt")
end
then this will still work! But it can also now be written (and looks more readable) as
dest_dir = '\tmp\my_app'
::Zip::File.open('zipfile.zip') do |zip|
zip.extract('known_entry.txt', destination_directory: dest_dir)
end
No changes in functionality, but now uses named parameters for readability:
- def get_output_stream(entry, permission_int = nil, comment = nil,
- extra = nil, compressed_size = nil, crc = nil,
- compression_method = nil, compression_level = nil,
- size = nil, time = nil, &a_proc)
+ def get_output_stream(entry, permissions: nil, comment: nil,
+ extra: nil, compressed_size: nil, crc: nil,
+ compression_method: nil, compression_level: nil,
+ size: nil, time: nil, &a_proc)
No changes in functionality, but now uses named parameters for readability:
- def initialize(*args)
+ def initialize(
+ zipfile = '', name = '',
+ comment: '', size: 0, compressed_size: 0, crc: 0,
+ compression_method: DEFLATED,
+ compression_level: ::Zip.default_compression,
+ time: ::Zip::DOSTime.now, extra: ::Zip::ExtraField.new
+ )
Major Update!
This method now forces extraction into the current working directory unless this is overridden by supplying a different directory via destination_directory
.
- def extract(dest_path = nil, &block)
+ def extract(entry_path = @name, destination_directory: '.', &block)
This effectively splits the final location of an extracted entry into two parts:
- the base directory (controlled by
destination_directory
and.
by default); and - the entry path (controlled by
entry_path
and the entry's name by default).
See File#extract, above, for the details and rationale for this change.
If previously you were doing something like this when using Zip::Entry#extract
dest_dir = '\tmp\my_app'
::Zip::File.open('zipfile.zip') do |zip|
zip.entries do |entry|
entry.extract(::File.join(dest_dir, entry.name))
end
end
then this will still work! But it can also now be written (and looks more readable) as
dest_dir = '\tmp\my_app'
::Zip::File.open('zipfile.zip') do |zip|
zip.entries do |entry|
entry.extract(destination_directory: dest_dir)
end
end
New method. A new alias of #time=
New method. A cleaner way to detect an Entry
that has ZIP64 extensions present.
This method now returns the empty string ''
if it is passed zero for number_of_bytes
.
New method. This returns the uncompressed size of the current entry in bytes, or nil
if there is no current entry.
No changes in functionality, but now uses named parameters for readability:
- def initialize(file_name, stream = false, encrypter = nil)
+ def initialize(file_name, stream: false, encrypter: nil)
No changes in functionality, but now uses named parameters for readability:
- def open(file_name, encrypter = nil)
+ def open(file_name, encrypter: nil)
No changes in functionality, but now uses named parameters for readability:
- def write_buffer(io = ::StringIO.new(''), encrypter = nil)
+ def write_buffer(io = ::StringIO.new(''), encrypter: nil)