ffi-libarchive 0.2.0 → 0.4.1
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.
- 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
|