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 +4 -0
- data/README.md +70 -0
- data/Rakefile +18 -0
- data/bin/ffi-libarchive-ruby +7 -0
- data/lib/ffi-libarchive.rb +60 -0
- data/lib/ffi-libarchive/archive.rb +306 -0
- data/lib/ffi-libarchive/entry.rb +482 -0
- data/lib/ffi-libarchive/reader.rb +131 -0
- data/lib/ffi-libarchive/stat.rb +31 -0
- data/lib/ffi-libarchive/writer.rb +143 -0
- data/test/data/test.tar.gz +0 -0
- data/test/sets/ts_read.rb +119 -0
- data/test/sets/ts_write.rb +133 -0
- data/test/test_ffi-libarchive.rb +8 -0
- data/version.txt +1 -0
- metadata +91 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
module Archive
|
2
|
+
|
3
|
+
# TODO: Remove this forward-declaration
|
4
|
+
class BaseArchive
|
5
|
+
end
|
6
|
+
|
7
|
+
class Reader < BaseArchive
|
8
|
+
|
9
|
+
private_class_method :new
|
10
|
+
|
11
|
+
def self.open_filename file_name, command = nil
|
12
|
+
if block_given?
|
13
|
+
reader = open_filename file_name, command
|
14
|
+
begin
|
15
|
+
yield reader
|
16
|
+
ensure
|
17
|
+
reader.close
|
18
|
+
end
|
19
|
+
else
|
20
|
+
new :file_name => file_name, :command => command
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.open_memory string, command = nil
|
25
|
+
if block_given?
|
26
|
+
reader = open_memory string, command
|
27
|
+
begin
|
28
|
+
yield reader
|
29
|
+
ensure
|
30
|
+
reader.close
|
31
|
+
end
|
32
|
+
else
|
33
|
+
new :memory => string, :command => command
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize params = {}
|
38
|
+
super C::method(:archive_read_new), C::method(:archive_read_finish)
|
39
|
+
|
40
|
+
if params[:command]
|
41
|
+
cmd = params[:command]
|
42
|
+
raise Error, @archive if C::archive_read_support_compression_program(archive, cmd) != C::OK
|
43
|
+
else
|
44
|
+
raise Error, @archive if C::archive_read_support_compression_all(archive) != C::OK
|
45
|
+
end
|
46
|
+
|
47
|
+
raise Error, @archive if C::archive_read_support_format_all(archive) != C::OK
|
48
|
+
|
49
|
+
if params[:file_name]
|
50
|
+
raise Error, @archive if C::archive_read_open_filename(archive, params[:file_name], 1024) != C::OK
|
51
|
+
elsif params[:memory]
|
52
|
+
str = params[:memory]
|
53
|
+
@data = FFI::MemoryPointer.new str.size
|
54
|
+
@data.put_bytes 0, str
|
55
|
+
raise Error, @archive if C::archive_read_open_memory(archive, @data, @data.size) != C::OK
|
56
|
+
end
|
57
|
+
rescue
|
58
|
+
close
|
59
|
+
raise
|
60
|
+
end
|
61
|
+
|
62
|
+
def extract entry, flags = 0
|
63
|
+
raise ArgumentError, "Expected Archive::Entry as first argument" unless entry.kind_of? Entry
|
64
|
+
raise ArgumentError, "Expected Integer as second argument" unless entry.kind_of? Integer
|
65
|
+
|
66
|
+
flags &= EXTRACT_FLAGS
|
67
|
+
raise Error, @archive if C::archive_read_extract(archive, entry, flags) != C::OK
|
68
|
+
end
|
69
|
+
|
70
|
+
def header_position
|
71
|
+
raise Error, @archive if C::archive_read_header_position archive
|
72
|
+
end
|
73
|
+
|
74
|
+
def next_header
|
75
|
+
entry_ptr = FFI::MemoryPointer.new(:pointer)
|
76
|
+
case C::archive_read_next_header(archive, entry_ptr)
|
77
|
+
when C::OK
|
78
|
+
Entry.from_pointer entry_ptr.read_pointer
|
79
|
+
when C::EOF
|
80
|
+
@eof = true
|
81
|
+
nil
|
82
|
+
else
|
83
|
+
raise Error, @archive
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def each_entry
|
88
|
+
while entry = next_header
|
89
|
+
yield entry
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def each_entry_with_data( size = C::DATA_BUFFER_SIZE )
|
94
|
+
while entry = next_header
|
95
|
+
yield entry, read_data
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def read_data size = C::DATA_BUFFER_SIZE, &block
|
100
|
+
raise ArgumentError, "Buffer size must be > 0 (was: #{size})" unless size.kind_of?(Integer) and size > 0
|
101
|
+
|
102
|
+
data = nil
|
103
|
+
unless block
|
104
|
+
data = ""
|
105
|
+
block = data.method :concat
|
106
|
+
end
|
107
|
+
|
108
|
+
buffer = FFI::Buffer.alloc_out(size)
|
109
|
+
len = 0
|
110
|
+
while (n = C::archive_read_data(archive, buffer, size)) > 0
|
111
|
+
case n
|
112
|
+
when C::FATAL, C::WARN, C::RETRY
|
113
|
+
raise Error, @archive
|
114
|
+
else
|
115
|
+
block.call buffer.get_bytes(0,n)
|
116
|
+
end
|
117
|
+
len += n
|
118
|
+
end
|
119
|
+
|
120
|
+
data || len
|
121
|
+
end
|
122
|
+
|
123
|
+
def save_data file_name
|
124
|
+
IO.sysopen(file_name, "wb") do |fd|
|
125
|
+
raise Error, @archive if C::archive_read_data_into_fd(archive, fd) != C::OK
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'ffi-inliner'
|
2
|
+
|
3
|
+
module Archive
|
4
|
+
module Stat
|
5
|
+
extend Inliner
|
6
|
+
inline do |builder|
|
7
|
+
builder.include 'stdlib.h'
|
8
|
+
builder.include 'sys/types.h'
|
9
|
+
builder.include 'sys/stat.h'
|
10
|
+
builder.c %q{
|
11
|
+
void* ffi_libarchive_create_stat(const char* filename) {
|
12
|
+
struct stat* s = malloc(sizeof(struct stat));
|
13
|
+
if (stat(filename, s) != 0) return NULL;
|
14
|
+
return s;
|
15
|
+
}
|
16
|
+
}
|
17
|
+
builder.c %q{
|
18
|
+
void* ffi_libarchive_create_lstat(const char* filename) {
|
19
|
+
struct stat* s = malloc(sizeof(struct stat));
|
20
|
+
lstat(filename, s);
|
21
|
+
return s;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
builder.c %q{
|
25
|
+
void ffi_libarchive_free_stat(void* s) {
|
26
|
+
free((struct stat*)s);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Archive
|
2
|
+
|
3
|
+
# TODO: Remove this forward-declaration
|
4
|
+
class BaseArchive
|
5
|
+
end
|
6
|
+
|
7
|
+
class Writer < BaseArchive
|
8
|
+
|
9
|
+
private_class_method :new
|
10
|
+
|
11
|
+
def self.open_filename file_name, compression, format
|
12
|
+
if block_given?
|
13
|
+
writer = open_filename file_name, compression, format
|
14
|
+
begin
|
15
|
+
yield writer
|
16
|
+
ensure
|
17
|
+
writer.close
|
18
|
+
end
|
19
|
+
else
|
20
|
+
new :file_name => file_name, :compression => compression, :format => format
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.open_memory string, compression, format
|
25
|
+
if block_given?
|
26
|
+
writer = open_memory string, compression, format
|
27
|
+
begin
|
28
|
+
yield writer
|
29
|
+
ensure
|
30
|
+
writer.close
|
31
|
+
end
|
32
|
+
else
|
33
|
+
if compression.kind_of? String
|
34
|
+
command = compression
|
35
|
+
compression = -1
|
36
|
+
else
|
37
|
+
command = nil
|
38
|
+
end
|
39
|
+
new :memory => string, :compression => compression, :format => format
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize params = {}
|
44
|
+
super C::method(:archive_write_new), C::method(:archive_write_finish)
|
45
|
+
|
46
|
+
compression = params[:compression]
|
47
|
+
case compression
|
48
|
+
when Symbol
|
49
|
+
compression = Archive::const_get("COMPRESSION_#{compression.to_s.upcase}".intern)
|
50
|
+
end
|
51
|
+
|
52
|
+
format = params[:format]
|
53
|
+
case format
|
54
|
+
when Symbol
|
55
|
+
format = Archive::const_get("FORMAT_#{format.to_s.upcase}".intern)
|
56
|
+
end
|
57
|
+
|
58
|
+
raise Error, @archive if C::archive_write_set_compression(archive, compression) != C::OK
|
59
|
+
|
60
|
+
raise Error, @archive if C::archive_write_set_format(archive, format) != C::OK
|
61
|
+
|
62
|
+
if params[:file_name]
|
63
|
+
raise Error, @archive if C::archive_write_open_filename(archive, params[:file_name]) != C::OK
|
64
|
+
elsif params[:memory]
|
65
|
+
@data = write_callback params[:memory]
|
66
|
+
raise Error, @archive if C::archive_write_open(archive, nil,
|
67
|
+
method(:open_callback),
|
68
|
+
@data,
|
69
|
+
nil) != C::OK
|
70
|
+
end
|
71
|
+
rescue => e
|
72
|
+
close
|
73
|
+
raise
|
74
|
+
end
|
75
|
+
|
76
|
+
def open_callback archive, client
|
77
|
+
if C::archive_write_get_bytes_in_last_block(archive) == -1
|
78
|
+
C::archive_write_set_bytes_in_last_block(archive, 1)
|
79
|
+
end
|
80
|
+
C::OK
|
81
|
+
end
|
82
|
+
private :open_callback
|
83
|
+
|
84
|
+
def write_callback data
|
85
|
+
Proc.new { |ar, client, buffer, length|
|
86
|
+
data.concat buffer.get_bytes(0,length)
|
87
|
+
length
|
88
|
+
}
|
89
|
+
end
|
90
|
+
private :write_callback
|
91
|
+
|
92
|
+
def new_entry
|
93
|
+
entry = Entry.new
|
94
|
+
if block_given?
|
95
|
+
begin
|
96
|
+
result = yield entry
|
97
|
+
ensure
|
98
|
+
entry.close
|
99
|
+
end
|
100
|
+
result
|
101
|
+
else
|
102
|
+
entry
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def add_entry &block
|
107
|
+
raise ArgumentError, "No block given" unless block_given?
|
108
|
+
|
109
|
+
entry = Entry.new
|
110
|
+
data = yield entry
|
111
|
+
write_header entry
|
112
|
+
write_data data if data
|
113
|
+
ensure
|
114
|
+
entry.close
|
115
|
+
end
|
116
|
+
|
117
|
+
def write_data *args
|
118
|
+
if block_given?
|
119
|
+
raise ArgumentError, "wrong number of argument (#{args.size} for 0)" if args.size > 0
|
120
|
+
|
121
|
+
ar = archive
|
122
|
+
len = 0
|
123
|
+
while true do
|
124
|
+
str = yield
|
125
|
+
if ((n = C::archive_write_data(ar, str, str.size)) < 1)
|
126
|
+
return len
|
127
|
+
end
|
128
|
+
len += n
|
129
|
+
end
|
130
|
+
else
|
131
|
+
raise ArgumentError, "wrong number of argument (#{args.size}) for 1)" if args.size != 1
|
132
|
+
str = args[0]
|
133
|
+
C::archive_write_data(archive, str, str.size)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def write_header entry
|
138
|
+
raise Error, @archive if C::archive_write_header(archive, entry.entry) != C::OK
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
Binary file
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'ffi-libarchive'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class TS_ReadArchive < Test::Unit::TestCase
|
6
|
+
|
7
|
+
CONTENT_SPEC =
|
8
|
+
[
|
9
|
+
['test/', 'directory', 0755, nil ],
|
10
|
+
['test/b/', 'directory', 0755, nil ],
|
11
|
+
['test/b/c/', 'directory', 0755, nil ],
|
12
|
+
['test/b/c/c.dat', 'file', 0600, "\266\262\v_\266\243\305\3601\204\277\351\354\265\003\036\036\365f\377\210\205\032\222\346\370b\360u\032Y\301" ],
|
13
|
+
['test/b/c/d/', 'directory', 0711, nil ],
|
14
|
+
['test/b/c/d/d.dat', 'symbolic_link', 0777, "../c.dat" ],
|
15
|
+
['test/b/b.dat', 'file', 0640, "s&\245\354(M\331=\270\000!s\355\240\252\355'N\304\343\bY\317\t\274\210\3128\321\347\234!" ],
|
16
|
+
['test/a.dat', 'file', 0777, "\021\216\231Y\354\236\271\372\336\213\224R\211{D{\277\262\304\211xu\330\\\275@~\035\vSRM" ]
|
17
|
+
]
|
18
|
+
|
19
|
+
def setup
|
20
|
+
File.open('data/test.tar.gz', 'rb') do |f|
|
21
|
+
@archive_content = f.read
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def test_read_tar_gz_from_file
|
27
|
+
Archive.read_open_filename('data/test.tar.gz') do |ar|
|
28
|
+
verify_content(ar)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_read_tar_gz_from_file_with_external_gunzip
|
33
|
+
Archive.read_open_filename('data/test.tar.gz', 'gunzip') do |ar|
|
34
|
+
verify_content(ar)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_read_tar_gz_from_memory
|
39
|
+
Archive.read_open_memory(@archive_content) do |ar|
|
40
|
+
verify_content(ar)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_read_tar_gz_from_memory_with_external_gunzip
|
45
|
+
Archive.read_open_memory(@archive_content, 'gunzip') do |ar|
|
46
|
+
verify_content(ar)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_read_entry_bigger_than_internal_buffer
|
51
|
+
alphabet = "abcdefghijklmnopqrstuvwxyz"
|
52
|
+
entry_size = 1024 * 4 - 3
|
53
|
+
|
54
|
+
srand
|
55
|
+
content = ""
|
56
|
+
1.upto(entry_size) do |i|
|
57
|
+
index = rand(alphabet.size)
|
58
|
+
content += alphabet[index,1]
|
59
|
+
end
|
60
|
+
|
61
|
+
Dir.mktmpdir do |dir|
|
62
|
+
Archive.write_open_filename(dir + '/test.tar.gz',
|
63
|
+
Archive::COMPRESSION_BZIP2, Archive::FORMAT_TAR) do |ar|
|
64
|
+
ar.new_entry do |entry|
|
65
|
+
entry.pathname = "chubby.dat"
|
66
|
+
entry.mode = 0666
|
67
|
+
entry.filetype = Archive::Entry::FILE
|
68
|
+
entry.atime = Time.now.to_i
|
69
|
+
entry.mtime = Time.now.to_i
|
70
|
+
entry.size = entry_size
|
71
|
+
ar.write_header(entry)
|
72
|
+
ar.write_data(content)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
Archive.read_open_filename(dir + '/test.tar.gz') do |ar|
|
77
|
+
entry = ar.next_header
|
78
|
+
data = ar.read_data
|
79
|
+
|
80
|
+
assert_equal entry_size, data.size
|
81
|
+
assert_equal content.size, data.size
|
82
|
+
assert_equal content, data
|
83
|
+
end
|
84
|
+
|
85
|
+
Archive.read_open_filename(dir + '/test.tar.gz') do |ar|
|
86
|
+
entry = ar.next_header
|
87
|
+
data = ""
|
88
|
+
ar.read_data(128) { |chunk| data += chunk }
|
89
|
+
|
90
|
+
assert_equal content, data
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def verify_content(ar)
|
98
|
+
content_spec_idx = 0
|
99
|
+
|
100
|
+
while entry = ar.next_header
|
101
|
+
expect_pathname, expect_type, expect_mode, expect_content =\
|
102
|
+
CONTENT_SPEC[content_spec_idx]
|
103
|
+
|
104
|
+
assert_equal expect_pathname, entry.pathname
|
105
|
+
assert_equal entry.send("#{expect_type}?"), true
|
106
|
+
assert_equal expect_mode, (entry.mode & 07777)
|
107
|
+
|
108
|
+
if entry.symbolic_link?
|
109
|
+
assert_equal expect_content, entry.symlink
|
110
|
+
elsif entry.file?
|
111
|
+
content = ar.read_data(1024)
|
112
|
+
assert_equal expect_content, content
|
113
|
+
end
|
114
|
+
|
115
|
+
content_spec_idx += 1
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'ffi-libarchive'
|
2
|
+
require 'tmpdir'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
class TS_WriteArchive < Test::Unit::TestCase
|
6
|
+
|
7
|
+
CONTENT_SPEC =
|
8
|
+
[
|
9
|
+
['test/', 'directory', 0755, nil ],
|
10
|
+
['test/b/', 'directory', 0755, nil ],
|
11
|
+
['test/b/c/', 'directory', 0755, nil ],
|
12
|
+
['test/b/c/c.dat', 'file', 0600, "\266\262\v_\266\243\305\3601\204\277\351\354\265\003\036\036\365f\377\210\205\032\222\346\370b\360u\032Y\301" ],
|
13
|
+
['test/b/c/d/', 'directory', 0711, nil ],
|
14
|
+
['test/b/c/d/d.dat', 'symbolic_link', 0777, "../c.dat" ],
|
15
|
+
['test/b/b.dat', 'file', 0640, "s&\245\354(M\331=\270\000!s\355\240\252\355'N\304\343\bY\317\t\274\210\3128\321\347\234!" ],
|
16
|
+
['test/a.dat', 'file', 0777, "\021\216\231Y\354\236\271\372\336\213\224R\211{D{\277\262\304\211xu\330\\\275@~\035\vSRM" ]
|
17
|
+
]
|
18
|
+
|
19
|
+
def test_end_to_end_write_read_tar_gz
|
20
|
+
Dir.mktmpdir do |dir|
|
21
|
+
Archive.write_open_filename(dir + '/test.tar.gz', :gzip, :tar) do |ar|
|
22
|
+
write_content(ar)
|
23
|
+
end
|
24
|
+
|
25
|
+
verify_content(dir + '/test.tar.gz')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_end_to_end_write_read_memory
|
30
|
+
memory = ""
|
31
|
+
Archive.write_open_memory(memory, Archive::COMPRESSION_GZIP, Archive::FORMAT_TAR) do |ar|
|
32
|
+
write_content ar
|
33
|
+
end
|
34
|
+
verify_content_memory(memory)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_end_to_end_write_read_tar_gz_with_external_gzip
|
38
|
+
Dir.mktmpdir do |dir|
|
39
|
+
Archive.write_open_filename(dir + '/test.tar.gz', 'gzip', :tar) do |ar|
|
40
|
+
write_content(ar)
|
41
|
+
end
|
42
|
+
|
43
|
+
verify_content(dir + '/test.tar.gz')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_end_to_end_write_read_tar_gz
|
48
|
+
Dir.mktmpdir do |dir|
|
49
|
+
Archive.write_open_filename(dir + '/test.tar.gz', :gzip, :tar) do |ar|
|
50
|
+
write_content(ar)
|
51
|
+
end
|
52
|
+
|
53
|
+
verify_content(dir + '/test.tar.gz')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def write_content(ar)
|
60
|
+
content_spec_idx = 0
|
61
|
+
|
62
|
+
while content_spec_idx < CONTENT_SPEC.size()
|
63
|
+
entry_path, entry_type, entry_mode, entry_content = \
|
64
|
+
CONTENT_SPEC[content_spec_idx]
|
65
|
+
|
66
|
+
ar.new_entry do |entry|
|
67
|
+
entry.pathname = entry_path
|
68
|
+
entry.mode = entry_mode
|
69
|
+
entry.filetype = eval "Archive::Entry::#{entry_type.upcase}"
|
70
|
+
entry.size = entry_content.size if entry_content
|
71
|
+
entry.symlink = entry_content if entry_type == 'symbolic_link'
|
72
|
+
entry.atime = Time.now.to_i
|
73
|
+
entry.mtime = Time.now.to_i
|
74
|
+
ar.write_header(entry)
|
75
|
+
|
76
|
+
if entry_type == 'file'
|
77
|
+
ar.write_data(entry_content)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
content_spec_idx += 1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def verify_content_memory(memory)
|
86
|
+
Archive.read_open_memory(memory) do |ar|
|
87
|
+
content_spec_idx = 0
|
88
|
+
|
89
|
+
while entry = ar.next_header
|
90
|
+
expect_pathname, expect_type, expect_mode, expect_content =\
|
91
|
+
CONTENT_SPEC[content_spec_idx]
|
92
|
+
|
93
|
+
assert_equal expect_pathname, entry.pathname
|
94
|
+
assert_equal entry.send("#{expect_type}?"), true
|
95
|
+
assert_equal expect_mode, (entry.mode & 07777)
|
96
|
+
|
97
|
+
if entry.symbolic_link?
|
98
|
+
assert_equal expect_content, entry.symlink
|
99
|
+
elsif entry.file?
|
100
|
+
content = ar.read_data(1024)
|
101
|
+
assert_equal expect_content, content
|
102
|
+
end
|
103
|
+
|
104
|
+
content_spec_idx += 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def verify_content(filename)
|
110
|
+
Archive.read_open_filename(filename) do |ar|
|
111
|
+
content_spec_idx = 0
|
112
|
+
|
113
|
+
while entry = ar.next_header
|
114
|
+
expect_pathname, expect_type, expect_mode, expect_content =\
|
115
|
+
CONTENT_SPEC[content_spec_idx]
|
116
|
+
|
117
|
+
assert_equal expect_pathname, entry.pathname
|
118
|
+
assert_equal entry.send("#{expect_type}?"), true
|
119
|
+
assert_equal expect_mode, (entry.mode & 07777)
|
120
|
+
|
121
|
+
if entry.symbolic_link?
|
122
|
+
assert_equal expect_content, entry.symlink
|
123
|
+
elsif entry.file?
|
124
|
+
content = ar.read_data(1024)
|
125
|
+
assert_equal expect_content, content
|
126
|
+
end
|
127
|
+
|
128
|
+
content_spec_idx += 1
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|