ffi-libarchive 0.2.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +3 -3
- data/LICENSE +201 -674
- data/README.md +69 -4
- data/Rakefile +26 -9
- data/VERSION +1 -0
- data/ffi-libarchive.gemspec +13 -13
- data/lib/ffi-libarchive.rb +10 -11
- data/lib/ffi-libarchive/archive.rb +94 -43
- data/lib/ffi-libarchive/entry.rb +148 -156
- data/lib/ffi-libarchive/reader.rb +31 -34
- data/lib/ffi-libarchive/stat.rb +14 -14
- data/lib/ffi-libarchive/version.rb +1 -1
- data/lib/ffi-libarchive/writer.rb +27 -34
- data/test/sets/ts_read.rb +91 -93
- data/test/sets/ts_write.rb +93 -93
- data/test/test_ffi-libarchive.rb +4 -4
- metadata +22 -18
- data/.gitattributes +0 -6
- data/.gitignore +0 -55
- data/.rubocop.yml +0 -41
- data/.yardopts +0 -5
data/README.md
CHANGED
@@ -3,10 +3,75 @@ ffi-libarchive
|
|
3
3
|
A Ruby FFI binding to [libarchive][0].
|
4
4
|
|
5
5
|
This library provides Ruby FFI bindings to the well-known
|
6
|
-
[libarchive library][0].
|
7
|
-
to libarchive-ruby.
|
6
|
+
[libarchive library][0].
|
8
7
|
|
9
|
-
##
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Ensure that you have libarchive installed. On Debian/Ubuntu:
|
11
|
+
|
12
|
+
```sh
|
13
|
+
apt install libarchive13
|
14
|
+
```
|
15
|
+
|
16
|
+
On macOS with Homebrew:
|
17
|
+
```sh
|
18
|
+
brew install libarchive
|
19
|
+
```
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem 'ffi-libarchive'
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
```shell
|
30
|
+
$ bundle
|
31
|
+
```
|
32
|
+
|
33
|
+
Or install it yourself as:
|
34
|
+
|
35
|
+
```shell
|
36
|
+
$ gem install ffi-libarchive
|
37
|
+
```
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
To extract an archive into the current directory:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
flags = Archive::EXTRACT_PERM
|
45
|
+
reader = Archive::Reader.open_filename('/path/to/archive.tgz')
|
46
|
+
|
47
|
+
reader.each_entry do |entry|
|
48
|
+
reader.extract(entry, flags.to_i)
|
49
|
+
end
|
50
|
+
reader.close
|
51
|
+
```
|
52
|
+
|
53
|
+
To create a gzipped tar archive:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
Archive.write_open_filename('my.tgz', Archive::COMPRESSION_GZIP, Archive::FORMAT_TAR_PAX_RESTRICTED) do |tar|
|
57
|
+
content = File.read 'some_path'
|
58
|
+
size = content.size
|
59
|
+
tar.new_entry do |e|
|
60
|
+
e.pathname = 'some_path'
|
61
|
+
e.size = size
|
62
|
+
e.filetype = Archive::Entry::FILE
|
63
|
+
tar.write_header e
|
64
|
+
tar.write_data content
|
65
|
+
end
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
## Contributing
|
70
|
+
|
71
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/chef/ffi-libarchive>. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Community Guidelines](https://docs.chef.io/community_guidelines.html) code of conduct.
|
72
|
+
|
73
|
+
## License
|
74
|
+
|
75
|
+
The gem is available as open source under the terms of the Apache License, v2
|
10
76
|
|
11
77
|
[0]: https://github.com/libarchive/libarchive
|
12
|
-
[1]: https://github.com/Hanmac/libarchive-ruby
|
data/Rakefile
CHANGED
@@ -1,11 +1,28 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "bundler/gem_tasks"
|
5
|
+
require "chefstyle"
|
6
|
+
require "rubocop/rake_task"
|
7
|
+
require "rake/testtask"
|
8
|
+
|
9
|
+
namespace :style do
|
10
|
+
desc "Run Ruby style checks"
|
11
|
+
RuboCop::RakeTask.new(:ruby)
|
12
|
+
end
|
13
|
+
|
14
|
+
Rake::TestTask.new(:test) do |t|
|
15
|
+
t.libs << "test"
|
16
|
+
t.libs << "lib"
|
17
|
+
t.test_files = FileList["test/test_ffi-libarchive.rb"]
|
9
18
|
end
|
10
19
|
|
11
|
-
|
20
|
+
desc "Run all style checks"
|
21
|
+
task style: ["style:ruby"]
|
22
|
+
|
23
|
+
desc "Run style & unit tests on Travis"
|
24
|
+
task travis: %w{style test}
|
25
|
+
|
26
|
+
# Default
|
27
|
+
desc "Run style, unit"
|
28
|
+
task default: %w{style test}
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.4.1
|
data/ffi-libarchive.gemspec
CHANGED
@@ -1,25 +1,25 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "ffi-libarchive/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
7
|
+
s.name = "ffi-libarchive"
|
8
8
|
s.version = Archive::VERSION
|
9
|
-
s.authors = [
|
9
|
+
s.authors = ["John Bellone", "Jamie Winsor", "Frank Fischer"]
|
10
10
|
s.email = %w{jbellone@bloomberg.net jamie@vialstudios.com frank-fischer@shadow-soft.de}
|
11
|
-
s.description =
|
11
|
+
s.description = "A Ruby FFI binding to libarchive."
|
12
12
|
s.summary = s.description
|
13
|
-
s.homepage =
|
14
|
-
s.license =
|
13
|
+
s.homepage = "https://github.com/chef/ffi-libarchive"
|
14
|
+
s.license = "Apache-2.0"
|
15
15
|
|
16
|
-
s.files =
|
17
|
-
s.test_files = s.files.grep(%r{^(test)/})
|
16
|
+
s.files = %w{ Gemfile Rakefile README.md LICENSE VERSION } + Dir.glob("{lib,test}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) } + Dir.glob("*.gemspec")
|
18
17
|
s.require_paths = %w{lib}
|
19
|
-
s.required_ruby_version =
|
18
|
+
s.required_ruby_version = ">= 2.4.0"
|
20
19
|
|
21
|
-
s.add_dependency
|
20
|
+
s.add_dependency "ffi", "~> 1.0"
|
22
21
|
|
23
|
-
s.add_development_dependency
|
24
|
-
s.add_development_dependency
|
22
|
+
s.add_development_dependency "bundler"
|
23
|
+
s.add_development_dependency "rake"
|
24
|
+
s.add_development_dependency "test-unit"
|
25
25
|
end
|
data/lib/ffi-libarchive.rb
CHANGED
@@ -8,8 +8,8 @@ module Archive
|
|
8
8
|
# they will be joined to the end of the libray path using
|
9
9
|
# <tt>File.join</tt>.
|
10
10
|
#
|
11
|
-
def self.libpath(
|
12
|
-
rv =
|
11
|
+
def self.libpath(*args)
|
12
|
+
rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
13
13
|
if block_given?
|
14
14
|
begin
|
15
15
|
$LOAD_PATH.unshift LIBPATH
|
@@ -18,14 +18,14 @@ module Archive
|
|
18
18
|
$LOAD_PATH.shift
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
rv
|
22
22
|
end
|
23
23
|
|
24
24
|
# Returns the lpath for the module. If any arguments are given,
|
25
25
|
# they will be joined to the end of the path using
|
26
26
|
# <tt>File.join</tt>.
|
27
27
|
#
|
28
|
-
def self.path(
|
28
|
+
def self.path(*args)
|
29
29
|
rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
30
30
|
if block_given?
|
31
31
|
begin
|
@@ -35,7 +35,7 @@ module Archive
|
|
35
35
|
$LOAD_PATH.shift
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
rv
|
39
39
|
end
|
40
40
|
|
41
41
|
# Utility method used to require all files ending in .rb that lie in the
|
@@ -43,15 +43,14 @@ module Archive
|
|
43
43
|
# in. Optionally, a specific _directory_ name can be passed in such that
|
44
44
|
# the _filename_ does not have to be equivalent to the directory.
|
45
45
|
#
|
46
|
-
def self.require_all_libs_relative_to(
|
47
|
-
dir ||= ::File.basename(fname,
|
46
|
+
def self.require_all_libs_relative_to(fname, dir = nil)
|
47
|
+
dir ||= ::File.basename(fname, ".*")
|
48
48
|
search_me = ::File.expand_path(
|
49
|
-
|
49
|
+
::File.join(::File.dirname(fname), dir, "**", "*.rb"))
|
50
50
|
|
51
|
-
Dir.glob(search_me).sort.each {|rb| require rb}
|
51
|
+
Dir.glob(search_me).sort.each { |rb| require rb }
|
52
52
|
end
|
53
|
-
|
54
|
-
end # module Archive
|
53
|
+
end # module Archive
|
55
54
|
|
56
55
|
require File.join(Archive::LIBPATH, "ffi-libarchive", "archive")
|
57
56
|
require File.join(Archive::LIBPATH, "ffi-libarchive", "reader")
|
@@ -1,15 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require "ffi"
|
2
2
|
|
3
3
|
module Archive
|
4
|
-
|
5
4
|
module C
|
6
|
-
def self.attach_function_maybe
|
5
|
+
def self.attach_function_maybe(*args)
|
7
6
|
attach_function(*args)
|
8
|
-
rescue FFI::NotFoundError
|
7
|
+
rescue FFI::NotFoundError # rubocop:disable Lint/HandleExceptions
|
9
8
|
end
|
10
9
|
|
11
10
|
extend FFI::Library
|
12
|
-
ffi_lib
|
11
|
+
ffi_lib %w{libarchive.so.13 libarchive.13 libarchive.so libarchive archive}
|
13
12
|
|
14
13
|
attach_function :archive_version_number, [], :int
|
15
14
|
attach_function :archive_version_string, [], :string
|
@@ -21,8 +20,49 @@ module Archive
|
|
21
20
|
attach_function :archive_read_open_memory, [:pointer, :pointer, :size_t], :int
|
22
21
|
attach_function :archive_read_support_compression_program, [:pointer, :string], :int
|
23
22
|
attach_function :archive_read_support_compression_all, [:pointer], :int
|
24
|
-
|
25
|
-
|
23
|
+
|
24
|
+
attach_function_maybe :archive_read_set_format, [:pointer, :int], :int
|
25
|
+
attach_function_maybe :archive_read_append_filter, [:pointer, :int], :int
|
26
|
+
attach_function_maybe :archive_read_append_filter_program, [:pointer, :pointer], :int
|
27
|
+
attach_function_maybe :archive_read_append_filter_program_signature, [:pointer, :string, :pointer, :size_t], :int
|
28
|
+
|
29
|
+
attach_function_maybe :archive_read_support_filter_all, [:pointer], :int
|
30
|
+
attach_function_maybe :archive_read_support_filter_bzip2, [:pointer], :int
|
31
|
+
attach_function_maybe :archive_read_support_filter_compress, [:pointer], :int
|
32
|
+
attach_function_maybe :archive_read_support_filter_gzip, [:pointer], :int
|
33
|
+
attach_function_maybe :archive_read_support_filter_grzip, [:pointer], :int
|
34
|
+
attach_function_maybe :archive_read_support_filter_lrzip, [:pointer], :int
|
35
|
+
attach_function_maybe :archive_read_support_filter_lz4, [:pointer], :int
|
36
|
+
attach_function_maybe :archive_read_support_filter_lzip, [:pointer], :int
|
37
|
+
attach_function_maybe :archive_read_support_filter_lzma, [:pointer], :int
|
38
|
+
attach_function_maybe :archive_read_support_filter_lzop, [:pointer], :int
|
39
|
+
attach_function_maybe :archive_read_support_filter_none, [:pointer], :int
|
40
|
+
attach_function_maybe :archive_read_support_filter_program, [:pointer], :int
|
41
|
+
attach_function_maybe :archive_read_support_filter_program_signature, [:pointer], :int
|
42
|
+
attach_function_maybe :archive_read_support_filter_rpm, [:pointer], :int
|
43
|
+
attach_function_maybe :archive_read_support_filter_uu, [:pointer], :int
|
44
|
+
attach_function_maybe :archive_read_support_filter_xz, [:pointer], :int
|
45
|
+
|
46
|
+
attach_function_maybe :archive_read_support_format_all, [:pointer], :int
|
47
|
+
attach_function_maybe :archive_read_support_format_7zip, [:pointer], :int
|
48
|
+
attach_function_maybe :archive_read_support_format_ar, [:pointer], :int
|
49
|
+
attach_function_maybe :archive_read_support_format_by_code, [:pointer], :int
|
50
|
+
attach_function_maybe :archive_read_support_format_cab, [:pointer], :int
|
51
|
+
attach_function_maybe :archive_read_support_format_cpio, [:pointer], :int
|
52
|
+
attach_function_maybe :archive_read_support_format_empty, [:pointer], :int
|
53
|
+
attach_function_maybe :archive_read_support_format_gnutar, [:pointer], :int
|
54
|
+
attach_function_maybe :archive_read_support_format_iso9660, [:pointer], :int
|
55
|
+
attach_function_maybe :archive_read_support_format_lha, [:pointer], :int
|
56
|
+
attach_function_maybe :archive_read_support_format_mtree, [:pointer], :int
|
57
|
+
attach_function_maybe :archive_read_support_format_rar, [:pointer], :int
|
58
|
+
attach_function_maybe :archive_read_support_format_raw, [:pointer], :int
|
59
|
+
attach_function_maybe :archive_read_support_format_tar, [:pointer], :int
|
60
|
+
attach_function_maybe :archive_read_support_format_warc, [:pointer], :int
|
61
|
+
attach_function_maybe :archive_read_support_format_xar, [:pointer], :int
|
62
|
+
attach_function_maybe :archive_read_support_format_zip, [:pointer], :int
|
63
|
+
attach_function_maybe :archive_read_support_format_zip_streamable, [:pointer], :int
|
64
|
+
attach_function_maybe :archive_read_support_format_zip_seekable, [:pointer], :int
|
65
|
+
|
26
66
|
attach_function :archive_read_finish, [:pointer], :int
|
27
67
|
attach_function :archive_read_extract, [:pointer, :pointer, :int], :int
|
28
68
|
attach_function :archive_read_header_position, [:pointer], :int
|
@@ -35,13 +75,11 @@ module Archive
|
|
35
75
|
callback :archive_open_callback, [:pointer, :pointer], :int
|
36
76
|
callback :archive_write_callback, [:pointer, :pointer, :pointer, :size_t], :int
|
37
77
|
callback :archive_close_callback, [:pointer, :pointer], :int
|
38
|
-
# TODO: the following function is the real definition but uses multiple callbacks. This implies that it will not work with Rubinius (currently), but luckily we only need the write-callback actually.
|
39
|
-
#attach_function :archive_write_open, [:pointer, :pointer, :archive_open_callback, :archive_write_callback, :archive_close_callback], :int
|
40
78
|
attach_function :archive_write_open, [:pointer, :pointer, :pointer, :archive_write_callback, :pointer], :int
|
41
|
-
# TODO: catch errors if not defined
|
42
79
|
attach_function :archive_write_set_compression_none, [:pointer], :int
|
43
80
|
attach_function_maybe :archive_write_set_compression_gzip, [:pointer], :int
|
44
81
|
attach_function_maybe :archive_write_set_compression_bzip2, [:pointer], :int
|
82
|
+
attach_function_maybe :archive_write_set_compression_deflate, [:pointer], :int
|
45
83
|
attach_function_maybe :archive_write_set_compression_compress, [:pointer], :int
|
46
84
|
attach_function_maybe :archive_write_set_compression_lzma, [:pointer], :int
|
47
85
|
attach_function_maybe :archive_write_set_compression_xz, [:pointer], :int
|
@@ -159,10 +197,10 @@ module Archive
|
|
159
197
|
|
160
198
|
EOF = 1
|
161
199
|
OK = 0
|
162
|
-
RETRY =
|
163
|
-
WARN =
|
164
|
-
FAILED =
|
165
|
-
FATAL =
|
200
|
+
RETRY = -10
|
201
|
+
WARN = -20
|
202
|
+
FAILED = -25
|
203
|
+
FATAL = -30
|
166
204
|
|
167
205
|
DATA_BUFFER_SIZE = 2**16
|
168
206
|
end
|
@@ -176,6 +214,11 @@ module Archive
|
|
176
214
|
COMPRESSION_XZ = 6
|
177
215
|
COMPRESSION_UU = 7
|
178
216
|
COMPRESSION_RPM = 8
|
217
|
+
COMPRESSION_LZIP = 9
|
218
|
+
COMPRESSION_LRZIP = 10
|
219
|
+
COMPRESSION_LZOP = 11
|
220
|
+
COMPRESSION_GRZIP = 12
|
221
|
+
COMPRESSION_LZ4 = 13
|
179
222
|
|
180
223
|
FORMAT_BASE_MASK = 0xff0000
|
181
224
|
FORMAT_CPIO = 0x10000
|
@@ -202,58 +245,67 @@ module Archive
|
|
202
245
|
FORMAT_MTREE = 0x80000
|
203
246
|
FORMAT_RAW = 0x90000
|
204
247
|
FORMAT_XAR = 0xA0000
|
248
|
+
FORMAT_LHA = 0xB0000
|
249
|
+
FORMAT_CAB = 0xC0000
|
250
|
+
FORMAT_RAR = 0xD0000
|
251
|
+
FORMAT_7ZIP = 0xE0000
|
252
|
+
FORMAT_WARC = 0xF0000
|
205
253
|
|
206
|
-
EXTRACT_OWNER =
|
207
|
-
EXTRACT_PERM =
|
208
|
-
EXTRACT_TIME =
|
209
|
-
EXTRACT_NO_OVERWRITE =
|
210
|
-
EXTRACT_UNLINK =
|
211
|
-
EXTRACT_ACL =
|
212
|
-
EXTRACT_FFLAGS =
|
213
|
-
EXTRACT_XATTR =
|
214
|
-
EXTRACT_SECURE_SYMLINKS =
|
215
|
-
EXTRACT_SECURE_NODOTDOT =
|
216
|
-
EXTRACT_NO_AUTODIR =
|
217
|
-
EXTRACT_NO_OVERWRITE_NEWER =
|
218
|
-
EXTRACT_SPARSE =
|
254
|
+
EXTRACT_OWNER = 0x0001
|
255
|
+
EXTRACT_PERM = 0x0002
|
256
|
+
EXTRACT_TIME = 0x0004
|
257
|
+
EXTRACT_NO_OVERWRITE = 0x0008
|
258
|
+
EXTRACT_UNLINK = 0x0010
|
259
|
+
EXTRACT_ACL = 0x0020
|
260
|
+
EXTRACT_FFLAGS = 0x0040
|
261
|
+
EXTRACT_XATTR = 0x0080
|
262
|
+
EXTRACT_SECURE_SYMLINKS = 0x0100
|
263
|
+
EXTRACT_SECURE_NODOTDOT = 0x0200
|
264
|
+
EXTRACT_NO_AUTODIR = 0x0400
|
265
|
+
EXTRACT_NO_OVERWRITE_NEWER = 0x0800
|
266
|
+
EXTRACT_SPARSE = 0x1000
|
267
|
+
EXTRACT_MAC_METADATA = 0x2000
|
268
|
+
EXTRACT_NO_HFS_COMPRESSION = 0x4000
|
269
|
+
EXTRACT_HFS_COMPRESSION_FORCED = 0x8000
|
270
|
+
EXTRACT_SECURE_NOABSOLUTEPATHS = 0x10000
|
271
|
+
EXTRACT_CLEAR_NOCHANGE_FFLAGS = 0x20000
|
219
272
|
|
220
|
-
def self.read_open_filename
|
273
|
+
def self.read_open_filename(file_name, command = nil, &block)
|
221
274
|
Reader.open_filename file_name, command, &block
|
222
275
|
end
|
223
276
|
|
224
|
-
def self.read_open_memory
|
277
|
+
def self.read_open_memory(string, command = nil, &block)
|
225
278
|
Reader.open_memory string, command, &block
|
226
279
|
end
|
227
280
|
|
228
|
-
def self.write_open_filename
|
281
|
+
def self.write_open_filename(file_name, compression, format, &block)
|
229
282
|
Writer.open_filename file_name, compression, format, &block
|
230
283
|
end
|
231
284
|
|
232
|
-
def self.write_open_memory
|
285
|
+
def self.write_open_memory(string, compression, format, &block)
|
233
286
|
Writer.open_memory string, compression, format, &block
|
234
287
|
end
|
235
288
|
|
236
289
|
def self.version_number
|
237
|
-
C
|
290
|
+
C.archive_version_number
|
238
291
|
end
|
239
292
|
|
240
293
|
def self.version_string
|
241
|
-
C
|
294
|
+
C.archive_version_string
|
242
295
|
end
|
243
296
|
|
244
297
|
class Error < StandardError
|
245
298
|
def initialize(archive)
|
246
|
-
if archive.
|
299
|
+
if archive.is_a? String
|
247
300
|
super archive
|
248
301
|
else
|
249
|
-
super
|
302
|
+
super C.archive_error_string(archive).to_s
|
250
303
|
end
|
251
304
|
end
|
252
305
|
end
|
253
306
|
|
254
307
|
class BaseArchive
|
255
|
-
|
256
|
-
def initialize alloc, free
|
308
|
+
def initialize(alloc, free)
|
257
309
|
@archive = nil
|
258
310
|
@archive_free = nil
|
259
311
|
@archive = alloc.call
|
@@ -261,11 +313,11 @@ module Archive
|
|
261
313
|
raise Error, @archive unless @archive
|
262
314
|
|
263
315
|
@archive_free[0] = free
|
264
|
-
ObjectSpace.define_finalizer(
|
316
|
+
ObjectSpace.define_finalizer(self, BaseArchive.finalizer(@archive, @archive_free))
|
265
317
|
end
|
266
318
|
|
267
|
-
def self.finalizer
|
268
|
-
|
319
|
+
def self.finalizer(archive, archive_free)
|
320
|
+
proc do |*_args|
|
269
321
|
archive_free[0].call(archive) if archive_free[0]
|
270
322
|
end
|
271
323
|
end
|
@@ -289,12 +341,11 @@ module Archive
|
|
289
341
|
protected :archive
|
290
342
|
|
291
343
|
def error_string
|
292
|
-
C
|
344
|
+
C.archive_error_string(@archive)
|
293
345
|
end
|
294
346
|
|
295
347
|
def errno
|
296
|
-
C
|
348
|
+
C.archive_errno(@archive)
|
297
349
|
end
|
298
350
|
end
|
299
|
-
|
300
351
|
end
|