Skip to content

Commit

Permalink
Fix for rubyzip#126 and rubyzip#127
Browse files Browse the repository at this point in the history
  • Loading branch information
simonoff committed Jan 24, 2014
1 parent 4f9b642 commit ec81c30
Show file tree
Hide file tree
Showing 19 changed files with 138 additions and 115 deletions.
34 changes: 8 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,32 +116,6 @@ end
File.open(new_path, "w") {|f| f.write(buffer.string) }
```

## Further Documentation

There is more than one way to access or create a zip archive with
rubyzip. The basic API is modeled after the classes in
java.util.zip from the Java SDK. This means there are classes such
as Zip::InputStream, Zip::OutputStream and
Zip::File. Zip::InputStream provides a basic interface for
iterating through the entries in a zip archive and reading from the
entries in the same way as from a regular File or IO
object. OutputStream is the corresponding basic output
facility. Zip::File provides a mean for accessing the archives
central directory and provides means for accessing any entry without
having to iterate through the archive. Unlike Java's
java.util.zip.ZipFile rubyzip's Zip::File is mutable, which means
it can be used to change zip files as well.

Another way to access a zip archive with rubyzip is to use rubyzip's
Zip::FileSystem API. Using this API files can be read from and
written to the archive in much the same manner as ruby's builtin
classes allows files to be read from and written to the file system.

For details about the specific behaviour of classes and methods refer
to the test suite. Finally you can generate the rdoc documentation or
visit http://rubyzip.sourceforge.net.


## Configuration

By default, rubyzip will not overwrite files if they already exist inside of the extracted path. To change this behavior, you may specify a configuration option like so:
Expand Down Expand Up @@ -183,6 +157,14 @@ All settings in same time
end
```

By default Zip64 support is disabled for writing. To enable it do next:

```ruby
Zip.write_zip64_support = true
```

_NOTE_: If you will enable Zip64 writing then you will need zip extractor with Zip64 support to extract archive.

## Developing

To run tests you need run next commands:
Expand Down
1 change: 0 additions & 1 deletion TODO
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* Suggestion: Add ZipFile/ZipInputStream example that demonstrates extracting all entries.
* Suggestion: ZipFile#extract destination should default to "."
* Suggestion: ZipEntry should have extract(), get_input_stream() methods etc
* Suggestion: ZipInputStream/ZipOutputStream should accept an IO object in addition to a filename.
* (is buffering used anywhere with write?)
* Inflater.sysread should pass the buffer to produce_input.
* Implement ZipFsDir.glob
Expand Down
3 changes: 2 additions & 1 deletion lib/zip.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@

module Zip
extend self
attr_accessor :unicode_names, :on_exists_proc, :continue_on_exists_proc, :sort_entries, :default_compression
attr_accessor :unicode_names, :on_exists_proc, :continue_on_exists_proc, :sort_entries, :default_compression, :write_zip64_support

def reset!
@_ran_once = false
Expand All @@ -43,6 +43,7 @@ def reset!
@continue_on_exists_proc = false
@sort_entries = false
@default_compression = ::Zlib::DEFAULT_COMPRESSION
@write_zip64_support = false
end

def setup
Expand Down
16 changes: 8 additions & 8 deletions lib/zip/central_directory.rb
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def read_64_e_o_c_d(buf) #:nodoc:
@size_in_bytes = Entry.read_zip_64_long(buf)
@cdir_offset = Entry.read_zip_64_long(buf)
@zip_64_extensible = buf.slice!(0, buf.bytesize)
raise ZipError, "Zip consistency problem while reading eocd structure" unless buf.size == 0
raise Error, "Zip consistency problem while reading eocd structure" unless buf.size == 0
end

def read_e_o_c_d(buf) #:nodoc:
Expand All @@ -110,14 +110,14 @@ def read_e_o_c_d(buf) #:nodoc:
else
buf.read(comment_length)
end
raise ZipError, "Zip consistency problem while reading eocd structure" unless buf.size == 0
raise Error, "Zip consistency problem while reading eocd structure" unless buf.size == 0
end

def read_central_directory_entries(io) #:nodoc:
begin
io.seek(@cdir_offset, IO::SEEK_SET)
rescue Errno::EINVAL
raise ZipError, "Zip consistency problem while reading central directory entry"
raise Error, "Zip consistency problem while reading central directory entry"
end
@entry_set = EntrySet.new
@size.times do
Expand All @@ -137,7 +137,7 @@ def read_from_stream(io) #:nodoc:

def get_e_o_c_d(buf) #:nodoc:
sig_index = buf.rindex([END_OF_CDS].pack('V'))
raise ZipError, "Zip end of central directory signature not found" unless sig_index
raise Error, "Zip end of central directory signature not found" unless sig_index
buf = buf.slice!((sig_index + 4)..(buf.bytesize))

def buf.read(count)
Expand All @@ -162,9 +162,9 @@ def start_buf(io)

def get_64_e_o_c_d(buf) #:nodoc:
zip_64_start = buf.rindex([ZIP64_END_OF_CDS].pack('V'))
raise ZipError, "Zip64 end of central directory signature not found" unless zip_64_start
raise Error, "Zip64 end of central directory signature not found" unless zip_64_start
zip_64_locator = buf.rindex([ZIP64_EOCD_LOCATOR].pack('V'))
raise ZipError, "Zip64 end of central directory signature locator not found" unless zip_64_locator
raise Error, "Zip64 end of central directory signature locator not found" unless zip_64_locator
buf = buf.slice!((zip_64_start + 4)..zip_64_locator)

def buf.read(count)
Expand All @@ -179,7 +179,7 @@ def each(&proc)
@entry_set.each(&proc)
end

# Returns the number of entries in the central directory (and
# Returns the number of entries in the central directory (and
# consequently in the zip archive).
def size
@entry_set.size
Expand All @@ -189,7 +189,7 @@ def self.read_from_stream(io) #:nodoc:
cdir = new
cdir.read_from_stream(io)
return cdir
rescue ZipError
rescue Error
return nil
end

Expand Down
40 changes: 22 additions & 18 deletions lib/zip/entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def set_default_vars_values

def check_name(name)
if name.start_with?('/')
raise ::Zip::ZipEntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
raise ::Zip::EntryNameError, "Illegal ZipEntry name '#{name}', name must not start with /"
end
end

Expand Down Expand Up @@ -92,7 +92,7 @@ def time=(value)
end

def file_type_is?(type)
raise ZipInternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
raise InternalError, "current filetype is unknown: #{self.inspect}" unless @ftype
@ftype == type
end

Expand Down Expand Up @@ -132,7 +132,7 @@ def calculate_local_header_size #:nodoc:all
def verify_local_header_size!
return if @local_header_size == 0
new_size = calculate_local_header_size
raise ZipError, "local header size changed (#{@local_header_size} -> #{new_size})" if @local_header_size != new_size
raise Error, "local header size changed (#{@local_header_size} -> #{new_size})" if @local_header_size != new_size
end

def cdir_header_size #:nodoc:all
Expand Down Expand Up @@ -185,15 +185,15 @@ def read_c_dir_entry(io) #:nodoc:all
entry = new(path)
entry.read_c_dir_entry(io)
entry
rescue ZipError
rescue Error
nil
end

def read_local_entry(io)
entry = self.new
entry = self.new(io)
entry.read_local_entry(io)
entry
rescue ZipError
rescue Error
nil
end

Expand Down Expand Up @@ -222,13 +222,13 @@ def read_local_entry(io) #:nodoc:all
static_sized_fields_buf = io.read(::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH)

unless static_sized_fields_buf.bytesize == ::Zip::LOCAL_ENTRY_STATIC_HEADER_LENGTH
raise ZipError, "Premature end of file. Not enough data for zip entry local header"
raise Error, "Premature end of file. Not enough data for zip entry local header"
end

unpack_local_entry(static_sized_fields_buf)

unless @header_signature == ::Zip::LOCAL_ENTRY_SIGNATURE
raise ::Zip::ZipError, "Zip local header magic not found at location '#{local_header_offset}'"
raise ::Zip::Error, "Zip local header magic not found at location '#{local_header_offset}'"
end
set_time(@last_mod_date, @last_mod_time)

Expand All @@ -238,7 +238,7 @@ def read_local_entry(io) #:nodoc:all
@name.gsub!('\\', '/')

if extra && extra.bytesize != @extra_length
raise ::Zip::ZipError, "Truncated local zip entry header"
raise ::Zip::Error, "Truncated local zip entry header"
else
if ::Zip::ExtraField === @extra
@extra.merge(extra)
Expand Down Expand Up @@ -332,19 +332,19 @@ def set_ftype_from_c_dir_entry

def check_c_dir_entry_static_header_length(buf)
unless buf.bytesize == ::Zip::CDIR_ENTRY_STATIC_HEADER_LENGTH
raise ZipError, 'Premature end of file. Not enough data for zip cdir entry header'
raise Error, 'Premature end of file. Not enough data for zip cdir entry header'
end
end

def check_c_dir_entry_signature
unless header_signature == ::Zip::CENTRAL_DIRECTORY_ENTRY_SIGNATURE
raise ZipError, "Zip local header magic not found at location '#{local_header_offset}'"
raise Error, "Zip local header magic not found at location '#{local_header_offset}'"
end
end

def check_c_dir_entry_comment_size
unless @comment && @comment.bytesize == @comment_length
raise ::Zip::ZipError, "Truncated cdir zip entry header"
raise ::Zip::Error, "Truncated cdir zip entry header"
end
end

Expand Down Expand Up @@ -427,7 +427,10 @@ def pack_c_dir_entry
(zip64 && zip64.disk_start_number) ? 0xFFFF : 0, # disk number start
@internal_file_attributes, # file type (binary=0, text=1)
@external_file_attributes, # native filesystem attributes
(zip64 && zip64.relative_header_offset) ? 0xFFFFFFFF : @local_header_offset
(zip64 && zip64.relative_header_offset) ? 0xFFFFFFFF : @local_header_offset,
@name,
@extra,
@comment
].pack('VCCvvvvvVVVvvvvvVV')
end

Expand Down Expand Up @@ -516,7 +519,7 @@ def gather_fileinfo_from_srcpath(src_path) # :nodoc:
end
:file
when 'directory'
@name += "/" unless name_is_directory?
@name += '/' unless name_is_directory?
:directory
when 'link'
if name_is_directory?
Expand Down Expand Up @@ -568,7 +571,7 @@ def set_time(binary_dos_date, binary_dos_time)

def create_file(dest_path, continue_on_exists_proc = proc { Zip.continue_on_exists_proc })
if ::File.exists?(dest_path) && !yield(self, dest_path)
raise ::Zip::ZipDestinationFileExistsError,
raise ::Zip::DestinationFileExistsError,
"Destination '#{dest_path}' already exists"
end
::File.open(dest_path, "wb") do |os|
Expand All @@ -589,7 +592,7 @@ def create_directory(dest_path)
if block_given? && yield(self, dest_path)
::FileUtils::rm_f dest_path
else
raise ::Zip::ZipDestinationFileExistsError,
raise ::Zip::DestinationFileExistsError,
"Cannot create directory '#{dest_path}'. "+
"A file already exists with that name"
end
Expand All @@ -614,12 +617,12 @@ def create_symlink(dest_path)
if ::File.readlink(dest_path) == linkto
return
else
raise ZipDestinationFileExistsError,
raise ::Zip::DestinationFileExistsError,
"Cannot create symlink '#{dest_path}'. "+
"A symlink already exists with that name"
end
else
raise ZipDestinationFileExistsError,
raise ::Zip::DestinationFileExistsError,
"Cannot create symlink '#{dest_path}'. "+
"A file already exists with that name"
end
Expand All @@ -642,6 +645,7 @@ def parse_zip64_extra(for_local_header) #:nodoc:all

# create a zip64 extra information field if we need one
def prep_zip64_extra(for_local_header) #:nodoc:all
return unless ::Zip.write_zip64_support
need_zip64 = @size >= 0xFFFFFFFF || @compressed_size >= 0xFFFFFFFF
unless for_local_header
need_zip64 ||= @local_header_offset >= 0xFFFFFFFF
Expand Down
12 changes: 6 additions & 6 deletions lib/zip/errors.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module Zip
class ZipError < StandardError; end
class ZipEntryExistsError < ZipError; end
class ZipDestinationFileExistsError < ZipError; end
class ZipCompressionMethodError < ZipError; end
class ZipEntryNameError < ZipError; end
class ZipInternalError < ZipError; end
class Error < StandardError; end
class EntryExistsError < Error; end
class DestinationFileExistsError < Error; end
class CompressionMethodError < Error; end
class EntryNameError < Error; end
class InternalError < Error; end
end
2 changes: 1 addition & 1 deletion lib/zip/extra_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def merge(binstr)

def create(name)
unless field_class = ID_MAP.values.find { |k| k.name == name }
raise ZipError, "Unknown extra field '#{name}'"
raise Error, "Unknown extra field '#{name}'"
end
self[name] = field_class.new
end
Expand Down
Loading

0 comments on commit ec81c30

Please sign in to comment.