ffi-libarchive 0.1.0
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/History.txt +4 -0
- data/README.md +70 -0
- data/Rakefile +18 -0
- data/bin/ffi-libarchive-ruby +7 -0
- data/lib/ffi-libarchive.rb +60 -0
- data/lib/ffi-libarchive/archive.rb +306 -0
- data/lib/ffi-libarchive/entry.rb +482 -0
- data/lib/ffi-libarchive/reader.rb +131 -0
- data/lib/ffi-libarchive/stat.rb +31 -0
- data/lib/ffi-libarchive/writer.rb +143 -0
- data/test/data/test.tar.gz +0 -0
- data/test/sets/ts_read.rb +119 -0
- data/test/sets/ts_write.rb +133 -0
- data/test/test_ffi-libarchive.rb +8 -0
- data/version.txt +1 -0
- metadata +91 -0
@@ -0,0 +1,482 @@
|
|
1
|
+
module Archive
|
2
|
+
|
3
|
+
class Entry
|
4
|
+
|
5
|
+
S_IFMT = 0170000
|
6
|
+
S_IFSOCK = 0140000 # socket
|
7
|
+
S_IFLNK = 0120000 # symbolic link
|
8
|
+
S_IFREG = 0100000 # regular file
|
9
|
+
S_IFBLK = 0060000 # block device
|
10
|
+
S_IFDIR = 0040000 # directory
|
11
|
+
S_IFCHR = 0020000 # character device
|
12
|
+
S_IFIFO = 0010000 # FIFO
|
13
|
+
|
14
|
+
SOCKET = 0140000 # socket
|
15
|
+
SYMBOLIC_LINK = 0120000 # symbolic link
|
16
|
+
FILE = 0100000 # regular file
|
17
|
+
BLOCK_SPECIAL = 0060000 # block device
|
18
|
+
DIRECTORY = 0040000 # directory
|
19
|
+
CHARACTER_SPECIAL = 0020000 # character device
|
20
|
+
FIFO = 0010000 # FIFO
|
21
|
+
|
22
|
+
def self.from_pointer entry
|
23
|
+
new entry
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize entry = nil
|
27
|
+
@entry_free = [true]
|
28
|
+
if entry
|
29
|
+
@entry = entry
|
30
|
+
yield self if block_given?
|
31
|
+
else
|
32
|
+
@entry = C::archive_entry_new
|
33
|
+
raise Error, @entry unless @entry
|
34
|
+
|
35
|
+
if block_given?
|
36
|
+
result = yield self
|
37
|
+
C::archive_entry_free(@entry)
|
38
|
+
@entry = nil
|
39
|
+
return result
|
40
|
+
else
|
41
|
+
@entry_free[0] = false
|
42
|
+
ObjectSpace.define_finalizer( self, Entry.finalizer(@entry, @entry_free) )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.finalizer entry, entry_free
|
48
|
+
Proc.new do |*args|
|
49
|
+
unless entry_free[0]
|
50
|
+
C::archive_entry_free(entry)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def close
|
56
|
+
# TODO: do we need synchronization here?
|
57
|
+
if @entry and !@entry_free[0]
|
58
|
+
@entry_free[0] = true
|
59
|
+
C::archive_entry_free(@entry)
|
60
|
+
end
|
61
|
+
ensure
|
62
|
+
@entry = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def entry
|
66
|
+
raise "No entry object" unless @entry
|
67
|
+
@entry
|
68
|
+
end
|
69
|
+
|
70
|
+
def atime
|
71
|
+
Time.at C::archive_entry_atime(entry)
|
72
|
+
end
|
73
|
+
|
74
|
+
def atime= time
|
75
|
+
set_atime time, 0
|
76
|
+
end
|
77
|
+
|
78
|
+
def set_atime time, nsec
|
79
|
+
C::archive_entry_set_atime(entry, time.to_i, nsec)
|
80
|
+
end
|
81
|
+
|
82
|
+
def atime_is_set?
|
83
|
+
C::archive_entry_atime_is_set(entry) != 0
|
84
|
+
end
|
85
|
+
|
86
|
+
def atime_nsec
|
87
|
+
C::archive_entry_atime_nsec(entry)
|
88
|
+
end
|
89
|
+
|
90
|
+
def birthtime
|
91
|
+
Time.at C::archive_entry_birthtime(entry)
|
92
|
+
end
|
93
|
+
|
94
|
+
def birthtime= time
|
95
|
+
set_birthtime time, 0
|
96
|
+
end
|
97
|
+
|
98
|
+
def set_birthtime time, nsec
|
99
|
+
C::archive_entry_set_birthtime(entry, time.to_i, nsec)
|
100
|
+
end
|
101
|
+
|
102
|
+
def birthtime_is_set?
|
103
|
+
C::archive_entry_birthtime_is_set(entry) != 0
|
104
|
+
end
|
105
|
+
|
106
|
+
def birthtime_nsec
|
107
|
+
C::archive_entry_birthtime_nsec(entry)
|
108
|
+
end
|
109
|
+
|
110
|
+
def ctime
|
111
|
+
Time.at C::archive_entry_ctime(entry)
|
112
|
+
end
|
113
|
+
|
114
|
+
def ctime= time
|
115
|
+
set_ctime time, 0
|
116
|
+
end
|
117
|
+
|
118
|
+
def set_ctime time, nsec
|
119
|
+
C::archive_entry_set_ctime(entry, time.to_i, nsec)
|
120
|
+
end
|
121
|
+
|
122
|
+
def ctime_is_set?
|
123
|
+
C::archive_entry_ctime_is_set(entry) != 0
|
124
|
+
end
|
125
|
+
|
126
|
+
def ctime_nsec
|
127
|
+
C::archive_entry_ctime_nsec(entry)
|
128
|
+
end
|
129
|
+
|
130
|
+
def block_special?
|
131
|
+
C::archive_entry_filetype(entry) & S_IFMT == S_IFBLK
|
132
|
+
end
|
133
|
+
|
134
|
+
def character_special?
|
135
|
+
C::archive_entry_filetype(entry) & S_IFMT == S_IFCHR
|
136
|
+
end
|
137
|
+
|
138
|
+
def directory?
|
139
|
+
C::archive_entry_filetype(entry) & S_IFMT == S_IFDIR
|
140
|
+
end
|
141
|
+
|
142
|
+
def fifo?
|
143
|
+
C::archive_entry_filetype(entry) & S_IFMT == S_IFIFO
|
144
|
+
end
|
145
|
+
|
146
|
+
def regular?
|
147
|
+
C::archive_entry_filetype(entry) & S_IFMT == S_IFREG
|
148
|
+
end
|
149
|
+
alias :file? :regular?
|
150
|
+
|
151
|
+
def socket?
|
152
|
+
C::archive_entry_filetype(entry) & S_IFMT == S_IFSOCK
|
153
|
+
end
|
154
|
+
|
155
|
+
def symbolic_link?
|
156
|
+
C::archive_entry_filetype(entry) & S_IFMT == S_IFLNK
|
157
|
+
end
|
158
|
+
|
159
|
+
def copy_fflags_text fflags_text
|
160
|
+
C::archive_entry_copy_fflags_text(entry, fflags_text)
|
161
|
+
nil
|
162
|
+
end
|
163
|
+
|
164
|
+
def copy_gname gname
|
165
|
+
C::archive_entry_copy_gname(entry, gname)
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
|
169
|
+
def copy_hardlink lnk
|
170
|
+
C::archive_entry_copy_hardlink(entry, lnk)
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
|
174
|
+
def copy_link lnk
|
175
|
+
C::archive_entry_copy_link(entry, lnk)
|
176
|
+
nil
|
177
|
+
end
|
178
|
+
|
179
|
+
def copy_lstat filename
|
180
|
+
# TODO get this work without ffi-inliner
|
181
|
+
begin
|
182
|
+
require File.join(File.dirname(__FILE__), 'stat.rb')
|
183
|
+
rescue => e
|
184
|
+
raise "ffi-inliner build for copy_stat failed:\n#{e}"
|
185
|
+
end
|
186
|
+
|
187
|
+
stat = Archive::Stat::ffi_libarchive_create_lstat(filename)
|
188
|
+
raise Error, "Copy stat failed: #{LibC::strerror(LibC::errno)}" if stat.null?
|
189
|
+
result = C::archive_entry_copy_stat(entry, stat)
|
190
|
+
ensure
|
191
|
+
Archive::Stat::ffi_libarchive_free_stat(stat)
|
192
|
+
end
|
193
|
+
|
194
|
+
def copy_pathname file_name
|
195
|
+
C::archive_entry_copy_pathname(entry, file_name)
|
196
|
+
nil
|
197
|
+
end
|
198
|
+
|
199
|
+
def copy_sourcepath path
|
200
|
+
C::archive_copy_sourcepath(entry, path)
|
201
|
+
nil
|
202
|
+
end
|
203
|
+
|
204
|
+
def copy_stat filename
|
205
|
+
# TODO get this work without ffi-inliner
|
206
|
+
begin
|
207
|
+
require File.join(File.dirname(__FILE__), 'stat.rb')
|
208
|
+
rescue => e
|
209
|
+
raise "ffi-inliner build for copy_stat failed:\n#{e}"
|
210
|
+
end
|
211
|
+
|
212
|
+
stat = Archive::Stat::ffi_libarchive_create_stat(filename)
|
213
|
+
raise Error, "Copy stat failed: #{LibC::strerror(LibC::errno)}" if stat.null?
|
214
|
+
result = C::archive_entry_copy_stat(entry, stat)
|
215
|
+
ensure
|
216
|
+
Archive::Stat::ffi_libarchive_free_stat(stat)
|
217
|
+
end
|
218
|
+
|
219
|
+
def copy_symlink slnk
|
220
|
+
C::archive_copy_symlink(entry, slnk)
|
221
|
+
nil
|
222
|
+
end
|
223
|
+
|
224
|
+
def copy_uname uname
|
225
|
+
C::archive_copy_uname(entry, uname)
|
226
|
+
nil
|
227
|
+
end
|
228
|
+
|
229
|
+
def dev
|
230
|
+
C::archive_entry_dev(entry)
|
231
|
+
end
|
232
|
+
|
233
|
+
def dev= dev
|
234
|
+
C::archive_entry_set_dev(entry, dev)
|
235
|
+
end
|
236
|
+
|
237
|
+
def devmajor
|
238
|
+
C::archive_entry_devmajor(entry)
|
239
|
+
end
|
240
|
+
|
241
|
+
def devmajor= dev
|
242
|
+
C::archive_entry_set_devmajor(entry, dev)
|
243
|
+
end
|
244
|
+
|
245
|
+
def devminor
|
246
|
+
C::archive_entry_devminor(entry)
|
247
|
+
end
|
248
|
+
|
249
|
+
def devminor= dev
|
250
|
+
C::archive_entry_set_devminor(entry, dev)
|
251
|
+
end
|
252
|
+
|
253
|
+
def fflags
|
254
|
+
set = FFI::MemoryPointer.new :long
|
255
|
+
clear = FFI::MemoryPointer.new :long
|
256
|
+
C::archive_entry_fflags(entry, set, clear)
|
257
|
+
[set.get_long(0), clear.get_long(0)]
|
258
|
+
end
|
259
|
+
|
260
|
+
def fflags_text
|
261
|
+
C::archive_entry_fflags_text(entry)
|
262
|
+
end
|
263
|
+
|
264
|
+
def filetype
|
265
|
+
C::archive_entry_filetype(entry)
|
266
|
+
end
|
267
|
+
|
268
|
+
def filetype= type
|
269
|
+
if type.kind_of? Symbol
|
270
|
+
type = Entry.const_get type.to_s.upcase.intern
|
271
|
+
end
|
272
|
+
C::archive_entry_set_filetype(entry, type)
|
273
|
+
end
|
274
|
+
|
275
|
+
def gid
|
276
|
+
C::archive_entry_gid(entry)
|
277
|
+
end
|
278
|
+
|
279
|
+
def gid= gid
|
280
|
+
C::archive_entry_set_gid(entry, gid)
|
281
|
+
end
|
282
|
+
|
283
|
+
def gname
|
284
|
+
C::archive_entry_gname(entry)
|
285
|
+
end
|
286
|
+
|
287
|
+
def gname= gname
|
288
|
+
C::archive_entry_set_gname(entry, gname)
|
289
|
+
end
|
290
|
+
|
291
|
+
def hardlink
|
292
|
+
C::archive_entry_hardlink(entry)
|
293
|
+
end
|
294
|
+
|
295
|
+
def hardlink= lnk
|
296
|
+
C::archive_entry_set_hardlink(entry, lnk)
|
297
|
+
end
|
298
|
+
|
299
|
+
def ino
|
300
|
+
C::archive_entry_ino(entry)
|
301
|
+
end
|
302
|
+
|
303
|
+
def ino= ino
|
304
|
+
C::archive_entry_set_ino(entry, ino)
|
305
|
+
end
|
306
|
+
|
307
|
+
def link= lnk
|
308
|
+
C::archive_entry_set_link(entry, lnk)
|
309
|
+
end
|
310
|
+
|
311
|
+
def mode
|
312
|
+
C::archive_entry_mode(entry)
|
313
|
+
end
|
314
|
+
|
315
|
+
def mode= mode
|
316
|
+
C::archive_entry_set_mode(entry, mode)
|
317
|
+
end
|
318
|
+
|
319
|
+
def mtime
|
320
|
+
Time.at C::archive_entry_mtime(entry)
|
321
|
+
end
|
322
|
+
|
323
|
+
def mtime= time
|
324
|
+
set_mtime time, 0
|
325
|
+
end
|
326
|
+
|
327
|
+
def set_mtime time, nsec
|
328
|
+
C::archive_entry_set_mtime(entry, time.to_i, nsec)
|
329
|
+
end
|
330
|
+
|
331
|
+
def mtime_is_set?
|
332
|
+
C::archive_entry_mtime_is_set(entry) != 0
|
333
|
+
end
|
334
|
+
|
335
|
+
def mtime_nsec
|
336
|
+
C::archive_entry_mtime_nsec(entry)
|
337
|
+
end
|
338
|
+
|
339
|
+
def nlink
|
340
|
+
C::archive_entry_nlink(entry)
|
341
|
+
end
|
342
|
+
|
343
|
+
def nlink= nlink
|
344
|
+
C::archive_entry_set_nlink(entry, nlink)
|
345
|
+
end
|
346
|
+
|
347
|
+
def pathname
|
348
|
+
C::archive_entry_pathname(entry)
|
349
|
+
end
|
350
|
+
|
351
|
+
def pathname= path
|
352
|
+
C::archive_entry_set_pathname(entry, path)
|
353
|
+
end
|
354
|
+
|
355
|
+
def perm= perm
|
356
|
+
C::archive_entry_set_perm(entry, perm)
|
357
|
+
end
|
358
|
+
|
359
|
+
def rdev
|
360
|
+
C::archive_entry_rdev(entry)
|
361
|
+
end
|
362
|
+
|
363
|
+
def rdev= dev
|
364
|
+
C::archive_entry_set_rdev(entry, dev)
|
365
|
+
end
|
366
|
+
|
367
|
+
def rdevmajor
|
368
|
+
C::archive_entry_rdevmajor(entry)
|
369
|
+
end
|
370
|
+
|
371
|
+
def rdevmajor= dev
|
372
|
+
C::archive_entry_set_rdevmajor(entry, dev)
|
373
|
+
end
|
374
|
+
|
375
|
+
def rdevminor
|
376
|
+
C::archive_entry_rdevminor(entry)
|
377
|
+
end
|
378
|
+
|
379
|
+
def rdevminor= dev
|
380
|
+
C::archive_entry_set_rdevminor(entry, dev)
|
381
|
+
end
|
382
|
+
|
383
|
+
def set_fflags set, clear
|
384
|
+
C::archive_entry_set_fflags(entry, set, clear)
|
385
|
+
end
|
386
|
+
|
387
|
+
def size
|
388
|
+
C::archive_entry_size(entry)
|
389
|
+
end
|
390
|
+
|
391
|
+
def size= size
|
392
|
+
C::archive_entry_set_size(entry, size)
|
393
|
+
end
|
394
|
+
|
395
|
+
def size_is_set?
|
396
|
+
C::archive_entry_size_is_set(entry) != 0
|
397
|
+
end
|
398
|
+
|
399
|
+
def sourcepath
|
400
|
+
C::archive_entry_sourcepath(entry)
|
401
|
+
end
|
402
|
+
|
403
|
+
def strmode
|
404
|
+
C::archive_entry_strmode(entry)
|
405
|
+
end
|
406
|
+
|
407
|
+
def symlink
|
408
|
+
C::archive_entry_symlink(entry)
|
409
|
+
end
|
410
|
+
|
411
|
+
def symlink= slnk
|
412
|
+
C::archive_entry_set_symlink(entry, slnk)
|
413
|
+
end
|
414
|
+
|
415
|
+
def uid
|
416
|
+
C::archive_entry_uid(entry)
|
417
|
+
end
|
418
|
+
|
419
|
+
def uid= uid
|
420
|
+
C::archive_entry_set_uid(entry, uid)
|
421
|
+
end
|
422
|
+
|
423
|
+
def uname
|
424
|
+
C::archive_entry_uname(entry)
|
425
|
+
end
|
426
|
+
|
427
|
+
def uname= uname
|
428
|
+
C::archive_entry_set_uname(entry, uname)
|
429
|
+
end
|
430
|
+
|
431
|
+
def unset_atime
|
432
|
+
C::archive_entry_unset_atime(entry)
|
433
|
+
end
|
434
|
+
|
435
|
+
def unset_birthtime
|
436
|
+
C::archive_entry_unset_birthtime(entry)
|
437
|
+
end
|
438
|
+
|
439
|
+
def unset_ctime
|
440
|
+
C::archive_entry_unset_ctime(entry)
|
441
|
+
end
|
442
|
+
|
443
|
+
def unset_mtime
|
444
|
+
C::archive_entry_unset_mtime(entry)
|
445
|
+
end
|
446
|
+
|
447
|
+
def unset_size
|
448
|
+
C::archive_entry_unset_size(entry)
|
449
|
+
end
|
450
|
+
|
451
|
+
def xattr_add_entry name, value
|
452
|
+
C::archive_entry_xattr_add_entry(entry, name, value, value.size)
|
453
|
+
end
|
454
|
+
|
455
|
+
def xattr_clear
|
456
|
+
C::archive_entry_xattr_clear(entry)
|
457
|
+
end
|
458
|
+
|
459
|
+
def xattr_count
|
460
|
+
C::archive_entry_xattr_count(entry)
|
461
|
+
end
|
462
|
+
|
463
|
+
def xattr_next
|
464
|
+
name = FFI::MemoryPointer.new :pointer
|
465
|
+
value = FFI::MemoryPointer.new :pointer
|
466
|
+
size = FFI::MemoryPointer.new :size_t
|
467
|
+
if C::archive_entry_xattr_next(entry, name, value, size) != C::OK
|
468
|
+
return nil
|
469
|
+
else
|
470
|
+
# TODO: someday size.read_size_t could work
|
471
|
+
return [name.null? ? nil : name.read_string,
|
472
|
+
value.null? ? nil : value.get_string(0,size.read_ulong)]
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
def xattr_reset
|
477
|
+
C::archive_entry_xattr_reset(entry)
|
478
|
+
end
|
479
|
+
|
480
|
+
end
|
481
|
+
|
482
|
+
end
|