class Zip::Entry
Zip::Entry represents an entry in a Zip archive.
Constants
- DEFLATED
-
Constant used to specify that the entry is deflated (i.e., compressed).
- STORED
-
Constant used to specify that the entry is stored (i.e., not compressed).
Attributes
Public Class Methods
Source
# File lib/zip/entry.rb, line 76 def initialize( zipfile = '', name = '', comment: '', size: nil, compressed_size: 0, crc: 0, compression_method: DEFLATED, compression_level: ::Zip.default_compression, time: ::Zip::DOSTime.now, extra: ::Zip::ExtraField.new ) super() @name = name check_name(@name) set_default_vars_values @fstype = ::Zip::RUNNING_ON_WINDOWS ? ::Zip::FSTYPE_FAT : ::Zip::FSTYPE_UNIX @zipfile = zipfile @comment = comment || '' @compression_method = compression_method || DEFLATED @compression_level = compression_level || ::Zip.default_compression @compressed_size = compressed_size || 0 @crc = crc || 0 @size = size @time = case time when ::Zip::DOSTime time when Time ::Zip::DOSTime.from_time(time) else ::Zip::DOSTime.now end @extra = extra.kind_of?(ExtraField) ? extra : ExtraField.new(extra.to_s) set_compression_level_flags end
Create a new Zip::Entry.
Public Instance Methods
Source
# File lib/zip/entry.rb, line 181 def absolute_time? @extra.member?(:universaltime) || @extra.member?(:ntfs) end
Does this entry return time fields with accurate timezone information?
Source
# File lib/zip/entry.rb, line 207 def aes? !@extra[:aes].nil? end
Is this entry encrypted with AES encryption?
Source
# File lib/zip/entry.rb, line 144 def atime time(component: :atime) end
Get the last access time of this entry, if available.
Source
# File lib/zip/entry.rb, line 171 def atime=(value) send(:time=, value, component: :atime) end
Set the last access time of this entry.
Source
# File lib/zip/entry.rb, line 189 def compression_method return STORED if ftype == :directory || @compression_level == 0 @compression_method end
Return the compression method for this entry.
Returns STORED if the entry is a directory or if the compression level is 0.
Source
# File lib/zip/entry.rb, line 196 def compression_method=(method) @dirty = true @compression_method = (ftype == :directory ? STORED : method) end
Set the compression method for this entry.
Source
# File lib/zip/entry.rb, line 149 def ctime time(component: :ctime) end
Get the creation time of this entry, if available.
Source
# File lib/zip/entry.rb, line 176 def ctime=(value) send(:time=, value, component: :ctime) end
Set the creation time of this entry.
Source
# File lib/zip/entry.rb, line 112 def encrypted? gp_flags & 1 == 1 end
Is this entry encrypted?
Source
# File lib/zip/entry.rb, line 289 def extract(entry_path = @name, destination_directory: '.', &block) dest_dir = ::File.absolute_path(destination_directory || '.') extract_path = ::File.absolute_path(::File.join(dest_dir, entry_path)) unless extract_path.start_with?(dest_dir) warn "WARNING: skipped extracting '#{@name}' to '#{extract_path}' as unsafe." return self end block ||= proc { ::Zip.on_exists_proc } raise "unknown file type #{inspect}" unless directory? || file? || symlink? __send__(:"create_#{ftype}", extract_path, &block) self end
Extracts this entry to a file at ‘entry_path`, with `destination_directory` as the base location in the filesystem.
NB: The caller is responsible for making sure ‘destination_directory` is safe, if it is passed.
Source
# File lib/zip/entry.rb, line 642 def get_input_stream(&block) if ftype == :directory yield ::Zip::NullInputStream if block ::Zip::NullInputStream elsif @filepath case ftype when :file ::File.open(@filepath, 'rb', &block) when :symlink linkpath = ::File.readlink(@filepath) stringio = ::StringIO.new(linkpath) yield(stringio) if block stringio else raise "unknown @file_type #{ftype}" end else zis = ::Zip::InputStream.new(@zipfile, offset: local_header_offset) zis.instance_variable_set(:@complete_entry, self) zis.get_next_entry if block begin yield(zis) ensure zis.close end else zis end end end
Returns an IO like object for the given ZipEntry. Warning: may behave weird with symlinks.
Source
# File lib/zip/entry.rb, line 121 def size @size || 0 end
The uncompressed size of the entry.
Source
# File lib/zip/entry.rb, line 128 def time(component: :mtime) time = if @extra[:universaltime] @extra[:universaltime].send(component) elsif @extra[:ntfs] @extra[:ntfs].send(component) end # Standard time field in central directory has local time # under archive creator. Then, we can't get timezone. time || (@time if component == :mtime) end
Get a timestamp component of this entry.
Returns modification time by default.
Source
# File lib/zip/entry.rb, line 156 def time=(value, component: :mtime) @dirty = true unless @extra.member?(:universaltime) || @extra.member?(:ntfs) @extra.create(:universaltime) end value = DOSTime.from_time(value) comp = "#{component}=" unless component.to_s.end_with?('=') (@extra[:universaltime] || @extra[:ntfs]).send(comp, value) @time = value if component == :mtime end
Set a timestamp component of this entry.
Sets modification time by default.
Source
# File lib/zip/entry.rb, line 202 def zip64? !@extra[:zip64].nil? end
Does this entry use the ZIP64 extensions?
Private Instance Methods
Source
# File lib/zip/entry.rb, line 779 def create_directory(dest_path) return if ::File.directory?(dest_path) if ::File.exist?(dest_path) raise ::Zip::DestinationExistsError, dest_path unless block_given? && yield(self, dest_path) ::FileUtils.rm_f dest_path end ::FileUtils.mkdir_p(dest_path) set_extra_attributes_on_path(dest_path) end
Source
# File lib/zip/entry.rb, line 752 def create_file(dest_path, _continue_on_exists_proc = proc { Zip.continue_on_exists_proc }) if ::File.exist?(dest_path) && !yield(self, dest_path) raise ::Zip::DestinationExistsError, dest_path end ::File.open(dest_path, 'wb') do |os| get_input_stream do |is| bytes_written = 0 warned = false buf = +'' while (buf = is.sysread(::Zip::Decompressor::CHUNK_SIZE, buf)) os << buf bytes_written += buf.bytesize next unless bytes_written > size && !warned error = ::Zip::EntrySizeError.new(self) raise error if ::Zip.validate_entry_sizes warn "WARNING: #{error.message}" warned = true end end end set_extra_attributes_on_path(dest_path) end
Source
# File lib/zip/entry.rb, line 793 def create_symlink(dest_path) # TODO: Symlinks pose security challenges. Symlink support temporarily # removed in view of https://github.com/rubyzip/rubyzip/issues/369 . warn "WARNING: skipped symlink '#{dest_path}'." end
BUG: create_symlink() does not use &block
Source
# File lib/zip/entry.rb, line 865 def prep_cdir_zip64_extra return unless ::Zip.write_zip64_support if (@size && @size >= 0xFFFFFFFF) || @compressed_size >= 0xFFFFFFFF || @local_header_offset >= 0xFFFFFFFF @version_needed_to_extract = VERSION_NEEDED_TO_EXTRACT_ZIP64 zip64 = @extra[:zip64] || @extra.create(:zip64) # Central directory entry entries include whichever fields are necessary. zip64.original_size = @size if @size && @size >= 0xFFFFFFFF zip64.compressed_size = @compressed_size if @compressed_size >= 0xFFFFFFFF zip64.relative_header_offset = @local_header_offset if @local_header_offset >= 0xFFFFFFFF end end
Source
# File lib/zip/entry.rb, line 849 def prep_local_zip64_extra return unless ::Zip.write_zip64_support return if (!zip64? && @size && @size < 0xFFFFFFFF) || !file? # Might not know size here, so need ZIP64 just in case. # If we already have a ZIP64 extra (placeholder) then we must fill it in. if zip64? || @size.nil? || @size >= 0xFFFFFFFF || @compressed_size >= 0xFFFFFFFF @version_needed_to_extract = VERSION_NEEDED_TO_EXTRACT_ZIP64 zip64 = @extra[:zip64] || @extra.create(:zip64) # Local header always includes size and compressed size. zip64.original_size = @size || 0 zip64.compressed_size = @compressed_size end end
rubocop:disable Style/GuardClause
Source
# File lib/zip/entry.rb, line 835 def set_compression_level_flags return unless compression_method == DEFLATED case @compression_level when 1 @gp_flags |= COMPRESSION_LEVEL_SUPERFAST_GPFLAG when 2 @gp_flags |= COMPRESSION_LEVEL_FAST_GPFLAG when 8, 9 @gp_flags |= COMPRESSION_LEVEL_MAX_GPFLAG end end
For DEFLATED compression only: set the general purpose flags 1 and 2 to indicate compression level. This seems to be mainly cosmetic but they are generally set by other tools - including in docx files. It is these flags that are used by commandline tools (and elsewhere) to give an indication of how compressed a file is. See the PKWARE APPNOTE for more information: pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
It’s safe to simply OR these flags here as compression_level is read only.
Source
# File lib/zip/entry.rb, line 746 def set_time(binary_dos_date, binary_dos_time) @time = ::Zip::DOSTime.parse_binary_dos_format(binary_dos_date, binary_dos_time) rescue ArgumentError warn 'WARNING: invalid date/time in zip entry.' if ::Zip.warn_invalid_date end