metasploit-framework/lib/rex/zip/archive.rb

131 lines
2.7 KiB
Ruby

# -*- coding: binary -*-
module Rex
module Zip
#
# This represents an entire archive.
#
class Archive
# An array of the Entry objects stored in this Archive.
attr_reader :entries
def initialize(compmeth=CM_DEFLATE)
@compmeth = compmeth
@entries = []
end
#
# Recursively adds a directory of files into the archive.
#
def add_r(dir)
path = File.dirname(dir)
Dir[File.join(dir, "**", "**")].each do |file|
relative = file.sub(/^#{path.chomp('/')}\//, '')
if File.directory?(file)
@entries << Entry.new(relative.chomp('/') + '/', '', @compmeth, nil, EFA_ISDIR, nil, nil)
else
contents = File.read(file, :mode => 'rb')
@entries << Entry.new(relative, contents, @compmeth, nil, nil, nil, nil)
end
end
end
#
# Create a new Entry and add it to the archive.
#
# If fdata is set, the file is populated with that data
# from the calling method. If fdata is nil, then the
# fs is checked for the file. If central_dir_name is set
# it will be used to spoof the name at the Central Directory
# at packing time.
#
def add_file(fname, fdata=nil, xtra=nil, comment=nil, central_dir_name=nil)
if (not fdata)
begin
st = File.stat(fname)
rescue
return nil
end
ts = st.mtime
if (st.directory?)
attrs = EFA_ISDIR
fdata = ''
unless fname[-1,1] == '/'
fname += '/'
end
else
f = File.open(fname, 'rb')
fdata = f.read(f.stat.size)
f.close
end
end
@entries << Entry.new(fname, fdata, @compmeth, ts, attrs, xtra, comment, central_dir_name)
end
def set_comment(comment)
@comment = comment
end
#
# Write the compressed file to +fname+.
#
def save_to(fname)
f = File.open(fname, 'wb')
f.write(pack)
f.close
end
#
# Compress this archive and return the resulting zip file as a String.
#
def pack
ret = ''
# save the offests
offsets = []
# file 1 .. file n
@entries.each { |ent|
offsets << ret.length
ret << ent.pack
}
# archive decryption header (unsupported)
# archive extra data record (unsupported)
# central directory
cfd_offset = ret.length
idx = 0
@entries.each { |ent|
cfd = CentralDir.new(ent, offsets[idx])
ret << cfd.pack
idx += 1
}
# zip64 end of central dir record (unsupported)
# zip64 end of central dir locator (unsupported)
# end of central directory record
cur_offset = ret.length - cfd_offset
ret << CentralDirEnd.new(@entries.length, cur_offset, cfd_offset, @comment).pack
ret
end
def inspect
"#<#{self.class} entries = [#{@entries.map{|e| e.name}.join(",")}]>"
end
end
end
end