archive_r_ruby 0.1.5 → 0.1.6
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 +4 -4
- data/LICENSE.txt +27 -7
- data/README.md +2 -2
- data/ext/archive_r/archive_r_ext.cc +5 -5
- data/ext/archive_r/extconf.rb +27 -22
- data/ext/archive_r/vendor/archive_r/LICENSE.txt +27 -7
- data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.cc +60 -66
- data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.h +18 -3
- data/ext/archive_r/vendor/archive_r/src/multi_volume_stream_base.cc +4 -4
- data/ext/archive_r/vendor/archive_r/src/system_file_stream.cc +7 -3
- data/ext/archive_r/vendor/archive_r/src/traverser.cc +0 -1
- data/lib/archive_r.rb +1 -1
- metadata +3 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c5c817b1729dcccb9268c75be4c2ce7fe8ca6a41e38421190d0028faa6223eaa
|
|
4
|
+
data.tar.gz: f6257d3a247d2abd5f88d149e09cd0d16a78623403b430c78f1e613db99f9b4d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b9076f2e8c632e23374174921c5862814348f8d64ca20405e3851101f798c15eaf56afef46339227b50b9a5da70ea40833ace51d3894435dc488a20cbe86cdb4
|
|
7
|
+
data.tar.gz: 9236f13270d0a46db84e592b0603817fc1b255c50d3ec80e7659d6c3eba02d7f6bcc457c303800a3c03d374e6209f4cf33a6c3e4857d0257989d9768e8bbf9b5
|
data/LICENSE.txt
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
archive_r License
|
|
2
|
-
Version: 0.1.
|
|
2
|
+
Version: 0.1.6 (2025-12-10)
|
|
3
3
|
|
|
4
4
|
----------------------------------------
|
|
5
5
|
Primary License
|
|
@@ -66,12 +66,32 @@ The following components are redistributed only because libarchive (bundled with
|
|
|
66
66
|
- Purpose: libarchive dependency providing Zstandard compression; shipped within archive_r binaries.
|
|
67
67
|
- License: BSD License (https://github.com/facebook/zstd)
|
|
68
68
|
|
|
69
|
-
8.
|
|
70
|
-
- Purpose: libarchive dependency providing cryptographic support
|
|
71
|
-
- License:
|
|
69
|
+
8. Nettle
|
|
70
|
+
- Purpose: libarchive dependency providing cryptographic support (macOS/Linux); bundled with archive_r binaries.
|
|
71
|
+
- License: GNU LGPLv3+ or GNU GPLv2+ (https://www.lysator.liu.se/~nisse/nettle/)
|
|
72
72
|
|
|
73
|
-
9.
|
|
74
|
-
- Purpose:
|
|
75
|
-
- License: GNU
|
|
73
|
+
9. mini-gmp
|
|
74
|
+
- Purpose: Nettle dependency for arithmetic operations (macOS/Linux); bundled with archive_r binaries.
|
|
75
|
+
- License: GNU LGPLv3+ or GNU GPLv2+ (https://gmplib.org/)
|
|
76
|
+
|
|
77
|
+
10. OpenSSL 3
|
|
78
|
+
- Purpose: libarchive dependency providing cryptographic support (Windows); bundled with archive_r binaries.
|
|
79
|
+
- License: Apache License 2.0 with OpenSSL exception (https://www.openssl.org/source/license.html)
|
|
80
|
+
|
|
81
|
+
11. lz4
|
|
82
|
+
- Purpose: libarchive dependency providing LZ4 compression; shipped with archive_r artifacts when required.
|
|
83
|
+
- License: BSD 2-Clause (https://github.com/lz4/lz4)
|
|
84
|
+
|
|
85
|
+
12. libb2 (BLAKE2)
|
|
86
|
+
- Purpose: libarchive dependency providing BLAKE2 hashing; bundled when archive formats require it.
|
|
87
|
+
- License: CC0 1.0 Universal (https://github.com/BLAKE2/libb2)
|
|
88
|
+
|
|
89
|
+
13. libattr
|
|
90
|
+
- Purpose: libarchive dependency providing extended attribute support on POSIX platforms; included in POSIX builds only.
|
|
91
|
+
- License: LGPL-2.1-or-later for the library (https://savannah.nongnu.org/projects/attr)
|
|
92
|
+
|
|
93
|
+
14. libacl
|
|
94
|
+
- Purpose: libarchive dependency providing POSIX ACL support; included in POSIX builds only.
|
|
95
|
+
- License: LGPL-2.1-or-later for the library (https://savannah.nongnu.org/projects/acl)
|
|
76
96
|
Users of archive_r should review the linked third-party licenses to ensure
|
|
77
97
|
compliance with their terms when redistributing this software.
|
data/README.md
CHANGED
|
@@ -37,9 +37,9 @@ bundle exec rake build # creates archive_r-<version>.gem locally
|
|
|
37
37
|
|
|
38
38
|
The `rake test` task compiles the extension, installs it into `lib/`, and executes the Minitest suite.
|
|
39
39
|
|
|
40
|
-
## Running the
|
|
40
|
+
## Running the repository test suite
|
|
41
41
|
|
|
42
|
-
`./
|
|
42
|
+
From the repository root run `./bindings/ruby/run_binding_tests.sh`. The script prepares a clean GEM_HOME (`build/ruby_gem_home`), installs the gem produced in `build/bindings/ruby`, runs `bindings/ruby/test/test_traverser.rb`, and saves the install log to `build/logs/ruby_gem_install.log`. CI invokes this script after the core tests.
|
|
43
43
|
|
|
44
44
|
## Usage Example
|
|
45
45
|
|
|
@@ -118,7 +118,7 @@ public:
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
~RubyUserStream() override {
|
|
121
|
-
|
|
121
|
+
release_active_io_resources(false);
|
|
122
122
|
rb_gc_unregister_address(&_ruby_stream);
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -140,7 +140,7 @@ protected:
|
|
|
140
140
|
|
|
141
141
|
void close_single_part() override {
|
|
142
142
|
if (_has_open_part_io) {
|
|
143
|
-
|
|
143
|
+
release_active_io_resources(true);
|
|
144
144
|
if (_has_close_part_io) {
|
|
145
145
|
rb_funcall(_ruby_stream, rb_id_close_part_io_method, 0);
|
|
146
146
|
}
|
|
@@ -250,7 +250,7 @@ private:
|
|
|
250
250
|
if (!rb_respond_to(io, rb_id_read_method)) {
|
|
251
251
|
rb_raise(rb_eTypeError, "open_part_io must return an object responding to #read");
|
|
252
252
|
}
|
|
253
|
-
|
|
253
|
+
release_active_io_resources(true);
|
|
254
254
|
_active_io = io;
|
|
255
255
|
rb_gc_register_address(&_active_io);
|
|
256
256
|
_active_io_seekable = rb_respond_to(io, rb_id_seek_method);
|
|
@@ -259,11 +259,11 @@ private:
|
|
|
259
259
|
_active_io_has_size = rb_respond_to(io, rb_id_size_method);
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
void
|
|
262
|
+
void release_active_io_resources(bool close_io) {
|
|
263
263
|
if (_active_io == Qnil) {
|
|
264
264
|
return;
|
|
265
265
|
}
|
|
266
|
-
if (_active_io_has_close) {
|
|
266
|
+
if (close_io && _active_io_has_close) {
|
|
267
267
|
rb_funcall(_active_io, rb_id_close_method, 0);
|
|
268
268
|
}
|
|
269
269
|
rb_gc_unregister_address(&_active_io);
|
data/ext/archive_r/extconf.rb
CHANGED
|
@@ -46,6 +46,7 @@ end
|
|
|
46
46
|
archive_r_include = File.join(archive_r_root, 'include')
|
|
47
47
|
archive_r_src = File.join(archive_r_root, 'src')
|
|
48
48
|
archive_r_lib_dir = File.join(archive_r_root, 'build')
|
|
49
|
+
archive_r_local_libs = File.expand_path('.libs', __dir__)
|
|
49
50
|
glue_source = File.join(__dir__, 'archive_r_ext.cc')
|
|
50
51
|
|
|
51
52
|
# Ensure make can locate vendored sources via VPATH
|
|
@@ -58,6 +59,11 @@ $VPATH << archive_r_src
|
|
|
58
59
|
# Add include paths
|
|
59
60
|
$INCFLAGS << " -I#{archive_r_include}"
|
|
60
61
|
$INCFLAGS << " -I#{archive_r_src}"
|
|
62
|
+
$LIBPATH.unshift(archive_r_local_libs)
|
|
63
|
+
|
|
64
|
+
unless Gem.win_platform?
|
|
65
|
+
$LDFLAGS << ' -Wl,-rpath,$ORIGIN/.libs'
|
|
66
|
+
end
|
|
61
67
|
|
|
62
68
|
# C++17 standard
|
|
63
69
|
$CXXFLAGS << " -std=c++17"
|
|
@@ -82,31 +88,30 @@ if ENV['LIBARCHIVE_LIBRARY_DIRS']
|
|
|
82
88
|
end
|
|
83
89
|
|
|
84
90
|
# Check for libarchive
|
|
85
|
-
unless have_library('archive')
|
|
86
|
-
|
|
87
|
-
unless have_library('archive_static') || have_library('libarchive')
|
|
88
|
-
abort "libarchive is required but not found"
|
|
89
|
-
end
|
|
91
|
+
unless have_library('archive') || have_library('libarchive')
|
|
92
|
+
abort "libarchive is required but not found"
|
|
90
93
|
end
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
95
|
+
shared_candidates = [
|
|
96
|
+
File.join(archive_r_lib_dir, 'libarchive_r_core.so'),
|
|
97
|
+
File.join(archive_r_lib_dir, 'libarchive_r_core.dylib'),
|
|
98
|
+
File.join(archive_r_lib_dir, 'archive_r_core.dll'),
|
|
99
|
+
File.join(archive_r_lib_dir, 'archive_r_core.lib'),
|
|
100
|
+
File.join(archive_r_lib_dir, 'Release', 'archive_r_core.dll'),
|
|
101
|
+
File.join(archive_r_lib_dir, 'Release', 'archive_r_core.lib'),
|
|
102
|
+
File.join(archive_r_local_libs, 'libarchive_r_core.so'),
|
|
103
|
+
File.join(archive_r_local_libs, 'libarchive_r_core.dylib'),
|
|
104
|
+
File.join(archive_r_local_libs, 'archive_r_core.dll'),
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
found_shared = shared_candidates.find { |path| File.exist?(path) }
|
|
108
|
+
|
|
109
|
+
if found_shared
|
|
110
|
+
$LIBPATH.unshift(File.dirname(found_shared))
|
|
111
|
+
$libs = "-larchive_r_core #{$libs}"
|
|
112
|
+
puts "Using pre-built shared archive_r core: #{found_shared}"
|
|
106
113
|
else
|
|
107
|
-
|
|
108
|
-
puts "Pre-built library not found, will build from source"
|
|
109
|
-
|
|
114
|
+
puts "Pre-built shared library not found, will build from source"
|
|
110
115
|
srcs = [glue_source] + Dir.glob(File.join(archive_r_src, '*.cc'))
|
|
111
116
|
$srcs = srcs
|
|
112
117
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
archive_r License
|
|
2
|
-
Version: 0.1.
|
|
2
|
+
Version: 0.1.6 (2025-12-10)
|
|
3
3
|
|
|
4
4
|
----------------------------------------
|
|
5
5
|
Primary License
|
|
@@ -66,12 +66,32 @@ The following components are redistributed only because libarchive (bundled with
|
|
|
66
66
|
- Purpose: libarchive dependency providing Zstandard compression; shipped within archive_r binaries.
|
|
67
67
|
- License: BSD License (https://github.com/facebook/zstd)
|
|
68
68
|
|
|
69
|
-
8.
|
|
70
|
-
- Purpose: libarchive dependency providing cryptographic support
|
|
71
|
-
- License:
|
|
69
|
+
8. Nettle
|
|
70
|
+
- Purpose: libarchive dependency providing cryptographic support (macOS/Linux); bundled with archive_r binaries.
|
|
71
|
+
- License: GNU LGPLv3+ or GNU GPLv2+ (https://www.lysator.liu.se/~nisse/nettle/)
|
|
72
72
|
|
|
73
|
-
9.
|
|
74
|
-
- Purpose:
|
|
75
|
-
- License: GNU
|
|
73
|
+
9. mini-gmp
|
|
74
|
+
- Purpose: Nettle dependency for arithmetic operations (macOS/Linux); bundled with archive_r binaries.
|
|
75
|
+
- License: GNU LGPLv3+ or GNU GPLv2+ (https://gmplib.org/)
|
|
76
|
+
|
|
77
|
+
10. OpenSSL 3
|
|
78
|
+
- Purpose: libarchive dependency providing cryptographic support (Windows); bundled with archive_r binaries.
|
|
79
|
+
- License: Apache License 2.0 with OpenSSL exception (https://www.openssl.org/source/license.html)
|
|
80
|
+
|
|
81
|
+
11. lz4
|
|
82
|
+
- Purpose: libarchive dependency providing LZ4 compression; shipped with archive_r artifacts when required.
|
|
83
|
+
- License: BSD 2-Clause (https://github.com/lz4/lz4)
|
|
84
|
+
|
|
85
|
+
12. libb2 (BLAKE2)
|
|
86
|
+
- Purpose: libarchive dependency providing BLAKE2 hashing; bundled when archive formats require it.
|
|
87
|
+
- License: CC0 1.0 Universal (https://github.com/BLAKE2/libb2)
|
|
88
|
+
|
|
89
|
+
13. libattr
|
|
90
|
+
- Purpose: libarchive dependency providing extended attribute support on POSIX platforms; included in POSIX builds only.
|
|
91
|
+
- License: LGPL-2.1-or-later for the library (https://savannah.nongnu.org/projects/attr)
|
|
92
|
+
|
|
93
|
+
14. libacl
|
|
94
|
+
- Purpose: libarchive dependency providing POSIX ACL support; included in POSIX builds only.
|
|
95
|
+
- License: LGPL-2.1-or-later for the library (https://savannah.nongnu.org/projects/acl)
|
|
76
96
|
Users of archive_r should review the linked third-party licenses to ensure
|
|
77
97
|
compliance with their terms when redistributing this software.
|
|
@@ -60,6 +60,11 @@ void StreamArchive::rewind() {
|
|
|
60
60
|
|
|
61
61
|
PathHierarchy StreamArchive::source_hierarchy() const { return _stream->source_hierarchy(); }
|
|
62
62
|
|
|
63
|
+
std::shared_ptr<StreamArchive> StreamArchive::parent_archive() const {
|
|
64
|
+
auto entry_stream = std::dynamic_pointer_cast<EntryPayloadStream>(_stream);
|
|
65
|
+
return entry_stream ? entry_stream->parent_archive() : nullptr;
|
|
66
|
+
}
|
|
67
|
+
|
|
63
68
|
la_ssize_t StreamArchive::read_callback_bridge(struct archive *a, void *client_data, const void **buff) {
|
|
64
69
|
auto *archive = static_cast<StreamArchive *>(client_data);
|
|
65
70
|
|
|
@@ -120,7 +125,9 @@ EntryPayloadStream::EntryPayloadStream(std::shared_ptr<StreamArchive> parent_arc
|
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
|
|
123
|
-
EntryPayloadStream::~EntryPayloadStream()
|
|
128
|
+
EntryPayloadStream::~EntryPayloadStream() {
|
|
129
|
+
deactivate_active_part();
|
|
130
|
+
}
|
|
124
131
|
|
|
125
132
|
std::shared_ptr<StreamArchive> EntryPayloadStream::parent_archive() const { return _parent_archive; }
|
|
126
133
|
|
|
@@ -143,11 +150,8 @@ void EntryPayloadStream::open_single_part(const PathHierarchy &single_part) {
|
|
|
143
150
|
}
|
|
144
151
|
|
|
145
152
|
void EntryPayloadStream::close_single_part() {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
_parent_archive->skip_data();
|
|
153
|
+
// libarchive automatically skips unread data when reading the next header,
|
|
154
|
+
// so explicit skipping here is unnecessary and avoids potential exceptions in destructor.
|
|
151
155
|
}
|
|
152
156
|
|
|
153
157
|
ssize_t EntryPayloadStream::read_from_single_part(void *buffer, size_t size) {
|
|
@@ -170,7 +174,8 @@ int64_t EntryPayloadStream::size_of_single_part(const PathHierarchy &single_part
|
|
|
170
174
|
|
|
171
175
|
ArchiveStackCursor::ArchiveStackCursor()
|
|
172
176
|
: options_snapshot()
|
|
173
|
-
,
|
|
177
|
+
, _current_stream(nullptr)
|
|
178
|
+
, _current_archive(nullptr) {}
|
|
174
179
|
|
|
175
180
|
void ArchiveStackCursor::configure(const ArchiveOption &options) {
|
|
176
181
|
options_snapshot = options;
|
|
@@ -178,16 +183,16 @@ void ArchiveStackCursor::configure(const ArchiveOption &options) {
|
|
|
178
183
|
|
|
179
184
|
void ArchiveStackCursor::reset() {
|
|
180
185
|
options_snapshot = ArchiveOption{};
|
|
181
|
-
|
|
186
|
+
_current_stream = nullptr;
|
|
187
|
+
_current_archive = nullptr;
|
|
182
188
|
}
|
|
183
189
|
|
|
184
190
|
bool ArchiveStackCursor::descend() {
|
|
185
|
-
if (
|
|
186
|
-
throw std::logic_error("stream
|
|
191
|
+
if (!_current_stream) {
|
|
192
|
+
throw std::logic_error("current stream is empty");
|
|
187
193
|
}
|
|
188
194
|
|
|
189
|
-
auto stream =
|
|
190
|
-
|
|
195
|
+
auto stream = _current_stream;
|
|
191
196
|
if (auto *archive = current_archive()) {
|
|
192
197
|
if (stream && !archive->current_entry_content_ready()) {
|
|
193
198
|
stream->rewind();
|
|
@@ -196,17 +201,22 @@ bool ArchiveStackCursor::descend() {
|
|
|
196
201
|
|
|
197
202
|
PathHierarchy dummy_hierarchy = stream->source_hierarchy();
|
|
198
203
|
auto archive_ptr = std::make_shared<StreamArchive>(std::move(stream), options_snapshot);
|
|
199
|
-
|
|
200
|
-
|
|
204
|
+
_current_archive = archive_ptr;
|
|
205
|
+
_current_stream = nullptr;
|
|
201
206
|
return true;
|
|
202
207
|
}
|
|
203
208
|
|
|
204
209
|
bool ArchiveStackCursor::ascend() {
|
|
205
|
-
if (
|
|
210
|
+
if (depth() <= 0) {
|
|
206
211
|
return false;
|
|
207
212
|
}
|
|
208
213
|
|
|
209
|
-
|
|
214
|
+
if (_current_archive) {
|
|
215
|
+
_current_stream = _current_archive->get_stream();
|
|
216
|
+
_current_archive = _current_archive->parent_archive();
|
|
217
|
+
} else {
|
|
218
|
+
_current_stream = nullptr;
|
|
219
|
+
}
|
|
210
220
|
|
|
211
221
|
return true;
|
|
212
222
|
}
|
|
@@ -217,6 +227,8 @@ bool ArchiveStackCursor::next() {
|
|
|
217
227
|
return false;
|
|
218
228
|
}
|
|
219
229
|
|
|
230
|
+
_current_stream = nullptr;
|
|
231
|
+
|
|
220
232
|
while (true) {
|
|
221
233
|
if (!archive->skip_to_next_header()) {
|
|
222
234
|
return false;
|
|
@@ -225,7 +237,8 @@ bool ArchiveStackCursor::next() {
|
|
|
225
237
|
break;
|
|
226
238
|
}
|
|
227
239
|
}
|
|
228
|
-
|
|
240
|
+
|
|
241
|
+
_current_stream = create_stream(current_entry_hierarchy());
|
|
229
242
|
return true;
|
|
230
243
|
}
|
|
231
244
|
|
|
@@ -233,33 +246,32 @@ bool ArchiveStackCursor::synchronize_to_hierarchy(const PathHierarchy &target_hi
|
|
|
233
246
|
if (target_hierarchy.empty()) {
|
|
234
247
|
throw_entry_fault("target hierarchy cannot be empty", {});
|
|
235
248
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
249
|
+
|
|
250
|
+
// 1. Ascend until we find a common ancestor
|
|
251
|
+
while (depth() > 0) {
|
|
252
|
+
auto current_h = _current_archive->source_hierarchy();
|
|
253
|
+
if (current_h.size() <= target_hierarchy.size() &&
|
|
254
|
+
hierarchies_equal(current_h, pathhierarchy_prefix_until(target_hierarchy, current_h.size() - 1))) {
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
ascend();
|
|
240
258
|
}
|
|
241
|
-
for (size_t depth = 0; depth < target_hierarchy.size(); ++depth) {
|
|
242
|
-
auto prefix = pathhierarchy_prefix_until(target_hierarchy, depth);
|
|
243
|
-
auto stream = stream_stack[depth];
|
|
244
259
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
260
|
+
// 2. Descend to target
|
|
261
|
+
for (size_t d = depth(); d < target_hierarchy.size(); ++d) {
|
|
262
|
+
auto prefix = pathhierarchy_prefix_until(target_hierarchy, d);
|
|
263
|
+
|
|
264
|
+
if (!_current_stream || !hierarchies_equal(_current_stream->source_hierarchy(), prefix)) {
|
|
265
|
+
_current_stream = create_stream(prefix);
|
|
266
|
+
_current_stream->rewind();
|
|
248
267
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
stream_stack.back() = stream;
|
|
253
|
-
stream->rewind();
|
|
254
|
-
|
|
255
|
-
if (depth == last_depth) {
|
|
256
|
-
return true;
|
|
268
|
+
|
|
269
|
+
if (d < target_hierarchy.size() - 1) {
|
|
270
|
+
descend();
|
|
257
271
|
}
|
|
258
|
-
// Descend into the archive for the next level of the hierarchy.
|
|
259
|
-
descend();
|
|
260
272
|
}
|
|
261
|
-
|
|
262
|
-
|
|
273
|
+
|
|
274
|
+
return true;
|
|
263
275
|
}
|
|
264
276
|
|
|
265
277
|
ssize_t ArchiveStackCursor::read(void *buff, size_t len) {
|
|
@@ -267,38 +279,22 @@ ssize_t ArchiveStackCursor::read(void *buff, size_t len) {
|
|
|
267
279
|
return 0;
|
|
268
280
|
}
|
|
269
281
|
|
|
270
|
-
if (
|
|
271
|
-
|
|
282
|
+
if (StreamArchive *archive = current_archive()) {
|
|
283
|
+
return archive->read_current(buff, len);
|
|
272
284
|
}
|
|
273
285
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
bytes = stream->read(buff, len);
|
|
277
|
-
|
|
278
|
-
if (bytes < 0) {
|
|
279
|
-
const std::string message = "Failed to read from active stream";
|
|
280
|
-
throw_entry_fault(message, current_entry_hierarchy());
|
|
286
|
+
if (_current_stream) {
|
|
287
|
+
return _current_stream->read(buff, len);
|
|
281
288
|
}
|
|
282
|
-
|
|
283
|
-
return bytes;
|
|
289
|
+
return 0;
|
|
284
290
|
}
|
|
285
291
|
|
|
286
292
|
StreamArchive *ArchiveStackCursor::current_archive() {
|
|
287
|
-
|
|
288
|
-
return nullptr;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const auto stream = std::dynamic_pointer_cast<EntryPayloadStream>(stream_stack.back());
|
|
292
|
-
if (!stream) {
|
|
293
|
-
return nullptr;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
auto parent_archive = stream->parent_archive();
|
|
297
|
-
return parent_archive ? parent_archive.get() : nullptr;
|
|
293
|
+
return _current_archive.get();
|
|
298
294
|
}
|
|
299
295
|
|
|
300
296
|
PathHierarchy ArchiveStackCursor::current_entry_hierarchy() {
|
|
301
|
-
if (
|
|
297
|
+
if (depth() == 0 || (!_current_stream && !_current_archive)) {
|
|
302
298
|
return {};
|
|
303
299
|
}
|
|
304
300
|
|
|
@@ -310,7 +306,7 @@ PathHierarchy ArchiveStackCursor::current_entry_hierarchy() {
|
|
|
310
306
|
return path;
|
|
311
307
|
}
|
|
312
308
|
|
|
313
|
-
return
|
|
309
|
+
return _current_stream->source_hierarchy();
|
|
314
310
|
}
|
|
315
311
|
|
|
316
312
|
std::shared_ptr<IDataStream> ArchiveStackCursor::create_stream(const PathHierarchy &hierarchy) {
|
|
@@ -322,9 +318,7 @@ std::shared_ptr<IDataStream> ArchiveStackCursor::create_stream(const PathHierarc
|
|
|
322
318
|
}
|
|
323
319
|
return std::make_shared<SystemFileStream>(hierarchy);
|
|
324
320
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
return std::make_shared<EntryPayloadStream>(stream->parent_archive(), hierarchy);
|
|
321
|
+
return std::make_shared<EntryPayloadStream>(_current_archive, hierarchy);
|
|
328
322
|
}
|
|
329
323
|
|
|
330
324
|
} // namespace archive_r
|
|
@@ -31,6 +31,9 @@ public:
|
|
|
31
31
|
void rewind() override;
|
|
32
32
|
|
|
33
33
|
PathHierarchy source_hierarchy() const;
|
|
34
|
+
std::shared_ptr<StreamArchive> parent_archive() const;
|
|
35
|
+
|
|
36
|
+
std::shared_ptr<IDataStream> get_stream() const { return _stream; }
|
|
34
37
|
|
|
35
38
|
private:
|
|
36
39
|
static la_ssize_t read_callback_bridge(struct archive *a, void *client_data, const void **buff);
|
|
@@ -75,7 +78,7 @@ struct ArchiveStackCursor {
|
|
|
75
78
|
|
|
76
79
|
void configure(const ArchiveOption &options);
|
|
77
80
|
void reset();
|
|
78
|
-
bool has_stream() const { return
|
|
81
|
+
bool has_stream() const { return _current_stream != nullptr; }
|
|
79
82
|
|
|
80
83
|
bool descend();
|
|
81
84
|
bool ascend();
|
|
@@ -83,7 +86,16 @@ struct ArchiveStackCursor {
|
|
|
83
86
|
bool synchronize_to_hierarchy(const PathHierarchy &hierarchy);
|
|
84
87
|
ssize_t read(void *buffer, size_t len);
|
|
85
88
|
|
|
86
|
-
size_t depth() const {
|
|
89
|
+
size_t depth() const {
|
|
90
|
+
size_t d = 0;
|
|
91
|
+
auto a = _current_archive;
|
|
92
|
+
while (a) {
|
|
93
|
+
d++;
|
|
94
|
+
a = a->parent_archive();
|
|
95
|
+
}
|
|
96
|
+
return d;
|
|
97
|
+
}
|
|
98
|
+
|
|
87
99
|
StreamArchive *current_archive();
|
|
88
100
|
|
|
89
101
|
PathHierarchy current_entry_hierarchy();
|
|
@@ -91,7 +103,10 @@ struct ArchiveStackCursor {
|
|
|
91
103
|
std::shared_ptr<IDataStream> create_stream(const PathHierarchy &hierarchy);
|
|
92
104
|
|
|
93
105
|
ArchiveOption options_snapshot;
|
|
94
|
-
|
|
106
|
+
|
|
107
|
+
private:
|
|
108
|
+
std::shared_ptr<IDataStream> _current_stream;
|
|
109
|
+
std::shared_ptr<StreamArchive> _current_archive;
|
|
95
110
|
};
|
|
96
111
|
|
|
97
112
|
} // namespace archive_r
|
|
@@ -20,6 +20,7 @@ struct MultiVolumeStreamBase::Impl {
|
|
|
20
20
|
std::vector<int64_t> part_offsets;
|
|
21
21
|
std::size_t total_parts = 0;
|
|
22
22
|
std::size_t active_part_index = 0;
|
|
23
|
+
std::size_t open_part_index = 0;
|
|
23
24
|
bool part_open = false;
|
|
24
25
|
int64_t logical_offset = 0;
|
|
25
26
|
int64_t total_size = -1;
|
|
@@ -84,7 +85,7 @@ void MultiVolumeStreamBase::rewind() {
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
bool MultiVolumeStreamBase::at_end() const {
|
|
87
|
-
return
|
|
88
|
+
return _impl->active_part_index >= _impl->total_parts;
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
|
|
@@ -122,14 +123,14 @@ int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
|
|
|
122
123
|
int64_t MultiVolumeStreamBase::tell() const { return _impl->logical_offset; }
|
|
123
124
|
|
|
124
125
|
void MultiVolumeStreamBase::Impl::ensure_part_active(std::size_t part_index) {
|
|
125
|
-
if (part_open &&
|
|
126
|
+
if (part_open && open_part_index == part_index) {
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
self.deactivate_active_part();
|
|
130
131
|
PathHierarchy single_part = pathhierarchy_select_single_part(self._logical_path, part_index);
|
|
131
132
|
self.open_single_part(single_part);
|
|
132
|
-
|
|
133
|
+
open_part_index = part_index;
|
|
133
134
|
part_open = true;
|
|
134
135
|
}
|
|
135
136
|
|
|
@@ -144,7 +145,6 @@ bool MultiVolumeStreamBase::Impl::advance_to_next_part() {
|
|
|
144
145
|
if (active_part_index >= total_parts) {
|
|
145
146
|
return false;
|
|
146
147
|
}
|
|
147
|
-
self.deactivate_active_part();
|
|
148
148
|
++active_part_index;
|
|
149
149
|
return active_part_index < total_parts;
|
|
150
150
|
}
|
|
@@ -78,7 +78,9 @@ SystemFileStream::SystemFileStream(PathHierarchy logical_path)
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
SystemFileStream::~SystemFileStream()
|
|
81
|
+
SystemFileStream::~SystemFileStream() {
|
|
82
|
+
deactivate_active_part();
|
|
83
|
+
}
|
|
82
84
|
|
|
83
85
|
void SystemFileStream::open_single_part(const PathHierarchy &single_part) {
|
|
84
86
|
const PathEntry &entry = single_part.back();
|
|
@@ -104,8 +106,10 @@ void SystemFileStream::open_single_part(const PathHierarchy &single_part) {
|
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
void SystemFileStream::close_single_part() {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
if (_handle) {
|
|
110
|
+
std::fclose(_handle);
|
|
111
|
+
_handle = nullptr;
|
|
112
|
+
}
|
|
109
113
|
_active_path.clear();
|
|
110
114
|
}
|
|
111
115
|
|
data/lib/archive_r.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: archive_r_ruby
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- raizo.tcs
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rake
|
|
@@ -91,7 +90,6 @@ metadata:
|
|
|
91
90
|
source_code_uri: https://github.com/raizo-tcs/archive_r
|
|
92
91
|
bug_tracker_uri: https://github.com/raizo-tcs/archive_r/issues
|
|
93
92
|
changelog_uri: https://github.com/raizo-tcs/archive_r/releases
|
|
94
|
-
post_install_message:
|
|
95
93
|
rdoc_options: []
|
|
96
94
|
require_paths:
|
|
97
95
|
- lib
|
|
@@ -106,8 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
106
104
|
- !ruby/object:Gem::Version
|
|
107
105
|
version: '0'
|
|
108
106
|
requirements: []
|
|
109
|
-
rubygems_version:
|
|
110
|
-
signing_key:
|
|
107
|
+
rubygems_version: 4.0.0
|
|
111
108
|
specification_version: 4
|
|
112
109
|
summary: Ruby bindings for archive_r that traverse nested archives without temp extraction
|
|
113
110
|
test_files: []
|