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

comment[RW]
compressed_size[RW]
name[RW]
restore_ownership[RW]
restore_permissions[RW]
restore_times[RW]
unix_gid[RW]
unix_perms[RW]
unix_uid[RW]

Public Class Methods

new( 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 ) click to toggle source

Create a new Zip::Entry.

Calls superclass method
# 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

Public Instance Methods

absolute_time?() click to toggle source

Does this entry return time fields with accurate timezone information?

# File lib/zip/entry.rb, line 181
def absolute_time?
  @extra.member?(:universaltime) || @extra.member?(:ntfs)
end
aes?() click to toggle source

Is this entry encrypted with AES encryption?

# File lib/zip/entry.rb, line 207
def aes?
  !@extra[:aes].nil?
end
atime() click to toggle source

Get the last access time of this entry, if available.

# File lib/zip/entry.rb, line 144
def atime
  time(component: :atime)
end
atime=(value) click to toggle source

Set the last access time of this entry.

# File lib/zip/entry.rb, line 171
def atime=(value)
  send(:time=, value, component: :atime)
end
compression_method() click to toggle source

Return the compression method for this entry.

Returns STORED if the entry is a directory or if the compression level is 0.

# File lib/zip/entry.rb, line 189
def compression_method
  return STORED if ftype == :directory || @compression_level == 0

  @compression_method
end
compression_method=(method) click to toggle source

Set the compression method for this entry.

# File lib/zip/entry.rb, line 196
def compression_method=(method)
  @dirty = true
  @compression_method = (ftype == :directory ? STORED : method)
end
ctime() click to toggle source

Get the creation time of this entry, if available.

# File lib/zip/entry.rb, line 149
def ctime
  time(component: :ctime)
end
ctime=(value) click to toggle source

Set the creation time of this entry.

# File lib/zip/entry.rb, line 176
def ctime=(value)
  send(:time=, value, component: :ctime)
end
encrypted?() click to toggle source

Is this entry encrypted?

# File lib/zip/entry.rb, line 112
def encrypted?
  gp_flags & 1 == 1
end
extract(entry_path = @name, destination_directory: '.', &block) click to toggle source

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.

# 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 + ::File::SEPARATOR) || dest_dir == ::File::SEPARATOR
    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
get_input_stream() { |NullInputStream| ... } click to toggle source

Returns an IO like object for the given ZipEntry. Warning: may behave weird with symlinks.

# 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
mtime(component: :mtime)
Alias for: time
mtime=(value, component: :mtime)
Alias for: time=
size() click to toggle source

The uncompressed size of the entry.

# File lib/zip/entry.rb, line 121
def size
  @size || 0
end
time(component: :mtime) click to toggle source

Get a timestamp component of this entry.

Returns modification time by default.

# 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
Also aliased as: mtime
time=(value, component: :mtime) click to toggle source

Set a timestamp component of this entry.

Sets modification time by default.

# 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
Also aliased as: mtime=
zip64?() click to toggle source

Does this entry use the ZIP64 extensions?

# File lib/zip/entry.rb, line 202
def zip64?
  !@extra[:zip64].nil?
end

Private Instance Methods

create_directory(dest_path) { |self, dest_path| ... } click to toggle source
# File lib/zip/entry.rb, line 778
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
create_file(dest_path, _continue_on_exists_proc = proc { Zip.continue_on_exists_proc }) { |self, dest_path| ... } click to toggle 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 DestinationExistsError, dest_path
  end

  ::File.open(dest_path, 'wb') do |os|
    get_input_stream do |is|
      bytes_written = 0
      warned = false
      while (buf = is.sysread(Decompressor::CHUNK_SIZE))
        os << buf
        bytes_written += buf.bytesize
        next unless bytes_written > size && !warned

        error = 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
prep_cdir_zip64_extra() click to toggle source
# File lib/zip/entry.rb, line 864
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
prep_local_zip64_extra() click to toggle source

rubocop:disable Style/GuardClause

# File lib/zip/entry.rb, line 848
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
set_compression_level_flags() click to toggle source

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.

# File lib/zip/entry.rb, line 834
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
set_time(binary_dos_date, binary_dos_time) click to toggle 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