ffi-libarchive 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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