2012-06-29 05:18:28 +00:00
|
|
|
# -*- coding: binary -*-
|
2010-02-10 17:27:40 +00:00
|
|
|
|
|
|
|
module Rex
|
|
|
|
module Zip
|
|
|
|
|
|
|
|
#
|
|
|
|
# This represents an entire archive.
|
|
|
|
#
|
|
|
|
class Archive
|
2011-05-25 16:45:20 +00:00
|
|
|
|
2013-08-30 21:28:33 +00:00
|
|
|
# An array of the Entry objects stored in this Archive.
|
|
|
|
attr_reader :entries
|
|
|
|
|
|
|
|
|
|
|
|
def initialize(compmeth=CM_DEFLATE)
|
|
|
|
@compmeth = compmeth
|
|
|
|
@entries = []
|
|
|
|
end
|
|
|
|
|
2014-03-06 22:11:26 +00:00
|
|
|
#
|
|
|
|
# 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
|
2013-08-30 21:28:33 +00:00
|
|
|
|
|
|
|
#
|
|
|
|
# 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
|
2014-04-07 14:21:26 +00:00
|
|
|
# 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.
|
2013-08-30 21:28:33 +00:00
|
|
|
#
|
2014-04-07 14:21:26 +00:00
|
|
|
def add_file(fname, fdata=nil, xtra=nil, comment=nil, central_dir_name=nil)
|
2013-08-30 21:28:33 +00:00
|
|
|
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
|
|
|
|
|
2014-04-07 14:21:26 +00:00
|
|
|
@entries << Entry.new(fname, fdata, @compmeth, ts, attrs, xtra, comment, central_dir_name)
|
2013-08-30 21:28:33 +00:00
|
|
|
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
|
|
|
|
|
2014-04-07 13:50:33 +00:00
|
|
|
|
|
|
|
#
|
2013-08-30 21:28:33 +00:00
|
|
|
# Compress this archive and return the resulting zip file as a String.
|
|
|
|
#
|
2014-04-07 13:50:33 +00:00
|
|
|
def pack
|
2013-08-30 21:28:33 +00:00
|
|
|
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])
|
2014-04-07 13:50:33 +00:00
|
|
|
ret << cfd.pack
|
2013-08-30 21:28:33 +00:00
|
|
|
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
|
2010-11-10 23:04:01 +00:00
|
|
|
|
2010-02-10 17:27:40 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|