fastlib 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +1 -1
- data/lib/fastlib.rb +132 -38
- metadata +4 -4
data/README.markdown
CHANGED
@@ -8,7 +8,7 @@ This is similar to capabilities like zip/ziprequire, except that it provides wor
|
|
8
8
|
|
9
9
|
$ apt-get install fastlib
|
10
10
|
|
11
|
-
$ \`gem env gemdir\`/gems/fastlib
|
11
|
+
$ \`gem env gemdir\`/gems/fastlib-\*/lib/fastlib.rb dump lib/myarchive.fastlib lib/ lib/\*
|
12
12
|
|
13
13
|
$ ruby -r rubygems -r fastlib -I lib/myarchive.fastlib application.rb
|
14
14
|
|
data/lib/fastlib.rb
CHANGED
@@ -20,6 +20,7 @@
|
|
20
20
|
|
21
21
|
require "find"
|
22
22
|
|
23
|
+
|
23
24
|
#
|
24
25
|
# Copyright (C) 2011 Rapid7. You can redistribute it and/or
|
25
26
|
# modify it under the terms of the ruby license.
|
@@ -98,9 +99,22 @@ end
|
|
98
99
|
#
|
99
100
|
class FastLib
|
100
101
|
|
101
|
-
VERSION = "0.0.
|
102
|
+
VERSION = "0.0.5"
|
102
103
|
|
104
|
+
FLAG_COMPRESS = 0x01
|
105
|
+
FLAG_ENCRYPT = 0x02
|
106
|
+
|
103
107
|
@@cache = {}
|
108
|
+
@@has_zlib = false
|
109
|
+
|
110
|
+
#
|
111
|
+
# Load zlib support if possible
|
112
|
+
#
|
113
|
+
begin
|
114
|
+
require 'zlib'
|
115
|
+
@@has_zlib = true
|
116
|
+
rescue ::LoadError
|
117
|
+
end
|
104
118
|
|
105
119
|
#
|
106
120
|
# This method returns the version of the fastlib library
|
@@ -128,7 +142,7 @@ class FastLib
|
|
128
142
|
@@cache[lib][:fastlib_header][1] +
|
129
143
|
@@cache[lib][name][0]
|
130
144
|
)
|
131
|
-
data =
|
145
|
+
data = fastlib_filter_decode( @@cache[lib][:fastlib_flags], fd.read(@@cache[lib][name][1] ))
|
132
146
|
end
|
133
147
|
|
134
148
|
# Return the contents in raw or processed form
|
@@ -140,50 +154,102 @@ class FastLib
|
|
140
154
|
#
|
141
155
|
def self.load_cache(lib)
|
142
156
|
return if @@cache[lib]
|
143
|
-
|
157
|
+
@@cache[lib] = {}
|
158
|
+
|
159
|
+
return if not ::File.exists?(lib)
|
160
|
+
|
144
161
|
::File.open(lib, 'rb') do |fd|
|
162
|
+
dict = {}
|
145
163
|
head = fd.read(4)
|
146
164
|
return if head != "FAST"
|
147
165
|
hlen = fd.read(4).unpack("N")[0]
|
148
|
-
|
166
|
+
flag = fd.read(4).unpack("N")[0]
|
167
|
+
|
168
|
+
@@cache[lib][:fastlib_header] = [12, hlen, fd.stat.mtime.utc.to_i ]
|
169
|
+
@@cache[lib][:fastlib_flags] = flag
|
149
170
|
|
150
|
-
nlen, doff, dlen = fd.read(
|
171
|
+
nlen, doff, dlen, tims = fd.read(16).unpack("N*")
|
151
172
|
|
152
173
|
while nlen > 0
|
153
|
-
name =
|
154
|
-
dict[name] = [doff, dlen]
|
174
|
+
name = fastlib_filter_decode( lib, fd.read(nlen) )
|
175
|
+
dict[name] = [doff, dlen, tims]
|
155
176
|
|
156
|
-
nlen, doff, dlen = fd.read(
|
177
|
+
nlen, doff, dlen, tims = fd.read(16).unpack("N*")
|
157
178
|
end
|
158
|
-
|
179
|
+
|
180
|
+
@@cache[lib].merge!(dict)
|
159
181
|
end
|
182
|
+
|
160
183
|
end
|
161
184
|
|
162
185
|
#
|
163
|
-
# This method provides
|
164
|
-
#
|
165
|
-
# used to provide encryption or compression.
|
186
|
+
# This method provides compression and encryption capabilities
|
187
|
+
# for the fastlib archive format.
|
166
188
|
#
|
167
|
-
def self.
|
168
|
-
|
189
|
+
def self.fastlib_filter_decode(lib, buff)
|
190
|
+
|
191
|
+
if (@@cache[lib][:fastlib_flags] & FLAG_ENCRYPT) != 0
|
192
|
+
|
193
|
+
@@cache[lib][:fastlib_decrypt] ||= ::Proc.new do |data|
|
194
|
+
stub = "decrypt_%.8x" % ( @@cache[lib][:fastlib_flags] & 0xfffffff0 )
|
195
|
+
FastLib.send(stub, data)
|
196
|
+
end
|
197
|
+
|
198
|
+
buff = @@cache[lib][:fastlib_decrypt].call( buff )
|
199
|
+
end
|
200
|
+
|
201
|
+
if (@@cache[lib][:fastlib_flags] & FLAG_COMPRESS) != 0
|
202
|
+
if not @@has_zlib
|
203
|
+
raise ::RuntimeError, "zlib is required to open this archive"
|
204
|
+
end
|
205
|
+
|
206
|
+
z = Zlib::Inflate.new
|
207
|
+
buff = z.inflate(buff)
|
208
|
+
buff << z.finish
|
209
|
+
z.close
|
210
|
+
end
|
211
|
+
|
212
|
+
buff
|
169
213
|
end
|
170
214
|
|
171
215
|
#
|
172
|
-
# This method provides
|
173
|
-
#
|
174
|
-
#
|
175
|
-
|
176
|
-
|
177
|
-
|
216
|
+
# This method provides compression and encryption capabilities
|
217
|
+
# for the fastlib archive format.
|
218
|
+
#
|
219
|
+
def self.fastlib_filter_encode(lib, buff)
|
220
|
+
|
221
|
+
if (@@cache[lib][:fastlib_flags] & FLAG_COMPRESS) != 0
|
222
|
+
if not @@has_zlib
|
223
|
+
raise ::RuntimeError, "zlib is required to open this archive"
|
224
|
+
end
|
225
|
+
|
226
|
+
z = Zlib::Deflate.new
|
227
|
+
buff = z.deflate(buff)
|
228
|
+
buff << z.finish
|
229
|
+
z.close
|
230
|
+
end
|
231
|
+
|
232
|
+
if (@@cache[lib][:fastlib_flags] & FLAG_ENCRYPT) != 0
|
233
|
+
|
234
|
+
@@cache[lib][:fastlib_encrypt] ||= ::Proc.new do |data|
|
235
|
+
stub = "encrypt_%.8x" % ( @@cache[lib][:fastlib_flags] & 0xfffffff0 )
|
236
|
+
FastLib.send(stub, data)
|
237
|
+
end
|
238
|
+
|
239
|
+
buff = @@cache[lib][:fastlib_encrypt].call( buff )
|
240
|
+
end
|
241
|
+
|
242
|
+
buff
|
178
243
|
end
|
179
244
|
|
245
|
+
|
180
246
|
#
|
181
247
|
# This method provides a way to create a FASTLIB archive programatically,
|
182
248
|
# the key arguments are the name of the destination archive, the base
|
183
249
|
# directory that should be excluded from the archived path, and finally
|
184
250
|
# the list of specific files and directories to include in the archive.
|
185
251
|
#
|
186
|
-
def self.dump(lib, bdir, *dirs)
|
252
|
+
def self.dump(lib, flag, bdir, *dirs)
|
187
253
|
head = ""
|
188
254
|
data = ""
|
189
255
|
hidx = 0
|
@@ -192,20 +258,26 @@ class FastLib
|
|
192
258
|
bdir = bdir.gsub(/\/$/, '')
|
193
259
|
brex = /^#{Regexp.escape(bdir)}\//
|
194
260
|
|
261
|
+
@@cache[lib] = {
|
262
|
+
:fastlib_flags => flag.to_i(16)
|
263
|
+
}
|
264
|
+
|
195
265
|
dirs.each do |dir|
|
196
266
|
::Find.find(dir).each do |path|
|
197
267
|
next if not ::File.file?(path)
|
198
|
-
name =
|
268
|
+
name = fastlib_filter_encode( lib, path.sub( brex, "" ) )
|
269
|
+
|
199
270
|
buff = ""
|
200
271
|
::File.open(path, "rb") do |fd|
|
201
|
-
buff = fd.read(fd.stat.size)
|
272
|
+
buff = fastlib_filter_encode(lib, fd.read(fd.stat.size))
|
202
273
|
end
|
203
|
-
|
204
|
-
|
274
|
+
|
275
|
+
|
276
|
+
head << [ name.length, didx, buff.length, ::File.stat(path).mtime.utc.to_i ].pack("NNNN")
|
205
277
|
head << name
|
206
|
-
hidx = hidx +
|
278
|
+
hidx = hidx + 16 + name.length
|
207
279
|
|
208
|
-
data <<
|
280
|
+
data << buff
|
209
281
|
didx = didx + buff.length
|
210
282
|
end
|
211
283
|
end
|
@@ -214,7 +286,7 @@ class FastLib
|
|
214
286
|
|
215
287
|
::File.open(lib, "wb") do |fd|
|
216
288
|
fd.write("FAST")
|
217
|
-
fd.write( [ head.length ].pack("
|
289
|
+
fd.write( [ head.length, flag.to_i(16) ].pack("NN") )
|
218
290
|
fd.write( head )
|
219
291
|
fd.write( data )
|
220
292
|
end
|
@@ -226,7 +298,7 @@ class FastLib
|
|
226
298
|
#
|
227
299
|
def self.list(lib)
|
228
300
|
load_cache(lib)
|
229
|
-
( @@cache[lib] || {} ).keys.map{|x| x.to_s }.sort
|
301
|
+
( @@cache[lib] || {} ).keys.map{|x| x.to_s }.sort.select{ |x| @@cache[lib][x] }
|
230
302
|
end
|
231
303
|
|
232
304
|
#
|
@@ -237,6 +309,24 @@ class FastLib
|
|
237
309
|
data.gsub('__FILE__', "'#{ ::File.expand_path(::File.join(::File.dirname(lib), name)) }'")
|
238
310
|
end
|
239
311
|
|
312
|
+
#
|
313
|
+
# This is a stub crypto handler that performs a basic XOR
|
314
|
+
# operation against a fixed one byte key
|
315
|
+
#
|
316
|
+
def self.encrypt_12345600(data)
|
317
|
+
data.unpack("C*").map{ |c| c ^ 0x90 }.pack("C*")
|
318
|
+
end
|
319
|
+
|
320
|
+
def self.decrypt_12345600(data)
|
321
|
+
encrypt_12345600(data)
|
322
|
+
end
|
323
|
+
|
324
|
+
def self.cache
|
325
|
+
@@cache
|
326
|
+
end
|
327
|
+
|
328
|
+
|
329
|
+
|
240
330
|
end
|
241
331
|
|
242
332
|
|
@@ -246,32 +336,35 @@ end
|
|
246
336
|
#
|
247
337
|
if __FILE__ == $0
|
248
338
|
cmd = ARGV.shift
|
249
|
-
unless ["
|
339
|
+
unless ["store", "list", "version"].include?(cmd)
|
250
340
|
$stderr.puts "Usage: #{$0} [dump|list|version] <arguments>"
|
251
341
|
exit(0)
|
252
342
|
end
|
253
343
|
|
254
344
|
case cmd
|
255
|
-
when "
|
345
|
+
when "store"
|
256
346
|
dst = ARGV.shift
|
347
|
+
flg = ARGV.shift
|
257
348
|
dir = ARGV.shift
|
258
349
|
src = ARGV
|
259
350
|
unless dst and dir and src.length > 0
|
260
|
-
$stderr.puts "Usage: #{$0}
|
351
|
+
$stderr.puts "Usage: #{$0} store destination.fastlib flags base_dir src1 src2 ... src99"
|
261
352
|
exit(0)
|
262
353
|
end
|
263
|
-
FastLib.dump(dst, dir, *src)
|
354
|
+
FastLib.dump(dst, flg, dir, *src)
|
264
355
|
|
265
356
|
when "list"
|
266
357
|
src = ARGV.shift
|
267
358
|
unless src
|
268
|
-
$stderr.puts "Usage: #{$0} list
|
359
|
+
$stderr.puts "Usage: #{$0} list"
|
269
360
|
exit(0)
|
270
361
|
end
|
271
362
|
$stdout.puts "Library: #{src}"
|
272
363
|
$stdout.puts "====================================================="
|
273
364
|
FastLib.list(src).each do |name|
|
274
|
-
|
365
|
+
fsize = FastLib.cache[src][name][1]
|
366
|
+
ftime = ::Time.at(FastLib.cache[src][name][2]).strftime("%Y-%m-%d %H:%M:%S")
|
367
|
+
$stdout.puts sprintf("%9d\t%20s\t%s\n", fsize, ftime, name)
|
275
368
|
end
|
276
369
|
$stdout.puts ""
|
277
370
|
|
@@ -289,10 +382,10 @@ end
|
|
289
382
|
|
290
383
|
* All integers are 32-bit and in network byte order (big endian / BE)
|
291
384
|
* The file signature is 0x46415354 (big endian, use htonl() if necessary)
|
292
|
-
* The header is always
|
293
|
-
* The data section is always
|
385
|
+
* The header is always 12 bytes into the archive (magic + header length)
|
386
|
+
* The data section is always 12 + header length into the archive
|
294
387
|
* The header entries always start with 'fastlib_header'
|
295
|
-
* The header entries always consist of
|
388
|
+
* The header entries always consist of 16 bytes + name length (no alignment)
|
296
389
|
* The header name data may be encoded, compressed, or transformed
|
297
390
|
* The data entries may be encoded, compressed, or transformed too
|
298
391
|
|
@@ -303,6 +396,7 @@ end
|
|
303
396
|
4 bytes: name length (0 = End of Names)
|
304
397
|
4 bytes: data offset
|
305
398
|
4 bytes: data length
|
399
|
+
4 bytes: timestamp
|
306
400
|
]
|
307
401
|
[ Raw Data ]
|
308
402
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 5
|
10
|
+
version: 0.0.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- HD Moore
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-11-
|
18
|
+
date: 2011-11-23 00:00:00 -06:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|