ffi_libarchive 1.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.
- checksums.yaml +7 -0
- data/LICENSE +201 -0
- data/README.md +87 -0
- data/lib/ffi_libarchive.rb +8 -0
- data/lib/ffi_libarchive/api.rb +282 -0
- data/lib/ffi_libarchive/archive.rb +182 -0
- data/lib/ffi_libarchive/entry.rb +575 -0
- data/lib/ffi_libarchive/reader.rb +227 -0
- data/lib/ffi_libarchive/utils.rb +119 -0
- data/lib/ffi_libarchive/writer.rb +178 -0
- metadata +130 -0
@@ -0,0 +1,182 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Archive
|
4
|
+
# Stream filter Codes
|
5
|
+
FILTER_NONE = 0
|
6
|
+
FILTER_GZIP = 1
|
7
|
+
FILTER_BZIP2 = 2
|
8
|
+
FILTER_COMPRESS = 3
|
9
|
+
FILTER_PROGRAM = 4
|
10
|
+
FILTER_LZMA = 5
|
11
|
+
FILTER_XZ = 6
|
12
|
+
FILTER_UU = 7
|
13
|
+
FILTER_RPM = 8
|
14
|
+
FILTER_LZIP = 9
|
15
|
+
FILTER_LRZIP = 10
|
16
|
+
FILTER_LZOP = 11
|
17
|
+
FILTER_GRZIP = 12
|
18
|
+
FILTER_LZ4 = 13
|
19
|
+
FILTER_ZSTD = 14
|
20
|
+
# endregion
|
21
|
+
|
22
|
+
# region Compression Codes (deprecated)
|
23
|
+
COMPRESSION_NONE = FILTER_NONE
|
24
|
+
COMPRESSION_GZIP = FILTER_GZIP
|
25
|
+
COMPRESSION_BZIP2 = FILTER_BZIP2
|
26
|
+
COMPRESSION_COMPRESS = FILTER_COMPRESS
|
27
|
+
COMPRESSION_PROGRAM = FILTER_PROGRAM
|
28
|
+
COMPRESSION_LZMA = FILTER_LZMA
|
29
|
+
COMPRESSION_XZ = FILTER_XZ
|
30
|
+
COMPRESSION_UU = FILTER_UU
|
31
|
+
COMPRESSION_RPM = FILTER_RPM
|
32
|
+
COMPRESSION_LZIP = FILTER_LZIP
|
33
|
+
COMPRESSION_LRZIP = FILTER_LRZIP
|
34
|
+
# endregion
|
35
|
+
|
36
|
+
# region Format Codes
|
37
|
+
FORMAT_BASE_MASK = 0xff0000
|
38
|
+
FORMAT_CPIO = 0x10000
|
39
|
+
FORMAT_CPIO_POSIX = (FORMAT_CPIO | 1)
|
40
|
+
FORMAT_CPIO_BIN_LE = (FORMAT_CPIO | 2)
|
41
|
+
FORMAT_CPIO_BIN_BE = (FORMAT_CPIO | 3)
|
42
|
+
FORMAT_CPIO_SVR4_NOCRC = (FORMAT_CPIO | 4)
|
43
|
+
FORMAT_CPIO_SVR4_CRC = (FORMAT_CPIO | 5)
|
44
|
+
FORMAT_CPIO_AFIO_LARGE = (FORMAT_CPIO | 6)
|
45
|
+
FORMAT_SHAR = 0x20000
|
46
|
+
FORMAT_SHAR_BASE = (FORMAT_SHAR | 1)
|
47
|
+
FORMAT_SHAR_DUMP = (FORMAT_SHAR | 2)
|
48
|
+
FORMAT_TAR = 0x30000
|
49
|
+
FORMAT_TAR_USTAR = (FORMAT_TAR | 1)
|
50
|
+
FORMAT_TAR_PAX_INTERCHANGE = (FORMAT_TAR | 2)
|
51
|
+
FORMAT_TAR_PAX_RESTRICTED = (FORMAT_TAR | 3)
|
52
|
+
FORMAT_TAR_GNUTAR = (FORMAT_TAR | 4)
|
53
|
+
FORMAT_ISO9660 = 0x40000
|
54
|
+
FORMAT_ISO9660_ROCKRIDGE = (FORMAT_ISO9660 | 1)
|
55
|
+
FORMAT_ZIP = 0x50000
|
56
|
+
FORMAT_EMPTY = 0x60000
|
57
|
+
FORMAT_AR = 0x70000
|
58
|
+
FORMAT_AR_GNU = (FORMAT_AR | 1)
|
59
|
+
FORMAT_AR_BSD = (FORMAT_AR | 2)
|
60
|
+
FORMAT_MTREE = 0x80000
|
61
|
+
FORMAT_RAW = 0x90000
|
62
|
+
FORMAT_XAR = 0xA0000
|
63
|
+
FORMAT_LHA = 0xB0000
|
64
|
+
FORMAT_CAB = 0xC0000
|
65
|
+
FORMAT_RAR = 0xD0000
|
66
|
+
FORMAT_7ZIP = 0xE0000
|
67
|
+
FORMAT_WARC = 0xF0000
|
68
|
+
FORMAT_RAR_V5 = 0x100000
|
69
|
+
# endregion
|
70
|
+
|
71
|
+
# region Extraction Flags
|
72
|
+
EXTRACT_OWNER = 0x0001
|
73
|
+
EXTRACT_PERM = 0x0002
|
74
|
+
EXTRACT_TIME = 0x0004
|
75
|
+
EXTRACT_NO_OVERWRITE = 0x0008
|
76
|
+
EXTRACT_UNLINK = 0x0010
|
77
|
+
EXTRACT_ACL = 0x0020
|
78
|
+
EXTRACT_FFLAGS = 0x0040
|
79
|
+
EXTRACT_XATTR = 0x0080
|
80
|
+
EXTRACT_SECURE_SYMLINKS = 0x0100
|
81
|
+
EXTRACT_SECURE_NODOTDOT = 0x0200
|
82
|
+
EXTRACT_NO_AUTODIR = 0x0400
|
83
|
+
EXTRACT_NO_OVERWRITE_NEWER = 0x0800
|
84
|
+
EXTRACT_SPARSE = 0x1000
|
85
|
+
EXTRACT_MAC_METADATA = 0x2000
|
86
|
+
EXTRACT_NO_HFS_COMPRESSION = 0x4000
|
87
|
+
EXTRACT_HFS_COMPRESSION_FORCED = 0x8000
|
88
|
+
EXTRACT_SECURE_NOABSOLUTEPATHS = 0x10000
|
89
|
+
EXTRACT_CLEAR_NOCHANGE_FFLAGS = 0x20000
|
90
|
+
# endregion
|
91
|
+
|
92
|
+
class << self
|
93
|
+
# @param [String] file_name
|
94
|
+
# @return [Reader]
|
95
|
+
# @yieldparam [Reader]
|
96
|
+
def read_open_filename(file_name, command = nil, &block)
|
97
|
+
Reader.open_filename file_name, command, &block
|
98
|
+
end
|
99
|
+
|
100
|
+
# @param [String] string
|
101
|
+
# @return [Reader]
|
102
|
+
# @yieldparam [Reader]
|
103
|
+
def read_open_memory(string, command = nil, &block)
|
104
|
+
Reader.open_memory string, command, &block
|
105
|
+
end
|
106
|
+
|
107
|
+
# @param [#call] reader
|
108
|
+
# @return [Reader]
|
109
|
+
# @yieldparam [Reader]
|
110
|
+
def read_open_stream(reader, command = nil, &block)
|
111
|
+
Reader.open_stream reader, command, &block
|
112
|
+
end
|
113
|
+
|
114
|
+
# @param [String] file_name
|
115
|
+
# @return [Writer]
|
116
|
+
# @yieldparam [Writer]
|
117
|
+
def write_open_filename(file_name, compression, format, &block)
|
118
|
+
Writer.open_filename file_name, compression, format, &block
|
119
|
+
end
|
120
|
+
|
121
|
+
# @param [String] string
|
122
|
+
# @return [Writer]
|
123
|
+
# @yieldparam [Writer]
|
124
|
+
def write_open_memory(string, compression, format, &block)
|
125
|
+
Writer.open_memory string, compression, format, &block
|
126
|
+
end
|
127
|
+
|
128
|
+
# @return [Integer]
|
129
|
+
def version_number
|
130
|
+
C.archive_version_number
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return [String]
|
134
|
+
def version_string
|
135
|
+
C.archive_version_string
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class Error < StandardError
|
140
|
+
# noinspection RubyNilAnalysis
|
141
|
+
def initialize(obj = nil)
|
142
|
+
super(obj.respond_to?(:error_string) ? obj.error_string : obj)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# @abstract
|
147
|
+
class BaseArchive
|
148
|
+
# @param [Method] alloc
|
149
|
+
# @param [Method] free
|
150
|
+
def initialize(alloc, free)
|
151
|
+
raise ArgumentError, 'Invalid methods' unless alloc.respond_to?(:call) && free.respond_to?(:call)
|
152
|
+
|
153
|
+
@archive = alloc.call
|
154
|
+
raise Error, 'No archive open' unless @archive
|
155
|
+
|
156
|
+
@archive_free = [free]
|
157
|
+
ObjectSpace.define_finalizer(self, method(:close).to_proc)
|
158
|
+
end
|
159
|
+
|
160
|
+
def close
|
161
|
+
# TODO: do we need synchronization here?
|
162
|
+
@archive_free[0].call(@archive) if @archive && @archive_free[0].respond_to?(:call) # TODO: Error check?
|
163
|
+
ensure
|
164
|
+
@archive = nil
|
165
|
+
@archive_free[0] = nil
|
166
|
+
end
|
167
|
+
|
168
|
+
# @!visibility protected
|
169
|
+
# @return [FFI::Pointer]
|
170
|
+
attr_reader :archive
|
171
|
+
|
172
|
+
# @return [String]
|
173
|
+
def error_string
|
174
|
+
C.archive_error_string(archive)
|
175
|
+
end
|
176
|
+
|
177
|
+
# @return [Integer]
|
178
|
+
def errno
|
179
|
+
C.archive_errno(archive)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
@@ -0,0 +1,575 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Archive
|
4
|
+
class Entry
|
5
|
+
# region File-type Constants
|
6
|
+
|
7
|
+
S_IFMT = 0o170000 # bits mask
|
8
|
+
S_IFSOCK = 0o140000
|
9
|
+
S_IFLNK = 0o120000
|
10
|
+
S_IFREG = 0o100000
|
11
|
+
S_IFBLK = 0o060000
|
12
|
+
S_IFDIR = 0o040000
|
13
|
+
S_IFCHR = 0o020000
|
14
|
+
S_IFIFO = 0o010000
|
15
|
+
|
16
|
+
SOCKET = S_IFSOCK
|
17
|
+
SYMBOLIC_LINK = S_IFLNK
|
18
|
+
FILE = S_IFREG # regular file
|
19
|
+
BLOCK_DEVICE = S_IFBLK # block special device
|
20
|
+
DIRECTORY = S_IFDIR
|
21
|
+
CHARACTER_DEVICE = S_IFCHR # character special device
|
22
|
+
FIFO = S_IFIFO # named pipe (FIFO)
|
23
|
+
|
24
|
+
def self.file_types
|
25
|
+
@file_types ||= Hash[constants.reject { |k| k =~ /^S_/ }.map { |k| [k.downcase, const_get(k)] }]
|
26
|
+
end
|
27
|
+
|
28
|
+
# endregion
|
29
|
+
|
30
|
+
# @param [FFI::Pointer]
|
31
|
+
# @return [Entry]
|
32
|
+
def self.from_pointer(entry)
|
33
|
+
new entry
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param [FFI::Pointer] entry
|
37
|
+
def initialize(entry = nil)
|
38
|
+
if entry
|
39
|
+
@entry = entry
|
40
|
+
else
|
41
|
+
@entry = C.archive_entry_new
|
42
|
+
raise Error, 'No entry object' unless @entry
|
43
|
+
end
|
44
|
+
|
45
|
+
if block_given?
|
46
|
+
begin
|
47
|
+
yield self
|
48
|
+
ensure
|
49
|
+
close
|
50
|
+
end
|
51
|
+
else
|
52
|
+
ObjectSpace.define_finalizer(self, method(:close).to_proc)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def close
|
57
|
+
# TODO: do we need synchronization here?
|
58
|
+
C.archive_entry_free(@entry) if @entry
|
59
|
+
ensure
|
60
|
+
@entry = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [FFI::Pointer]
|
64
|
+
attr_reader :entry
|
65
|
+
|
66
|
+
class << self
|
67
|
+
protected
|
68
|
+
|
69
|
+
# @param [Symbol] api API method
|
70
|
+
# @param [Hash] opts
|
71
|
+
# @option opts [#to_sym] :name Method name
|
72
|
+
# @option opts [Boolean] :maybe Skip undefined method?
|
73
|
+
# @option opts [#call] :post The result transformer
|
74
|
+
# @option opts [#call] :pre The arguments processor
|
75
|
+
def attach_attribute(api, opts = {})
|
76
|
+
opts[:name] ||= api.to_s.sub(/^archive_entry_/, '').sub(/_is_.*$/, '\0?')
|
77
|
+
|
78
|
+
define_method(opts[:name].to_sym) do |*args|
|
79
|
+
opts[:pre].call(args) if opts[:pre].respond_to?(:call)
|
80
|
+
|
81
|
+
result = C.respond_to?(api) || !opts[:maybe] ? C.send(api, *args.unshift(entry)) : nil
|
82
|
+
opts[:post].respond_to?(:call) ? opts[:post].call(result) : result
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def proc_time_at
|
87
|
+
@proc_time_at ||= Time.method(:at)
|
88
|
+
end
|
89
|
+
|
90
|
+
def proc_2_args_to_i
|
91
|
+
@proc_2_args_to_i ||= proc { |args| args.fill(0, args.size..1).map!(&:to_i) }
|
92
|
+
end
|
93
|
+
|
94
|
+
def proc_is_nonzero
|
95
|
+
@proc_is_nonzero ||= 0.method(:!=)
|
96
|
+
end
|
97
|
+
|
98
|
+
def proc_read_wide_string
|
99
|
+
@proc_read_wide_string ||= Utils.method(:read_wide_string)
|
100
|
+
end
|
101
|
+
|
102
|
+
def proc_string_arg_to_wide
|
103
|
+
@proc_string_arg_to_wide ||= proc { |args| args.map! { |s| Utils.to_wide_string s } }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# region Access time
|
108
|
+
# @!method atime
|
109
|
+
# @return [Time]
|
110
|
+
attach_attribute :archive_entry_atime, post: proc_time_at
|
111
|
+
|
112
|
+
# @!method set_atime(time, nsec = 0)
|
113
|
+
# @param [Time, #to_i] time
|
114
|
+
# @param [Integer, #to_i] nsec
|
115
|
+
attach_attribute :archive_entry_set_atime, pre: proc_2_args_to_i
|
116
|
+
|
117
|
+
alias atime= set_atime
|
118
|
+
|
119
|
+
# @!method atime_is_set?
|
120
|
+
# @return [Boolean]
|
121
|
+
attach_attribute :archive_entry_atime_is_set, post: proc_is_nonzero
|
122
|
+
|
123
|
+
# @!method atime_nsec
|
124
|
+
# @return [Integer] :long
|
125
|
+
attach_attribute :archive_entry_atime_nsec
|
126
|
+
|
127
|
+
# @!method unset_atime
|
128
|
+
attach_attribute :archive_entry_unset_atime
|
129
|
+
# endregion
|
130
|
+
|
131
|
+
# region Creation time
|
132
|
+
# @!method birthtime
|
133
|
+
# @return [Time]
|
134
|
+
attach_attribute :archive_entry_birthtime, post: proc_time_at
|
135
|
+
|
136
|
+
# @!method set_birthtime(time, nsec = 0)
|
137
|
+
# @param [Time, #to_i] time
|
138
|
+
# @param [Integer, #to_i] nsec
|
139
|
+
attach_attribute :archive_entry_set_birthtime, pre: proc_2_args_to_i
|
140
|
+
|
141
|
+
alias birthtime= set_birthtime
|
142
|
+
|
143
|
+
# @!method birthtime_is_set?
|
144
|
+
# @return [Boolean]
|
145
|
+
attach_attribute :archive_entry_birthtime_is_set, post: proc_is_nonzero
|
146
|
+
|
147
|
+
# @!method birthtime_nsec
|
148
|
+
# @return [Integer] :long
|
149
|
+
attach_attribute :archive_entry_birthtime_nsec
|
150
|
+
|
151
|
+
# @!method unset_birthtime
|
152
|
+
attach_attribute :archive_entry_unset_birthtime
|
153
|
+
# endregion
|
154
|
+
|
155
|
+
# region Change time
|
156
|
+
# @!method ctime
|
157
|
+
# @return [Time]
|
158
|
+
attach_attribute :archive_entry_ctime, post: proc_time_at
|
159
|
+
|
160
|
+
# @!method set_ctime(time, nsec = 0)
|
161
|
+
# @param [Time, #to_i] time
|
162
|
+
# @param [Integer, #to_i] nsec
|
163
|
+
attach_attribute :archive_entry_set_ctime, pre: proc_2_args_to_i
|
164
|
+
|
165
|
+
alias ctime= set_ctime
|
166
|
+
|
167
|
+
# @!method ctime_is_set?
|
168
|
+
# @return [Boolean]
|
169
|
+
attach_attribute :archive_entry_ctime_is_set, post: proc_is_nonzero
|
170
|
+
|
171
|
+
# @!method ctime_nsec
|
172
|
+
# @return [Integer] :long
|
173
|
+
attach_attribute :archive_entry_ctime_nsec
|
174
|
+
|
175
|
+
# @!method unset_ctime
|
176
|
+
attach_attribute :archive_entry_unset_ctime
|
177
|
+
# endregion
|
178
|
+
|
179
|
+
# region File-type
|
180
|
+
|
181
|
+
# @!method filetype
|
182
|
+
# @return [Integer] :mode_t
|
183
|
+
attach_attribute :archive_entry_filetype
|
184
|
+
|
185
|
+
# @!method filetype=(type)
|
186
|
+
# @param [Integer, #to_s] type
|
187
|
+
attach_attribute(
|
188
|
+
:archive_entry_set_filetype,
|
189
|
+
name: 'filetype=', pre: ->(args) { args.map! { |t| t.is_a?(Integer) ? t : const_get(t.to_s.upcase) } }
|
190
|
+
)
|
191
|
+
|
192
|
+
# @!method block_device?
|
193
|
+
# @return [Boolean]
|
194
|
+
# @!method character_device?
|
195
|
+
# @return [Boolean]
|
196
|
+
# @!method directory?
|
197
|
+
# @return [Boolean]
|
198
|
+
# @!method fifo?
|
199
|
+
# @return [Boolean]
|
200
|
+
# @!method file?
|
201
|
+
# @return [Boolean]
|
202
|
+
# @!method socket?
|
203
|
+
# @return [Boolean]
|
204
|
+
# @!method symbolic_link?
|
205
|
+
# @return [Boolean]
|
206
|
+
file_types.each do |k, v|
|
207
|
+
define_method("#{k}?".to_sym) { (filetype & S_IFMT) == v }
|
208
|
+
end
|
209
|
+
|
210
|
+
alias regular? file?
|
211
|
+
alias block_special? block_device?
|
212
|
+
alias character_special? character_device?
|
213
|
+
|
214
|
+
# @return [Symbol]
|
215
|
+
def filetype_s
|
216
|
+
self.class.file_types.key(filetype & S_IFMT)
|
217
|
+
end
|
218
|
+
|
219
|
+
# endregion
|
220
|
+
|
221
|
+
# region File status
|
222
|
+
|
223
|
+
# @!method stat
|
224
|
+
# @return [FFI::Pointer]
|
225
|
+
attach_attribute :archive_entry_stat
|
226
|
+
|
227
|
+
# @param [String, FFI::Pointer] filename
|
228
|
+
def copy_lstat(filename)
|
229
|
+
copy_stat_from(filename.is_a?(String) ? File.lstat(filename) : filename)
|
230
|
+
end
|
231
|
+
|
232
|
+
# @param [String, FFI::Pointer] filename
|
233
|
+
def copy_stat(filename)
|
234
|
+
copy_stat_from(filename.is_a?(String) ? File.stat(filename) : filename)
|
235
|
+
end
|
236
|
+
|
237
|
+
# @private
|
238
|
+
# @param [FFI::Pointer, File::Stat] stat
|
239
|
+
def copy_stat_from(stat)
|
240
|
+
if stat.respond_to?(:null?) && !stat.null?
|
241
|
+
C.archive_entry_copy_stat(entry, stat)
|
242
|
+
|
243
|
+
elsif stat.is_a?(File::Stat)
|
244
|
+
%w[dev gid uid ino nlink rdev size mode].each do |fn|
|
245
|
+
# @type [Integer]
|
246
|
+
f = stat.send(fn)
|
247
|
+
send "#{fn}=", f if f
|
248
|
+
end
|
249
|
+
|
250
|
+
%w[atime ctime mtime birthtime].each do |fn|
|
251
|
+
# @type [Time]
|
252
|
+
f = stat.respond_to?(fn) ? stat.send(fn) : nil
|
253
|
+
send "set_#{fn}", f, f.tv_nsec if f
|
254
|
+
end
|
255
|
+
else
|
256
|
+
raise ArgumentError, "Copying stat for #{stat.class} is not supported"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# endregion
|
261
|
+
|
262
|
+
# region Device number
|
263
|
+
# @!method dev
|
264
|
+
# @return [Integer] :dev_t
|
265
|
+
attach_attribute :archive_entry_dev
|
266
|
+
|
267
|
+
# @!method dev=(dev)
|
268
|
+
# @param [Integer] dev
|
269
|
+
attach_attribute :archive_entry_set_dev, name: 'dev='
|
270
|
+
|
271
|
+
# @!method devmajor
|
272
|
+
# @return [Integer] :dev_t
|
273
|
+
attach_attribute :archive_entry_devmajor
|
274
|
+
|
275
|
+
# @!method devmajor=(dev)
|
276
|
+
# @param [Integer] dev
|
277
|
+
attach_attribute :archive_entry_set_devmajor, name: 'devmajor='
|
278
|
+
|
279
|
+
# @!method devminor
|
280
|
+
# @return [Integer] :dev_t
|
281
|
+
attach_attribute :archive_entry_devminor
|
282
|
+
|
283
|
+
# @!method devminor=(dev)
|
284
|
+
# @param [Integer] dev
|
285
|
+
attach_attribute :archive_entry_set_devminor, name: 'devminor='
|
286
|
+
# endregion
|
287
|
+
|
288
|
+
# region File flags/attributes (see #lsattr)
|
289
|
+
# @return [Array<Integer>] of [:set, :clear]
|
290
|
+
def fflags
|
291
|
+
set = FFI::MemoryPointer.new :ulong
|
292
|
+
clear = FFI::MemoryPointer.new :ulong
|
293
|
+
C.archive_entry_fflags(entry, set, clear)
|
294
|
+
|
295
|
+
[set.get_ulong(0), clear.get_ulong(0)]
|
296
|
+
end
|
297
|
+
|
298
|
+
# @!method set_fflags(set, clear)
|
299
|
+
# @param [Integer] set
|
300
|
+
# @param [Integer] clear
|
301
|
+
attach_attribute :archive_entry_set_fflags
|
302
|
+
|
303
|
+
# @!method fflags_text
|
304
|
+
# @return [String]
|
305
|
+
attach_attribute :archive_entry_fflags_text
|
306
|
+
|
307
|
+
# @!method copy_fflags_text(fflags_text)
|
308
|
+
# @param [String] fflags_text
|
309
|
+
# @return [String] Invalid token string, or NULL if success
|
310
|
+
attach_attribute :archive_entry_copy_fflags_text
|
311
|
+
|
312
|
+
alias fflags_text= copy_fflags_text
|
313
|
+
# endregion
|
314
|
+
|
315
|
+
# region Group ownership
|
316
|
+
# @!method gid
|
317
|
+
# @return [Integer] :int64_t
|
318
|
+
attach_attribute :archive_entry_gid
|
319
|
+
|
320
|
+
# @!method gid=(gid)
|
321
|
+
# @param [Integer] gid
|
322
|
+
attach_attribute :archive_entry_set_gid, name: 'gid='
|
323
|
+
|
324
|
+
# @!method gname
|
325
|
+
# @return [String]
|
326
|
+
attach_attribute :archive_entry_gname
|
327
|
+
|
328
|
+
# @!method gname=(gname)
|
329
|
+
# @param [String] gname
|
330
|
+
attach_attribute :archive_entry_set_gname, name: 'gname='
|
331
|
+
|
332
|
+
# @!method copy_gname(gname)
|
333
|
+
# @param [String] gname
|
334
|
+
attach_attribute :archive_entry_copy_gname
|
335
|
+
# endregion
|
336
|
+
|
337
|
+
# region Links
|
338
|
+
|
339
|
+
# @!method hardlink
|
340
|
+
# @return [String]
|
341
|
+
attach_attribute :archive_entry_hardlink
|
342
|
+
|
343
|
+
# @!method hardlink=(lnk)
|
344
|
+
# @param [String] lnk
|
345
|
+
attach_attribute :archive_entry_set_hardlink, name: 'hardlink='
|
346
|
+
|
347
|
+
# @!method copy_hardlink(lnk)
|
348
|
+
# @param [String] lnk
|
349
|
+
attach_attribute :archive_entry_copy_hardlink
|
350
|
+
|
351
|
+
# @!method link=(lnk)
|
352
|
+
# @param [String] lnk
|
353
|
+
attach_attribute :archive_entry_set_link, name: 'link='
|
354
|
+
|
355
|
+
# @!method copy_link(lnk)
|
356
|
+
# @param [String] lnk
|
357
|
+
attach_attribute :archive_entry_copy_link
|
358
|
+
|
359
|
+
# @!method symlink
|
360
|
+
# @return [String]
|
361
|
+
attach_attribute :archive_entry_symlink
|
362
|
+
|
363
|
+
# @!method symlink=(lnk)
|
364
|
+
# @param [String] lnk
|
365
|
+
attach_attribute :archive_entry_set_symlink, name: 'symlink='
|
366
|
+
|
367
|
+
# @!method copy_symlink(lnk)
|
368
|
+
# @param [String] lnk
|
369
|
+
attach_attribute :archive_entry_copy_symlink
|
370
|
+
|
371
|
+
# endregion
|
372
|
+
|
373
|
+
# @!method ino
|
374
|
+
# @return [Integer] :int64_t of inode number
|
375
|
+
attach_attribute :archive_entry_ino
|
376
|
+
|
377
|
+
# @!method ino=(ino)
|
378
|
+
# @param [String] ino inode number
|
379
|
+
attach_attribute :archive_entry_set_ino, name: 'ino='
|
380
|
+
|
381
|
+
# region File permissions
|
382
|
+
|
383
|
+
# @!method mode
|
384
|
+
# @return [Integer] :mode_t
|
385
|
+
attach_attribute :archive_entry_mode
|
386
|
+
|
387
|
+
# @!method mode=(mode)
|
388
|
+
# @param [Integer] mode File protection (see #filetype)
|
389
|
+
attach_attribute :archive_entry_set_mode, name: 'mode='
|
390
|
+
|
391
|
+
# @!method perm
|
392
|
+
# @return [Integer] :mode_t
|
393
|
+
attach_attribute :archive_entry_perm
|
394
|
+
|
395
|
+
# @!method perm=(perm)
|
396
|
+
# @param [Integer] perm of :mode_t
|
397
|
+
attach_attribute :archive_entry_set_perm, name: 'perm='
|
398
|
+
|
399
|
+
# @!method strmode
|
400
|
+
# @return [String]
|
401
|
+
attach_attribute :archive_entry_strmode
|
402
|
+
|
403
|
+
# endregion
|
404
|
+
|
405
|
+
# region Modification time
|
406
|
+
# @!method mtime
|
407
|
+
# @return [Time]
|
408
|
+
attach_attribute :archive_entry_mtime, post: proc_time_at
|
409
|
+
|
410
|
+
# @!method set_mtime(time, nsec = 0)
|
411
|
+
# @param [Time, #to_i] time
|
412
|
+
# @param [Integer, #to_i] nsec
|
413
|
+
attach_attribute :archive_entry_set_mtime, pre: proc_2_args_to_i
|
414
|
+
|
415
|
+
alias mtime= set_mtime
|
416
|
+
|
417
|
+
# @!method mtime_is_set?
|
418
|
+
# @return [Boolean]
|
419
|
+
attach_attribute :archive_entry_mtime_is_set, post: proc_is_nonzero
|
420
|
+
|
421
|
+
# @!method mtime_nsec
|
422
|
+
# @return [Integer] :long
|
423
|
+
attach_attribute :archive_entry_mtime_nsec
|
424
|
+
|
425
|
+
# @!method unset_mtime
|
426
|
+
attach_attribute :archive_entry_unset_mtime
|
427
|
+
# endregion
|
428
|
+
|
429
|
+
# @!method nlink
|
430
|
+
# @return [Integer] :uint
|
431
|
+
attach_attribute :archive_entry_nlink
|
432
|
+
|
433
|
+
# @!method nlink=(nlink)
|
434
|
+
# @param [Integer] nlink Number of hard links / files in a directory
|
435
|
+
attach_attribute :archive_entry_set_nlink, name: 'nlink='
|
436
|
+
|
437
|
+
# region File path
|
438
|
+
# @!method pathname
|
439
|
+
# @return [String]
|
440
|
+
attach_attribute :archive_entry_pathname
|
441
|
+
|
442
|
+
# @!method pathname=(path)
|
443
|
+
# @param [String] path
|
444
|
+
attach_attribute :archive_entry_set_pathname, name: 'pathname='
|
445
|
+
|
446
|
+
# @!method pathname_w
|
447
|
+
# @return [String]
|
448
|
+
attach_attribute :archive_entry_pathname_w, maybe: true, post: proc_read_wide_string
|
449
|
+
|
450
|
+
# @!method pathname_w=(path)
|
451
|
+
# @param [String] path
|
452
|
+
attach_attribute :archive_entry_copy_pathname_w, name: 'pathname_w=', pre: proc_string_arg_to_wide
|
453
|
+
|
454
|
+
# @!method copy_pathname(file_name)
|
455
|
+
# @param [String] file_name
|
456
|
+
attach_attribute :archive_entry_copy_pathname
|
457
|
+
# endregion
|
458
|
+
|
459
|
+
# region Root device ID (if special?)
|
460
|
+
# @!method rdev
|
461
|
+
# @return [Integer] :dev_t
|
462
|
+
attach_attribute :archive_entry_rdev
|
463
|
+
|
464
|
+
# @!method rdev=(dev)
|
465
|
+
# @param [Integer] dev
|
466
|
+
attach_attribute :archive_entry_set_rdev, name: 'rdev='
|
467
|
+
|
468
|
+
# @!method rdevmajor
|
469
|
+
# @return [Integer] :dev_t
|
470
|
+
attach_attribute :archive_entry_rdevmajor
|
471
|
+
|
472
|
+
# @!method rdevmajor=(dev)
|
473
|
+
# @param [Integer] dev
|
474
|
+
attach_attribute :archive_entry_set_rdevmajor, name: 'rdevmajor='
|
475
|
+
|
476
|
+
# @!method rdevminor
|
477
|
+
# @return [Integer] :dev_t
|
478
|
+
attach_attribute :archive_entry_rdevminor
|
479
|
+
|
480
|
+
# @!method rdevminor=(dev)
|
481
|
+
# @param [Integer] dev
|
482
|
+
attach_attribute :archive_entry_set_rdevminor, name: 'rdevminor='
|
483
|
+
# endregion
|
484
|
+
|
485
|
+
# region File size
|
486
|
+
|
487
|
+
# @!method size
|
488
|
+
# @return [Integer] :int64_t
|
489
|
+
attach_attribute :archive_entry_size
|
490
|
+
|
491
|
+
# @!method size=(size)
|
492
|
+
# @param [Integer] size
|
493
|
+
attach_attribute :archive_entry_set_size, name: 'size='
|
494
|
+
|
495
|
+
# @!method size_is_set?
|
496
|
+
# @return [Boolean]
|
497
|
+
attach_attribute :archive_entry_size_is_set, post: proc_is_nonzero
|
498
|
+
|
499
|
+
# @!method unset_size
|
500
|
+
attach_attribute :archive_entry_unset_size
|
501
|
+
|
502
|
+
# endregion
|
503
|
+
|
504
|
+
# @!method sourcepath
|
505
|
+
# @return [String]
|
506
|
+
attach_attribute :archive_entry_sourcepath
|
507
|
+
|
508
|
+
# @!method copy_sourcepath(path)
|
509
|
+
# @param [String] path
|
510
|
+
attach_attribute :archive_entry_copy_sourcepath
|
511
|
+
|
512
|
+
alias sourcepath= copy_sourcepath
|
513
|
+
|
514
|
+
# region Ownership
|
515
|
+
# @!method uid
|
516
|
+
# @return [Integer] :int64_t
|
517
|
+
attach_attribute :archive_entry_uid
|
518
|
+
|
519
|
+
# @!method uid=(uid)
|
520
|
+
# @param [Integer] uid
|
521
|
+
attach_attribute :archive_entry_set_uid, name: 'uid='
|
522
|
+
|
523
|
+
# @!method uname
|
524
|
+
# @return [String]
|
525
|
+
attach_attribute :archive_entry_uname
|
526
|
+
|
527
|
+
# @!method uname=(uname)
|
528
|
+
# @param [String] uname
|
529
|
+
attach_attribute :archive_entry_set_uname, name: 'uname='
|
530
|
+
|
531
|
+
# @!method copy_uname(uname)
|
532
|
+
# @param [String] uname
|
533
|
+
attach_attribute :archive_entry_copy_uname
|
534
|
+
# endregion
|
535
|
+
|
536
|
+
# region Extended attributes
|
537
|
+
|
538
|
+
# @param [String] name
|
539
|
+
# @param [String] value
|
540
|
+
def xattr_add_entry(name, value)
|
541
|
+
raise ArgumentError, 'value is not a String' unless value.is_a?(String)
|
542
|
+
|
543
|
+
C.archive_entry_xattr_add_entry(entry, name, Utils.get_memory_ptr(value), value.bytesize)
|
544
|
+
end
|
545
|
+
|
546
|
+
# @!method xattr_clear
|
547
|
+
attach_attribute :archive_entry_xattr_clear
|
548
|
+
|
549
|
+
# @!method xattr_count
|
550
|
+
# @return [Integer]
|
551
|
+
attach_attribute :archive_entry_xattr_count
|
552
|
+
|
553
|
+
# @return [Array<String>] of [:name, :value]
|
554
|
+
def xattr_next
|
555
|
+
name = FFI::MemoryPointer.new :pointer
|
556
|
+
value = FFI::MemoryPointer.new :pointer
|
557
|
+
size = FFI::MemoryPointer.new :size_t
|
558
|
+
return nil if C.archive_entry_xattr_next(entry, name, value, size) != C::OK
|
559
|
+
|
560
|
+
name = name.get_pointer(0) unless name.null?
|
561
|
+
value = value.get_pointer(0) unless value.null?
|
562
|
+
# Someday size.get(:size_t) could work
|
563
|
+
[
|
564
|
+
name.null? ? nil : name.get_string(0),
|
565
|
+
value.null? ? nil : value.get_bytes(0, size.send("get_uint#{FFI.type_size(:size_t) * 8}", 0))
|
566
|
+
]
|
567
|
+
end
|
568
|
+
|
569
|
+
# @!method xattr_reset
|
570
|
+
# @return [Integer]
|
571
|
+
attach_attribute :archive_entry_xattr_reset
|
572
|
+
|
573
|
+
# endregion
|
574
|
+
end
|
575
|
+
end
|