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.
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]. It aims to be interface compatiable
7
- to libarchive-ruby.
6
+ [libarchive library][0].
8
7
 
9
- ## Why this instead of libarchive-ruby?
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
- require 'bundler/gem_tasks'
2
-
3
- require 'rspec/core/rake_task'
4
- RSpec::Core::RakeTask.new do |t|
5
- t.rspec_opts = [
6
- '--color',
7
- '--format progress',
8
- ].join(' ')
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
- task default: :spec
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
@@ -1,25 +1,25 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
2
+ lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'ffi-libarchive/version'
4
+ require "ffi-libarchive/version"
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = 'ffi-libarchive'
7
+ s.name = "ffi-libarchive"
8
8
  s.version = Archive::VERSION
9
- s.authors = ['John Bellone', 'Jamie Winsor', 'Frank Fischer']
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 = 'A Ruby FFI binding to libarchive.'
11
+ s.description = "A Ruby FFI binding to libarchive."
12
12
  s.summary = s.description
13
- s.homepage = 'https://github.com/johnbellone/ffi-libarchive'
14
- s.license = 'GPL 3.0'
13
+ s.homepage = "https://github.com/chef/ffi-libarchive"
14
+ s.license = "Apache-2.0"
15
15
 
16
- s.files = `git ls-files`.split($/)
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 = '>= 1.9'
18
+ s.required_ruby_version = ">= 2.4.0"
20
19
 
21
- s.add_dependency 'ffi', '~> 1.0'
20
+ s.add_dependency "ffi", "~> 1.0"
22
21
 
23
- s.add_development_dependency 'bundler'
24
- s.add_development_dependency 'rake'
22
+ s.add_development_dependency "bundler"
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "test-unit"
25
25
  end
@@ -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( *args )
12
- rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
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
- return rv
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( *args )
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
- return rv
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( fname, dir = nil )
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
- ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
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 'ffi'
1
+ require "ffi"
2
2
 
3
3
  module Archive
4
-
5
4
  module C
6
- def self.attach_function_maybe *args
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 ["archive", "libarchive.so.2"]
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
- attach_function :archive_read_support_format_all, [:pointer], :int
25
- # TODO: this function has been renamed to :archive_read_free in libarchive 3.0
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 = (-10)
163
- WARN = (-20)
164
- FAILED = (-25)
165
- FATAL = (-30)
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 = (0x0001)
207
- EXTRACT_PERM = (0x0002)
208
- EXTRACT_TIME = (0x0004)
209
- EXTRACT_NO_OVERWRITE = (0x0008)
210
- EXTRACT_UNLINK = (0x0010)
211
- EXTRACT_ACL = (0x0020)
212
- EXTRACT_FFLAGS = (0x0040)
213
- EXTRACT_XATTR = (0x0080)
214
- EXTRACT_SECURE_SYMLINKS = (0x0100)
215
- EXTRACT_SECURE_NODOTDOT = (0x0200)
216
- EXTRACT_NO_AUTODIR = (0x0400)
217
- EXTRACT_NO_OVERWRITE_NEWER = (0x0800)
218
- EXTRACT_SPARSE = (0x1000)
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 file_name, command = nil, &block
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 string, command = nil, &block
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 file_name, compression, format, &block
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 string, compression, format, &block
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::archive_version_number
290
+ C.archive_version_number
238
291
  end
239
292
 
240
293
  def self.version_string
241
- C::archive_version_string
294
+ C.archive_version_string
242
295
  end
243
296
 
244
297
  class Error < StandardError
245
298
  def initialize(archive)
246
- if archive.kind_of? String
299
+ if archive.is_a? String
247
300
  super archive
248
301
  else
249
- super "#{C::archive_error_string(archive)}"
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( self, BaseArchive.finalizer(@archive, @archive_free) )
316
+ ObjectSpace.define_finalizer(self, BaseArchive.finalizer(@archive, @archive_free))
265
317
  end
266
318
 
267
- def self.finalizer archive, archive_free
268
- Proc.new do |*args|
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::archive_error_string(@archive)
344
+ C.archive_error_string(@archive)
293
345
  end
294
346
 
295
347
  def errno
296
- C::archive_errno(@archive)
348
+ C.archive_errno(@archive)
297
349
  end
298
350
  end
299
-
300
351
  end