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 ADDED
@@ -0,0 +1,4 @@
1
+ == 0.1.0 / 2011-04-11
2
+
3
+ * 1 major enhancement
4
+ * Birthday!
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ ffi-libarchive
2
+ ==============
3
+
4
+ An ffi binding to libarchive.
5
+
6
+ This library provides ruby-bindings to the well-known
7
+ [libarchive](http://code.google.com/p/libarchive/) library. It should be interface-compatible to libarchive-ruby and libarchive-ruby-swig gems.
8
+
9
+ Why another binding? Because I often work on workstations without
10
+ development libraries of libarchive installed. An FFI-based gem allows
11
+ to use the library without the hassle of compiling native extensions.
12
+
13
+ Note that this is not completely true for this library. Two methods,
14
+ ``Entry::copy_stat`` and ``Entry::copy_lstat`` require a small native
15
+ extension through ``ffi-inliner``, though this does not require
16
+ development files of libarchive but only of libc.
17
+
18
+ Features
19
+ --------
20
+
21
+ * Compatible interface to libarchive-ruby Entry::copy_lstat and
22
+ * Entry::copy_stat require ffi-inliner because of the platform
23
+ dependence of stat() and lstat() functions of libc
24
+
25
+ Examples
26
+ --------
27
+
28
+ require 'ffi-libarchive'
29
+
30
+ Requirements
31
+ ------------
32
+
33
+ * ``ffi`` >= 1.0.0
34
+ * ``ffi-inliner`` for ``Entry::copy_lstat`` and ``Entry::copy_stat``
35
+
36
+ Install
37
+ -------
38
+
39
+ * gem install ffi-libarchive
40
+
41
+ Author
42
+ ------
43
+
44
+ Original author: Frank Fischer
45
+
46
+ License
47
+ -------
48
+
49
+ (The MIT License)
50
+
51
+ Copyright (c) 2011 Frank Fischer
52
+
53
+ Permission is hereby granted, free of charge, to any person obtaining
54
+ a copy of this software and associated documentation files (the
55
+ 'Software'), to deal in the Software without restriction, including
56
+ without limitation the rights to use, copy, modify, merge, publish,
57
+ distribute, sublicense, and/or sell copies of the Software, and to
58
+ permit persons to whom the Software is furnished to do so, subject to
59
+ the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be
62
+ included in all copies or substantial portions of the Software.
63
+
64
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
65
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
66
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
67
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
68
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
69
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
70
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+
2
+ begin
3
+ require 'bones'
4
+ rescue LoadError
5
+ abort '### Please install the "bones" gem ###'
6
+ end
7
+
8
+ task :default => 'test:run'
9
+ task 'gem:release' => 'test:run'
10
+
11
+ Bones {
12
+ name 'ffi-libarchive'
13
+ authors 'Frank Fischer'
14
+ email 'frank.fischer@mathematik.tu-chemnitz.de'
15
+ url 'http://darcsden.com/lyro/ffi-libarchive'
16
+ depend_on 'ffi', '~> 1.0.0'
17
+ }
18
+
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.expand_path(
4
+ File.join(File.dirname(__FILE__), %w[.. lib ffi-libarchive-ruby]))
5
+
6
+ # Put your code here
7
+
@@ -0,0 +1,60 @@
1
+
2
+ module Archive
3
+
4
+ # :stopdoc:
5
+ LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
6
+ PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
7
+ VERSION = ::File.read(PATH + 'version.txt').strip
8
+ # :startdoc:
9
+
10
+ # Returns the library path for the module. If any arguments are given,
11
+ # they will be joined to the end of the libray path using
12
+ # <tt>File.join</tt>.
13
+ #
14
+ def self.libpath( *args )
15
+ rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
16
+ if block_given?
17
+ begin
18
+ $LOAD_PATH.unshift LIBPATH
19
+ rv = yield
20
+ ensure
21
+ $LOAD_PATH.shift
22
+ end
23
+ end
24
+ return rv
25
+ end
26
+
27
+ # Returns the lpath for the module. If any arguments are given,
28
+ # they will be joined to the end of the path using
29
+ # <tt>File.join</tt>.
30
+ #
31
+ def self.path( *args )
32
+ rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
33
+ if block_given?
34
+ begin
35
+ $LOAD_PATH.unshift PATH
36
+ rv = yield
37
+ ensure
38
+ $LOAD_PATH.shift
39
+ end
40
+ end
41
+ return rv
42
+ end
43
+
44
+ # Utility method used to require all files ending in .rb that lie in the
45
+ # directory below this file that has the same name as the filename passed
46
+ # in. Optionally, a specific _directory_ name can be passed in such that
47
+ # the _filename_ does not have to be equivalent to the directory.
48
+ #
49
+ def self.require_all_libs_relative_to( fname, dir = nil )
50
+ dir ||= ::File.basename(fname, '.*')
51
+ search_me = ::File.expand_path(
52
+ ::File.join(::File.dirname(fname), dir, '**', '*.rb'))
53
+
54
+ Dir.glob(search_me).sort.each {|rb| require rb}
55
+ end
56
+
57
+ end # module Archive
58
+
59
+ Archive.require_all_libs_relative_to(__FILE__)
60
+
@@ -0,0 +1,306 @@
1
+ require 'ffi'
2
+
3
+ module Archive
4
+
5
+ module LibC
6
+ extend FFI::Library
7
+ ffi_lib FFI::Library::LIBC
8
+
9
+ attach_variable :errno, :int
10
+ attach_function :strerror, [:int], :string
11
+ end
12
+
13
+ module C
14
+ def self.attach_function_maybe *args
15
+ attach_function *args
16
+ rescue FFI::NotFoundError
17
+ end
18
+
19
+ extend FFI::Library
20
+ ffi_lib ["archive", "libarchive.so.2"]
21
+
22
+ attach_function :archive_version_number, [], :int
23
+ attach_function :archive_version_string, [], :string
24
+ attach_function :archive_error_string, [:pointer], :string
25
+ attach_function :archive_errno, [:pointer], :int
26
+
27
+ attach_function :archive_read_new, [], :pointer
28
+ attach_function :archive_read_open_filename, [:pointer, :string, :size_t], :int
29
+ attach_function :archive_read_open_memory, [:pointer, :pointer, :size_t], :int
30
+ attach_function :archive_read_support_compression_program, [:pointer, :string], :int
31
+ attach_function :archive_read_support_compression_all, [:pointer], :int
32
+ attach_function :archive_read_support_format_all, [:pointer], :int
33
+ # TODO: this function has been renamed to :archive_read_free in libarchive 3.0
34
+ attach_function :archive_read_finish, [:pointer], :int
35
+ attach_function :archive_read_extract, [:pointer, :pointer, :int], :int
36
+ attach_function :archive_read_header_position, [:pointer], :int
37
+ attach_function :archive_read_next_header, [:pointer, :pointer], :int
38
+ attach_function :archive_read_data, [:pointer, :pointer, :size_t], :size_t
39
+ attach_function :archive_read_data_into_fd, [:pointer, :int], :int
40
+
41
+ attach_function :archive_write_new, [], :pointer
42
+ attach_function :archive_write_open_filename, [:pointer, :string], :int
43
+ callback :archive_open_callback, [:pointer, :pointer], :int
44
+ callback :archive_write_callback, [:pointer, :pointer, :pointer, :size_t], :int
45
+ callback :archive_close_callback, [:pointer, :pointer], :int
46
+ attach_function :archive_write_open, [:pointer, :pointer, :archive_open_callback, :archive_write_callback, :archive_close_callback], :int
47
+ # TODO: catch errors if not defined
48
+ attach_function :archive_write_set_compression_none, [:pointer], :int
49
+ attach_function_maybe :archive_write_set_compression_gzip, [:pointer], :int
50
+ attach_function_maybe :archive_write_set_compression_bzip2, [:pointer], :int
51
+ attach_function_maybe :archive_write_set_compression_compress, [:pointer], :int
52
+ attach_function_maybe :archive_write_set_compression_lzma, [:pointer], :int
53
+ attach_function_maybe :archive_write_set_compression_xz, [:pointer], :int
54
+ attach_function :archive_write_set_compression_program, [:pointer, :string], :int
55
+
56
+ def self.archive_write_set_compression(archive, compression)
57
+ case compression
58
+ when String
59
+ archive_write_set_compression_program archive, compression
60
+ when COMPRESSION_BZIP2
61
+ archive_write_set_compression_bzip2 archive
62
+ when COMPRESSION_GZIP
63
+ archive_write_set_compression_gzip archive
64
+ when COMPRESSION_LZMA
65
+ archive_write_set_compression_lzma archive
66
+ when COMPRESSION_XZ
67
+ archive_write_set_compression_xz archive
68
+ when COMPRESSION_COMPRESS
69
+ archive_write_set_compression_compress archive
70
+ when COMPRESSION_NONE
71
+ archive_write_set_compression_none archive
72
+ else
73
+ raise "Unknown compression type: #{compression}"
74
+ end
75
+ end
76
+
77
+ attach_function :archive_write_set_format, [:pointer, :int], :int
78
+ attach_function :archive_write_data, [:pointer, :pointer, :size_t], :ssize_t
79
+ attach_function :archive_write_header, [:pointer, :pointer], :int
80
+ attach_function :archive_write_finish, [:pointer], :void
81
+ attach_function :archive_write_get_bytes_in_last_block, [:pointer], :int
82
+ attach_function :archive_write_set_bytes_in_last_block, [:pointer, :int], :int
83
+
84
+ attach_function :archive_entry_new, [], :pointer
85
+ attach_function :archive_entry_free, [:pointer], :void
86
+ attach_function :archive_entry_atime, [:pointer], :time_t
87
+ attach_function :archive_entry_atime_nsec, [:pointer, :time_t, :long], :void
88
+ attach_function_maybe :archive_entry_atime_is_set, [:pointer], :int
89
+ attach_function :archive_entry_set_atime, [:pointer, :time_t, :long], :int
90
+ attach_function_maybe :archive_entry_unset_atime, [:pointer], :int
91
+ attach_function_maybe :archive_entry_birthtime, [:pointer], :time_t
92
+ attach_function_maybe :archive_entry_birthtime_nsec, [:pointer, :time_t, :long], :void
93
+ attach_function_maybe :archive_entry_birthtime_is_set, [:pointer], :int
94
+ attach_function_maybe :archive_entry_set_birthtime, [:pointer, :time_t, :long], :int
95
+ attach_function_maybe :archive_entry_unset_birthtime, [:pointer], :int
96
+ attach_function :archive_entry_ctime, [:pointer], :time_t
97
+ attach_function :archive_entry_ctime_nsec, [:pointer, :time_t, :long], :void
98
+ attach_function_maybe :archive_entry_ctime_is_set, [:pointer], :int
99
+ attach_function :archive_entry_set_ctime, [:pointer, :time_t, :long], :int
100
+ attach_function_maybe :archive_entry_unset_ctime, [:pointer], :int
101
+ attach_function :archive_entry_mtime, [:pointer], :time_t
102
+ attach_function :archive_entry_mtime_nsec, [:pointer, :time_t, :long], :void
103
+ attach_function_maybe :archive_entry_mtime_is_set, [:pointer], :int
104
+ attach_function :archive_entry_set_mtime, [:pointer, :time_t, :long], :int
105
+ attach_function_maybe :archive_entry_unset_mtime, [:pointer], :int
106
+ attach_function :archive_entry_dev, [:pointer], :dev_t
107
+ attach_function :archive_entry_set_dev, [:pointer, :dev_t], :void
108
+ attach_function :archive_entry_devmajor, [:pointer], :dev_t
109
+ attach_function :archive_entry_set_devmajor, [:pointer, :dev_t], :void
110
+ attach_function :archive_entry_devminor, [:pointer], :dev_t
111
+ attach_function :archive_entry_set_devminor, [:pointer, :dev_t], :void
112
+ attach_function :archive_entry_filetype, [:pointer], :mode_t
113
+ attach_function :archive_entry_set_filetype, [:pointer, :mode_t], :void
114
+ attach_function :archive_entry_fflags, [:pointer, :pointer, :pointer], :void
115
+ attach_function :archive_entry_set_fflags, [:pointer, :ulong, :ulong], :void
116
+ attach_function :archive_entry_fflags_text, [:pointer], :string
117
+ attach_function :archive_entry_gid, [:pointer], :gid_t
118
+ attach_function :archive_entry_set_gid, [:pointer, :gid_t], :void
119
+ attach_function :archive_entry_gname, [:pointer], :string
120
+ attach_function :archive_entry_set_gname, [:pointer, :string], :void
121
+ attach_function :archive_entry_hardlink, [:pointer], :string
122
+ attach_function :archive_entry_set_hardlink, [:pointer, :string], :void
123
+ attach_function :archive_entry_set_link, [:pointer, :string], :void
124
+ attach_function :archive_entry_ino, [:pointer], :ino_t
125
+ attach_function :archive_entry_set_ino, [:pointer, :ino_t], :void
126
+ attach_function :archive_entry_mode, [:pointer], :mode_t
127
+ attach_function :archive_entry_set_mode, [:pointer, :mode_t], :void
128
+ attach_function :archive_entry_set_perm, [:pointer, :mode_t], :void
129
+ attach_function :archive_entry_nlink, [:pointer], :uint
130
+ attach_function :archive_entry_set_nlink, [:pointer, :uint], :void
131
+ attach_function :archive_entry_pathname, [:pointer], :string
132
+ attach_function :archive_entry_set_pathname, [:pointer, :string], :void
133
+ attach_function :archive_entry_rdev, [:pointer], :dev_t
134
+ attach_function :archive_entry_set_rdev, [:pointer, :dev_t], :void
135
+ attach_function :archive_entry_rdevmajor, [:pointer], :dev_t
136
+ attach_function :archive_entry_set_rdevmajor, [:pointer, :dev_t], :void
137
+ attach_function :archive_entry_rdevminor, [:pointer], :dev_t
138
+ attach_function :archive_entry_set_rdevminor, [:pointer, :dev_t], :void
139
+ attach_function :archive_entry_size, [:pointer], :int64_t
140
+ attach_function :archive_entry_set_size, [:pointer, :int64_t], :void
141
+ attach_function_maybe :archive_entry_unset_size, [:pointer], :void
142
+ attach_function_maybe :archive_entry_size_is_set, [:pointer], :int
143
+ attach_function :archive_entry_sourcepath, [:pointer], :string
144
+ attach_function :archive_entry_strmode, [:pointer], :string
145
+ attach_function :archive_entry_symlink, [:pointer], :string
146
+ attach_function :archive_entry_set_symlink, [:pointer, :string], :void
147
+ attach_function :archive_entry_uid, [:pointer], :uid_t
148
+ attach_function :archive_entry_set_uid, [:pointer, :uid_t], :void
149
+ attach_function :archive_entry_uname, [:pointer], :string
150
+ attach_function :archive_entry_set_uname, [:pointer, :string], :void
151
+ attach_function :archive_entry_copy_stat, [:pointer, :pointer], :void
152
+ attach_function :archive_entry_copy_fflags_text, [:pointer, :string], :string
153
+ attach_function :archive_entry_copy_gname, [:pointer, :string], :string
154
+ attach_function :archive_entry_copy_uname, [:pointer, :string], :string
155
+ attach_function :archive_entry_copy_hardlink, [:pointer, :string], :string
156
+ attach_function :archive_entry_copy_link, [:pointer, :string], :string
157
+ attach_function :archive_entry_copy_symlink, [:pointer, :string], :string
158
+ attach_function :archive_entry_copy_sourcepath, [:pointer, :string], :string
159
+ attach_function :archive_entry_copy_pathname, [:pointer, :string], :string
160
+ attach_function :archive_entry_xattr_clear, [:pointer], :void
161
+ attach_function :archive_entry_xattr_add_entry, [:pointer, :string, :pointer, :size_t], :void
162
+ attach_function :archive_entry_xattr_count, [:pointer], :int
163
+ attach_function :archive_entry_xattr_reset, [:pointer], :int
164
+ attach_function :archive_entry_xattr_next, [:pointer, :pointer, :pointer, :pointer], :int
165
+
166
+ EOF = 1
167
+ OK = 0
168
+ RETRY = (-10)
169
+ WARN = (-20)
170
+ FAILED = (-25)
171
+ FATAL = (-30)
172
+
173
+ DATA_BUFFER_SIZE = 2**16
174
+ end
175
+
176
+ COMPRESSION_NONE = 0
177
+ COMPRESSION_GZIP = 1
178
+ COMPRESSION_BZIP2 = 2
179
+ COMPRESSION_COMPRESS = 3
180
+ COMPRESSION_PROGRAM = 4
181
+ COMPRESSION_LZMA = 5
182
+ COMPRESSION_XZ = 6
183
+ COMPRESSION_UU = 7
184
+ COMPRESSION_RPM = 8
185
+
186
+ FORMAT_BASE_MASK = 0xff0000
187
+ FORMAT_CPIO = 0x10000
188
+ FORMAT_CPIO_POSIX = (FORMAT_CPIO | 1)
189
+ FORMAT_CPIO_BIN_LE = (FORMAT_CPIO | 2)
190
+ FORMAT_CPIO_BIN_BE = (FORMAT_CPIO | 3)
191
+ FORMAT_CPIO_SVR4_NOCRC = (FORMAT_CPIO | 4)
192
+ FORMAT_CPIO_SVR4_CRC = (FORMAT_CPIO | 5)
193
+ FORMAT_SHAR = 0x20000
194
+ FORMAT_SHAR_BASE = (FORMAT_SHAR | 1)
195
+ FORMAT_SHAR_DUMP = (FORMAT_SHAR | 2)
196
+ FORMAT_TAR = 0x30000
197
+ FORMAT_TAR_USTAR = (FORMAT_TAR | 1)
198
+ FORMAT_TAR_PAX_INTERCHANGE = (FORMAT_TAR | 2)
199
+ FORMAT_TAR_PAX_RESTRICTED = (FORMAT_TAR | 3)
200
+ FORMAT_TAR_GNUTAR = (FORMAT_TAR | 4)
201
+ FORMAT_ISO9660 = 0x40000
202
+ FORMAT_ISO9660_ROCKRIDGE = (FORMAT_ISO9660 | 1)
203
+ FORMAT_ZIP = 0x50000
204
+ FORMAT_EMPTY = 0x60000
205
+ FORMAT_AR = 0x70000
206
+ FORMAT_AR_GNU = (FORMAT_AR | 1)
207
+ FORMAT_AR_BSD = (FORMAT_AR | 2)
208
+ FORMAT_MTREE = 0x80000
209
+ FORMAT_RAW = 0x90000
210
+ FORMAT_XAR = 0xA0000
211
+
212
+ EXTRACT_OWNER = (0x0001)
213
+ EXTRACT_PERM = (0x0002)
214
+ EXTRACT_TIME = (0x0004)
215
+ EXTRACT_NO_OVERWRITE = (0x0008)
216
+ EXTRACT_UNLINK = (0x0010)
217
+ EXTRACT_ACL = (0x0020)
218
+ EXTRACT_FFLAGS = (0x0040)
219
+ EXTRACT_XATTR = (0x0080)
220
+ EXTRACT_SECURE_SYMLINKS = (0x0100)
221
+ EXTRACT_SECURE_NODOTDOT = (0x0200)
222
+ EXTRACT_NO_AUTODIR = (0x0400)
223
+ EXTRACT_NO_OVERWRITE_NEWER = (0x0800)
224
+ EXTRACT_SPARSE = (0x1000)
225
+
226
+ def self.read_open_filename file_name, command = nil, &block
227
+ Reader.open_filename file_name, command, &block
228
+ end
229
+
230
+ def self.read_open_memory string, command = nil, &block
231
+ Reader.open_memory string, command, &block
232
+ end
233
+
234
+ def self.write_open_filename file_name, compression, format, &block
235
+ Writer.open_filename file_name, compression, format, &block
236
+ end
237
+
238
+ def self.write_open_memory string, compression, format, &block
239
+ Writer.open_memory string, compression, format, &block
240
+ end
241
+
242
+ def self.version_number
243
+ C::archive_version_number
244
+ end
245
+
246
+ def self.version_string
247
+ C::archive_version_string
248
+ end
249
+
250
+ class Error < StandardError
251
+ def initialize(archive)
252
+ if archive.kind_of? String
253
+ super archive
254
+ else
255
+ super "#{C::archive_error_string(archive)}"
256
+ end
257
+ end
258
+ end
259
+
260
+ class BaseArchive
261
+
262
+ def initialize alloc, free
263
+ @archive = nil
264
+ @archive_free = nil
265
+ @archive = alloc.call
266
+ @archive_free = [nil]
267
+ raise Error, @archive unless @archive
268
+
269
+ @archive_free[0] = free
270
+ ObjectSpace.define_finalizer( self, BaseArchive.finalizer(@archive, @archive_free) )
271
+ end
272
+
273
+ def self.finalizer archive, archive_free
274
+ Proc.new do |*args|
275
+ archive_free[0].call(archive) if archive_free[0]
276
+ end
277
+ end
278
+
279
+ def close
280
+ # TODO: do we need synchronization here?
281
+ if @archive
282
+ # TODO: Error check?
283
+ @archive_free[0].call(@archive)
284
+ end
285
+ ensure
286
+ @archive = nil
287
+ @archive_free[0] = nil
288
+ @data = nil
289
+ end
290
+
291
+ def archive
292
+ raise Error, "No archive open" unless @archive
293
+ @archive
294
+ end
295
+ protected :archive
296
+
297
+ def error_string
298
+ C::archive_error_string(@archive)
299
+ end
300
+
301
+ def errno
302
+ C::archive_errno(@archive)
303
+ end
304
+ end
305
+
306
+ end