archive_r_ruby 0.1.8 → 0.1.9
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/VERSION +1 -0
- data/ext/archive_r/archive_r_ext.cc +6 -8
- data/ext/archive_r/vendor/archive_r/include/archive_r/data_stream.h +2 -2
- data/ext/archive_r/vendor/archive_r/include/archive_r/entry.h +8 -8
- data/ext/archive_r/vendor/archive_r/include/archive_r/multi_volume_stream_base.h +2 -2
- data/ext/archive_r/vendor/archive_r/include/archive_r/path_hierarchy_utils.h +0 -1
- data/ext/archive_r/vendor/archive_r/include/archive_r/platform_compat.h +8 -8
- data/ext/archive_r/vendor/archive_r/include/archive_r/traverser.h +2 -2
- data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.cc +10 -34
- data/ext/archive_r/vendor/archive_r/src/archive_stack_cursor.h +1 -3
- data/ext/archive_r/vendor/archive_r/src/archive_stack_orchestrator.cc +4 -5
- data/ext/archive_r/vendor/archive_r/src/archive_stack_orchestrator.h +1 -1
- data/ext/archive_r/vendor/archive_r/src/archive_type.cc +4 -13
- data/ext/archive_r/vendor/archive_r/src/archive_type.h +2 -2
- data/ext/archive_r/vendor/archive_r/src/entry.cc +2 -17
- data/ext/archive_r/vendor/archive_r/src/entry_fault_error.cc +23 -23
- data/ext/archive_r/vendor/archive_r/src/entry_impl.h +1 -2
- data/ext/archive_r/vendor/archive_r/src/multi_volume_manager.cc +3 -8
- data/ext/archive_r/vendor/archive_r/src/multi_volume_manager.h +2 -4
- data/ext/archive_r/vendor/archive_r/src/multi_volume_stream_base.cc +23 -14
- data/ext/archive_r/vendor/archive_r/src/path_hierarchy.cc +1 -4
- data/ext/archive_r/vendor/archive_r/src/path_hierarchy_utils.cc +14 -36
- data/ext/archive_r/vendor/archive_r/src/simple_profiler.h +64 -75
- data/ext/archive_r/vendor/archive_r/src/system_file_stream.cc +13 -26
- data/ext/archive_r/vendor/archive_r/src/system_file_stream.h +2 -2
- data/ext/archive_r/vendor/archive_r/src/traverser.cc +17 -41
- data/lib/archive_r.rb +5 -1
- metadata +7 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a67077047d1881a2760f1e04788746c09f7476ac86543d0edf506446f3c95d27
|
|
4
|
+
data.tar.gz: 7c9c88796f1382285ff08cbcc2e61e59cbe517ef81d72eb7d41ef2c20ddb438a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a5129e0027a2f4bd1d9bf99f98589f9713408deb0a3ebf207101af4ea25b371ee81396579396590e6b659187967a84fb967d9cbc5dae6cf167eeb3f4345b43ed
|
|
7
|
+
data.tar.gz: 118cb09083a9ca57fa4a90ad719a16178bcdd4d5f7926892f31c5849a9af0e40487dfe1d4f6bdaee61c684d942db3b3c43195fcee7d510ddcf0ed5b8f34a1f00
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.1.9
|
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
#ifdef memcpy
|
|
16
16
|
#undef memcpy
|
|
17
17
|
#endif
|
|
18
|
+
#include <limits>
|
|
19
|
+
#include <optional>
|
|
18
20
|
#include <stdexcept>
|
|
19
21
|
#include <string>
|
|
20
22
|
#include <utility>
|
|
21
23
|
#include <variant>
|
|
22
24
|
#include <vector>
|
|
23
|
-
#include <limits>
|
|
24
|
-
#include <optional>
|
|
25
25
|
|
|
26
26
|
using namespace archive_r;
|
|
27
27
|
|
|
@@ -295,16 +295,14 @@ static void stream_wrapper_free(void *ptr) {
|
|
|
295
295
|
delete wrapper;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
-
static size_t stream_wrapper_memsize(const void *ptr) {
|
|
299
|
-
return sizeof(RubyStreamWrapper);
|
|
300
|
-
}
|
|
298
|
+
static size_t stream_wrapper_memsize(const void *ptr) { return sizeof(RubyStreamWrapper); }
|
|
301
299
|
|
|
302
300
|
static const rb_data_type_t stream_wrapper_type = {
|
|
303
301
|
"ArchiveR::Stream",
|
|
304
302
|
{
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
303
|
+
nullptr,
|
|
304
|
+
stream_wrapper_free,
|
|
305
|
+
stream_wrapper_memsize,
|
|
308
306
|
},
|
|
309
307
|
nullptr,
|
|
310
308
|
nullptr,
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
#pragma once
|
|
5
5
|
|
|
6
|
-
#include "archive_r/platform_compat.h"
|
|
7
6
|
#include "archive_r/path_hierarchy.h"
|
|
7
|
+
#include "archive_r/platform_compat.h"
|
|
8
8
|
|
|
9
|
+
#include <cstdint>
|
|
9
10
|
#include <functional>
|
|
10
11
|
#include <memory>
|
|
11
|
-
#include <cstdint>
|
|
12
12
|
|
|
13
13
|
namespace archive_r {
|
|
14
14
|
|
|
@@ -97,8 +97,8 @@ public:
|
|
|
97
97
|
/**
|
|
98
98
|
* @brief Read data from the entry
|
|
99
99
|
*
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
* Each call uses an internal ArchiveStackOrchestrator so reads remain valid even
|
|
101
|
+
* if the owning iterator advances.
|
|
102
102
|
*
|
|
103
103
|
* @param buffer Buffer to read data into
|
|
104
104
|
* @param length Maximum number of bytes to read
|
|
@@ -109,9 +109,9 @@ public:
|
|
|
109
109
|
/**
|
|
110
110
|
* @brief Enable or disable automatic descent into this entry
|
|
111
111
|
* @param enabled true to descend (default), false to keep traversal at current level
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
*
|
|
113
|
+
* This control is only available for entries that are managed by a Traverser.
|
|
114
|
+
* Calling this on an Entry that is not traverser-managed reports a fault.
|
|
115
115
|
*/
|
|
116
116
|
void set_descent(bool enabled);
|
|
117
117
|
|
|
@@ -139,9 +139,9 @@ public:
|
|
|
139
139
|
* }
|
|
140
140
|
* }
|
|
141
141
|
* @endcode
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
*
|
|
143
|
+
* This control is only available for entries that are managed by a Traverser.
|
|
144
|
+
* Calling this on an Entry that is not traverser-managed reports a fault.
|
|
145
145
|
*/
|
|
146
146
|
void set_multi_volume_group(const std::string &base_name, const MultiVolumeGroupOptions &options = {});
|
|
147
147
|
|
|
@@ -30,8 +30,8 @@ protected:
|
|
|
30
30
|
virtual void open_single_part(const PathHierarchy &single_part) = 0;
|
|
31
31
|
virtual void close_single_part() = 0;
|
|
32
32
|
virtual ssize_t read_from_single_part(void *buffer, size_t size) = 0;
|
|
33
|
-
virtual int64_t seek_within_single_part(int64_t offset, int whence)
|
|
34
|
-
virtual int64_t size_of_single_part(const PathHierarchy &single_part)
|
|
33
|
+
virtual int64_t seek_within_single_part(int64_t offset, int whence);
|
|
34
|
+
virtual int64_t size_of_single_part(const PathHierarchy &single_part);
|
|
35
35
|
|
|
36
36
|
PathHierarchy _logical_path;
|
|
37
37
|
void deactivate_active_part();
|
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
#include <sys/types.h>
|
|
7
7
|
|
|
8
8
|
#if defined(_WIN32)
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
9
|
+
#include <BaseTsd.h>
|
|
10
|
+
#include <sys/stat.h>
|
|
11
|
+
#if !defined(_SSIZE_T_DEFINED)
|
|
12
12
|
using ssize_t = SSIZE_T;
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
13
|
+
#define _SSIZE_T_DEFINED
|
|
14
|
+
#endif
|
|
15
|
+
#if !defined(_MODE_T_DEFINED)
|
|
16
16
|
using mode_t = unsigned short; // MSVC does not expose POSIX mode_t by default
|
|
17
|
-
#
|
|
18
|
-
#
|
|
17
|
+
#define _MODE_T_DEFINED
|
|
18
|
+
#endif
|
|
19
19
|
#endif
|
|
20
20
|
|
|
21
21
|
namespace archive_r {
|
|
@@ -75,8 +75,8 @@ public:
|
|
|
75
75
|
* Provide one or more paths to traverse. Single-path traversal can be
|
|
76
76
|
* achieved by passing a container with one element:
|
|
77
77
|
* Traverser traverser({make_single_path("archive.tar.gz")});
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
*
|
|
79
|
+
* @throws std::invalid_argument if paths is empty or contains an empty hierarchy
|
|
80
80
|
*/
|
|
81
81
|
explicit Traverser(std::vector<PathHierarchy> paths, TraverserOptions options = {});
|
|
82
82
|
|
|
@@ -125,9 +125,7 @@ EntryPayloadStream::EntryPayloadStream(std::shared_ptr<StreamArchive> parent_arc
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
EntryPayloadStream::~EntryPayloadStream() {
|
|
129
|
-
deactivate_active_part();
|
|
130
|
-
}
|
|
128
|
+
EntryPayloadStream::~EntryPayloadStream() { deactivate_active_part(); }
|
|
131
129
|
|
|
132
130
|
std::shared_ptr<StreamArchive> EntryPayloadStream::parent_archive() const { return _parent_archive; }
|
|
133
131
|
|
|
@@ -154,19 +152,7 @@ void EntryPayloadStream::close_single_part() {
|
|
|
154
152
|
// so explicit skipping here is unnecessary and avoids potential exceptions in destructor.
|
|
155
153
|
}
|
|
156
154
|
|
|
157
|
-
ssize_t EntryPayloadStream::read_from_single_part(void *buffer, size_t size) {
|
|
158
|
-
if (size == 0) {
|
|
159
|
-
return 0;
|
|
160
|
-
}
|
|
161
|
-
return _parent_archive->read_current(buffer, size);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
int64_t EntryPayloadStream::seek_within_single_part(int64_t offset, int whence) { return -1; }
|
|
165
|
-
|
|
166
|
-
int64_t EntryPayloadStream::size_of_single_part(const PathHierarchy &single_part) {
|
|
167
|
-
(void)single_part;
|
|
168
|
-
return -1;
|
|
169
|
-
}
|
|
155
|
+
ssize_t EntryPayloadStream::read_from_single_part(void *buffer, size_t size) { return _parent_archive->read_current(buffer, size); }
|
|
170
156
|
|
|
171
157
|
// ============================================================================
|
|
172
158
|
// ArchiveStackCursor Implementation
|
|
@@ -177,9 +163,7 @@ ArchiveStackCursor::ArchiveStackCursor()
|
|
|
177
163
|
, _current_stream(nullptr)
|
|
178
164
|
, _current_archive(nullptr) {}
|
|
179
165
|
|
|
180
|
-
void ArchiveStackCursor::configure(const ArchiveOption &options) {
|
|
181
|
-
options_snapshot = options;
|
|
182
|
-
}
|
|
166
|
+
void ArchiveStackCursor::configure(const ArchiveOption &options) { options_snapshot = options; }
|
|
183
167
|
|
|
184
168
|
void ArchiveStackCursor::reset() {
|
|
185
169
|
options_snapshot = ArchiveOption{};
|
|
@@ -207,17 +191,12 @@ bool ArchiveStackCursor::descend() {
|
|
|
207
191
|
}
|
|
208
192
|
|
|
209
193
|
bool ArchiveStackCursor::ascend() {
|
|
210
|
-
if (
|
|
194
|
+
if (!_current_archive) {
|
|
211
195
|
return false;
|
|
212
196
|
}
|
|
213
197
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
_current_archive = _current_archive->parent_archive();
|
|
217
|
-
} else {
|
|
218
|
-
_current_stream = nullptr;
|
|
219
|
-
}
|
|
220
|
-
|
|
198
|
+
_current_stream = _current_archive->get_stream();
|
|
199
|
+
_current_archive = _current_archive->parent_archive();
|
|
221
200
|
return true;
|
|
222
201
|
}
|
|
223
202
|
|
|
@@ -250,8 +229,7 @@ bool ArchiveStackCursor::synchronize_to_hierarchy(const PathHierarchy &target_hi
|
|
|
250
229
|
// 1. Ascend until we find a common ancestor
|
|
251
230
|
while (depth() > 0) {
|
|
252
231
|
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))) {
|
|
232
|
+
if (current_h.size() <= target_hierarchy.size() && hierarchies_equal(current_h, pathhierarchy_prefix_until(target_hierarchy, current_h.size() - 1))) {
|
|
255
233
|
break;
|
|
256
234
|
}
|
|
257
235
|
ascend();
|
|
@@ -289,12 +267,10 @@ ssize_t ArchiveStackCursor::read(void *buff, size_t len) {
|
|
|
289
267
|
return 0;
|
|
290
268
|
}
|
|
291
269
|
|
|
292
|
-
StreamArchive *ArchiveStackCursor::current_archive() {
|
|
293
|
-
return _current_archive.get();
|
|
294
|
-
}
|
|
270
|
+
StreamArchive *ArchiveStackCursor::current_archive() { return _current_archive.get(); }
|
|
295
271
|
|
|
296
272
|
PathHierarchy ArchiveStackCursor::current_entry_hierarchy() {
|
|
297
|
-
if (
|
|
273
|
+
if (!_current_stream && !_current_archive) {
|
|
298
274
|
return {};
|
|
299
275
|
}
|
|
300
276
|
|
|
@@ -306,7 +282,7 @@ PathHierarchy ArchiveStackCursor::current_entry_hierarchy() {
|
|
|
306
282
|
return path;
|
|
307
283
|
}
|
|
308
284
|
|
|
309
|
-
return _current_stream->source_hierarchy();
|
|
285
|
+
return _current_stream ? _current_stream->source_hierarchy() : PathHierarchy{};
|
|
310
286
|
}
|
|
311
287
|
|
|
312
288
|
std::shared_ptr<IDataStream> ArchiveStackCursor::create_stream(const PathHierarchy &hierarchy) {
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
#pragma once
|
|
5
5
|
|
|
6
6
|
#include "archive_r/data_stream.h"
|
|
7
|
+
#include "archive_r/multi_volume_stream_base.h"
|
|
7
8
|
#include "archive_r/path_hierarchy.h"
|
|
8
9
|
#include "archive_type.h"
|
|
9
10
|
#include "entry_fault_error.h"
|
|
10
|
-
#include "archive_r/multi_volume_stream_base.h"
|
|
11
11
|
#include <array>
|
|
12
12
|
#include <cstddef>
|
|
13
13
|
#include <exception>
|
|
@@ -64,8 +64,6 @@ private:
|
|
|
64
64
|
void open_single_part(const PathHierarchy &single_part) override;
|
|
65
65
|
void close_single_part() override;
|
|
66
66
|
ssize_t read_from_single_part(void *buffer, size_t size) override;
|
|
67
|
-
int64_t seek_within_single_part(int64_t offset, int whence) override;
|
|
68
|
-
int64_t size_of_single_part(const PathHierarchy &single_part) override;
|
|
69
67
|
};
|
|
70
68
|
|
|
71
69
|
// ============================================================================
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Copyright (c) 2025 archive_r Team
|
|
3
3
|
|
|
4
4
|
#include "archive_stack_orchestrator.h"
|
|
5
|
-
#include "archive_r/path_hierarchy_utils.h"
|
|
6
5
|
#include "archive_r/entry_fault.h"
|
|
6
|
+
#include "archive_r/path_hierarchy_utils.h"
|
|
7
7
|
#include "system_file_stream.h"
|
|
8
8
|
|
|
9
9
|
#include <algorithm>
|
|
@@ -19,8 +19,7 @@
|
|
|
19
19
|
namespace archive_r {
|
|
20
20
|
|
|
21
21
|
ArchiveStackOrchestrator::ArchiveStackOrchestrator(const ArchiveOption &options)
|
|
22
|
-
: _archive_options(options)
|
|
23
|
-
{
|
|
22
|
+
: _archive_options(options) {
|
|
24
23
|
_head.configure(_archive_options);
|
|
25
24
|
}
|
|
26
25
|
|
|
@@ -135,12 +134,12 @@ void ArchiveStackOrchestrator::mark_entry_as_multi_volume(const PathHierarchy &e
|
|
|
135
134
|
}
|
|
136
135
|
|
|
137
136
|
bool ArchiveStackOrchestrator::descend_pending_multi_volumes() {
|
|
138
|
-
const PathHierarchy current_hierarchy = _head.current_entry_hierarchy();
|
|
137
|
+
const PathHierarchy current_hierarchy = (depth() == 0) ? PathHierarchy{} : _head.current_entry_hierarchy();
|
|
139
138
|
PathHierarchy multi_volume_target;
|
|
140
139
|
if (!_multi_volume_manager.pop_multi_volume_group(current_hierarchy, multi_volume_target)) {
|
|
141
140
|
return false;
|
|
142
141
|
}
|
|
143
|
-
|
|
142
|
+
|
|
144
143
|
_head.synchronize_to_hierarchy(multi_volume_target);
|
|
145
144
|
_head.descend();
|
|
146
145
|
return true;
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
#include "archive_r/path_hierarchy.h"
|
|
7
7
|
#include "archive_r/platform_compat.h"
|
|
8
|
-
#include "archive_type.h"
|
|
9
8
|
#include "archive_stack_cursor.h"
|
|
9
|
+
#include "archive_type.h"
|
|
10
10
|
#include "entry_fault_error.h"
|
|
11
11
|
#include "multi_volume_manager.h"
|
|
12
12
|
#include <limits>
|
|
@@ -232,9 +232,7 @@ bool Archive::search_forward_until_eof(const std::string &entryname) {
|
|
|
232
232
|
if (current_entryname == entryname) {
|
|
233
233
|
return true;
|
|
234
234
|
}
|
|
235
|
-
|
|
236
|
-
return false;
|
|
237
|
-
}
|
|
235
|
+
skip_data();
|
|
238
236
|
}
|
|
239
237
|
return false;
|
|
240
238
|
}
|
|
@@ -247,9 +245,7 @@ bool Archive::search_until_position(const std::string &entryname, const std::str
|
|
|
247
245
|
if (current_entryname == stop_position) {
|
|
248
246
|
break;
|
|
249
247
|
}
|
|
250
|
-
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
248
|
+
skip_data();
|
|
253
249
|
}
|
|
254
250
|
return false;
|
|
255
251
|
}
|
|
@@ -453,14 +449,9 @@ EntryMetadataMap Archive::current_entry_metadata(const std::unordered_set<std::s
|
|
|
453
449
|
}
|
|
454
450
|
}
|
|
455
451
|
|
|
456
|
-
|
|
457
|
-
char *acl_text = wants("acl_text") ? archive_entry_acl_to_text(current_entry, &acl_length, ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) : nullptr;
|
|
452
|
+
char *acl_text = wants("acl_text") ? archive_entry_acl_to_text(current_entry, nullptr, ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) : nullptr;
|
|
458
453
|
if (acl_text) {
|
|
459
|
-
|
|
460
|
-
metadata["acl_text"] = std::string(acl_text, static_cast<size_t>(acl_length));
|
|
461
|
-
} else {
|
|
462
|
-
metadata["acl_text"] = std::string(acl_text);
|
|
463
|
-
}
|
|
454
|
+
metadata["acl_text"] = std::string(acl_text);
|
|
464
455
|
std::free(acl_text);
|
|
465
456
|
}
|
|
466
457
|
|
|
@@ -26,8 +26,8 @@ using archive_ptr = std::unique_ptr<struct archive, archive_deleter>;
|
|
|
26
26
|
using open_delegate = std::function<int(struct archive *ar)>;
|
|
27
27
|
|
|
28
28
|
struct ArchiveOption {
|
|
29
|
-
std::vector<std::string> passphrases;
|
|
30
|
-
std::vector<std::string> formats;
|
|
29
|
+
std::vector<std::string> passphrases; ///< Passphrases for encrypted archives
|
|
30
|
+
std::vector<std::string> formats; ///< Specific format names to enable (empty = all)
|
|
31
31
|
std::unordered_set<std::string> metadata_keys; ///< Metadata keys to capture (empty = none)
|
|
32
32
|
};
|
|
33
33
|
|
|
@@ -32,24 +32,9 @@ Entry::Impl::Impl(const Impl &other)
|
|
|
32
32
|
, _descend_enabled(other._descend_enabled)
|
|
33
33
|
, _orchestrator(nullptr)
|
|
34
34
|
, _shares_traverser_orchestrator(false)
|
|
35
|
-
, _archive_options(other._archive_options) {
|
|
36
|
-
}
|
|
35
|
+
, _archive_options(other._archive_options) {}
|
|
37
36
|
|
|
38
37
|
// Copy assignment operator
|
|
39
|
-
Entry::Impl &Entry::Impl::operator=(const Impl &other) {
|
|
40
|
-
if (this != &other) {
|
|
41
|
-
_path_hierarchy = other._path_hierarchy;
|
|
42
|
-
_size = other._size;
|
|
43
|
-
_filetype = other._filetype;
|
|
44
|
-
_metadata = other._metadata;
|
|
45
|
-
_descend_enabled = other._descend_enabled;
|
|
46
|
-
_orchestrator.reset();
|
|
47
|
-
_shares_traverser_orchestrator = false;
|
|
48
|
-
_archive_options = other._archive_options;
|
|
49
|
-
}
|
|
50
|
-
return *this;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
38
|
Entry::Impl::Impl(const PathHierarchy &hierarchy, std::shared_ptr<ArchiveStackOrchestrator> data_source_orchestrator, bool default_descent)
|
|
54
39
|
: _path_hierarchy(hierarchy)
|
|
55
40
|
, _size(0)
|
|
@@ -199,7 +184,7 @@ ssize_t Entry::Impl::read(void *buffer, size_t length) {
|
|
|
199
184
|
// ============================================================================
|
|
200
185
|
|
|
201
186
|
Entry::Entry(const PathHierarchy &hierarchy, std::shared_ptr<ArchiveStackOrchestrator> data_source_orchestrator, bool default_descent)
|
|
202
|
-
|
|
187
|
+
: _impl(std::make_unique<Impl>(hierarchy, std::move(data_source_orchestrator), default_descent)) {}
|
|
203
188
|
|
|
204
189
|
Entry::Entry(Impl *impl)
|
|
205
190
|
: _impl(impl) {}
|
|
@@ -18,35 +18,35 @@ EntryFaultError::EntryFaultError(EntryFault fault, const std::string &internal_m
|
|
|
18
18
|
, _fault(std::move(fault)) {}
|
|
19
19
|
|
|
20
20
|
EntryFaultError make_entry_fault_error(const std::string &message, PathHierarchy hierarchy, int errno_value) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
EntryFault fault;
|
|
22
|
+
fault.hierarchy = std::move(hierarchy);
|
|
23
|
+
fault.message = message;
|
|
24
|
+
fault.errno_value = errno_value;
|
|
25
|
+
return EntryFaultError(std::move(fault));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
std::string format_errno_error(const std::string &prefix, int err) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
if (err == 0) {
|
|
30
|
+
return prefix;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
std::string message = prefix;
|
|
34
|
+
message.append(": ");
|
|
35
|
+
message.append(std::strerror(err));
|
|
36
|
+
message.append(" (posix errno=");
|
|
37
|
+
message.append(std::to_string(err));
|
|
38
|
+
message.push_back(')');
|
|
39
|
+
return message;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
std::string format_path_errno_error(const std::string &action, const std::string &path, int err) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
43
|
+
std::string prefix = action;
|
|
44
|
+
if (!path.empty()) {
|
|
45
|
+
prefix.append(" '");
|
|
46
|
+
prefix.append(path);
|
|
47
|
+
prefix.push_back('\'');
|
|
48
|
+
}
|
|
49
|
+
return format_errno_error(prefix, err);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
std::string prefer_error_detail(const std::string &detail, const std::string &fallback) { return detail.empty() ? fallback : detail; }
|
|
@@ -19,7 +19,6 @@ public:
|
|
|
19
19
|
// No libarchive dependency
|
|
20
20
|
// Copy constructor and assignment (orchestrator is not copied)
|
|
21
21
|
Impl(const Impl &other);
|
|
22
|
-
Impl &operator=(const Impl &other);
|
|
23
22
|
|
|
24
23
|
Impl(const PathHierarchy &hierarchy, std::shared_ptr<ArchiveStackOrchestrator> data_source_orchestrator, bool default_descent);
|
|
25
24
|
|
|
@@ -45,7 +44,7 @@ private:
|
|
|
45
44
|
EntryMetadataMap _metadata;
|
|
46
45
|
bool _descend_enabled = true; // Flag to control automatic descent
|
|
47
46
|
|
|
48
|
-
std::shared_ptr<ArchiveStackOrchestrator> _orchestrator;
|
|
47
|
+
std::shared_ptr<ArchiveStackOrchestrator> _orchestrator; ///< Active orchestrator (shared with traverser or detached copy)
|
|
49
48
|
bool _shares_traverser_orchestrator = false;
|
|
50
49
|
|
|
51
50
|
mutable std::optional<ArchiveOption> _archive_options;
|
|
@@ -10,9 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
namespace archive_r {
|
|
12
12
|
|
|
13
|
-
MultiVolumeManager::MultiVolumeGroup &MultiVolumeManager::get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy,
|
|
14
|
-
const std::string &base_name,
|
|
15
|
-
PathEntry::Parts::Ordering ordering) {
|
|
13
|
+
MultiVolumeManager::MultiVolumeGroup &MultiVolumeManager::get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy, const std::string &base_name, PathEntry::Parts::Ordering ordering) {
|
|
16
14
|
GroupList &groups = _multi_volume_groups[parent_hierarchy];
|
|
17
15
|
auto it = std::find_if(groups.begin(), groups.end(), [&](const MultiVolumeGroup &group) { return group.base_name == base_name; });
|
|
18
16
|
|
|
@@ -47,17 +45,14 @@ bool MultiVolumeManager::pop_group_for_parent(const PathHierarchy &parent_hierar
|
|
|
47
45
|
return true;
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
void MultiVolumeManager::mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name,
|
|
51
|
-
PathEntry::Parts::Ordering ordering) {
|
|
48
|
+
void MultiVolumeManager::mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name, PathEntry::Parts::Ordering ordering) {
|
|
52
49
|
if (entry_path.empty() || pathhierarchy_is_multivolume(entry_path)) {
|
|
53
50
|
return;
|
|
54
51
|
}
|
|
55
52
|
|
|
56
53
|
MultiVolumeGroup &target = get_or_create_multi_volume_group(parent_hierarchy(entry_path), base_name, ordering);
|
|
57
54
|
auto &parts = target.parts;
|
|
58
|
-
const bool exists = std::any_of(parts.begin(), parts.end(), [&](const PathHierarchy &existing) {
|
|
59
|
-
return hierarchies_equal(existing, entry_path);
|
|
60
|
-
});
|
|
55
|
+
const bool exists = std::any_of(parts.begin(), parts.end(), [&](const PathHierarchy &existing) { return hierarchies_equal(existing, entry_path); });
|
|
61
56
|
if (!exists) {
|
|
62
57
|
parts.push_back(entry_path);
|
|
63
58
|
}
|
|
@@ -24,14 +24,12 @@ public:
|
|
|
24
24
|
using GroupList = std::vector<MultiVolumeGroup>;
|
|
25
25
|
using ParentGroupMap = std::map<PathHierarchy, GroupList, PathHierarchyLess>;
|
|
26
26
|
|
|
27
|
-
void mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name,
|
|
28
|
-
PathEntry::Parts::Ordering ordering = PathEntry::Parts::Ordering::Natural);
|
|
27
|
+
void mark_entry_as_multi_volume(const PathHierarchy &entry_path, const std::string &base_name, PathEntry::Parts::Ordering ordering = PathEntry::Parts::Ordering::Natural);
|
|
29
28
|
|
|
30
29
|
bool pop_multi_volume_group(const PathHierarchy ¤t_hierarchy, PathHierarchy &multi_volume_hierarchy);
|
|
31
30
|
|
|
32
31
|
private:
|
|
33
|
-
MultiVolumeGroup &get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy, const std::string &base_name,
|
|
34
|
-
PathEntry::Parts::Ordering ordering);
|
|
32
|
+
MultiVolumeGroup &get_or_create_multi_volume_group(const PathHierarchy &parent_hierarchy, const std::string &base_name, PathEntry::Parts::Ordering ordering);
|
|
35
33
|
|
|
36
34
|
bool pop_group_for_parent(const PathHierarchy &parent_hierarchy, MultiVolumeGroup &out_group);
|
|
37
35
|
|
|
@@ -33,9 +33,9 @@ struct MultiVolumeStreamBase::Impl {
|
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
MultiVolumeStreamBase::MultiVolumeStreamBase(PathHierarchy logical_path, bool supports_seek)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
: _logical_path(std::move(logical_path))
|
|
37
|
+
, _supports_seek(supports_seek)
|
|
38
|
+
, _impl(std::make_unique<Impl>(*this)) {
|
|
39
39
|
_impl->total_parts = pathhierarchy_volume_size(_logical_path);
|
|
40
40
|
if (_impl->total_parts == 0) {
|
|
41
41
|
throw std::invalid_argument("MultiVolumeStreamBase requires at least one volume component");
|
|
@@ -84,9 +84,7 @@ void MultiVolumeStreamBase::rewind() {
|
|
|
84
84
|
_impl->logical_offset = 0;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
bool MultiVolumeStreamBase::at_end() const {
|
|
88
|
-
return _impl->active_part_index >= _impl->total_parts;
|
|
89
|
-
}
|
|
87
|
+
bool MultiVolumeStreamBase::at_end() const { return _impl->active_part_index >= _impl->total_parts; }
|
|
90
88
|
|
|
91
89
|
int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
|
|
92
90
|
if (!_supports_seek) {
|
|
@@ -122,6 +120,17 @@ int64_t MultiVolumeStreamBase::seek(int64_t offset, int whence) {
|
|
|
122
120
|
|
|
123
121
|
int64_t MultiVolumeStreamBase::tell() const { return _impl->logical_offset; }
|
|
124
122
|
|
|
123
|
+
int64_t MultiVolumeStreamBase::seek_within_single_part(int64_t offset, int whence) {
|
|
124
|
+
(void)offset;
|
|
125
|
+
(void)whence;
|
|
126
|
+
return -1;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
int64_t MultiVolumeStreamBase::size_of_single_part(const PathHierarchy &single_part) {
|
|
130
|
+
(void)single_part;
|
|
131
|
+
return -1;
|
|
132
|
+
}
|
|
133
|
+
|
|
125
134
|
void MultiVolumeStreamBase::Impl::ensure_part_active(std::size_t part_index) {
|
|
126
135
|
if (part_open && open_part_index == part_index) {
|
|
127
136
|
return;
|
|
@@ -173,14 +182,14 @@ bool MultiVolumeStreamBase::Impl::ensure_size_metadata() {
|
|
|
173
182
|
|
|
174
183
|
int64_t MultiVolumeStreamBase::Impl::compute_target_offset(int64_t offset, int whence) const {
|
|
175
184
|
switch (whence) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
185
|
+
case SEEK_SET:
|
|
186
|
+
return offset;
|
|
187
|
+
case SEEK_CUR:
|
|
188
|
+
return logical_offset + offset;
|
|
189
|
+
case SEEK_END:
|
|
190
|
+
return total_size + offset;
|
|
191
|
+
default:
|
|
192
|
+
return -1;
|
|
184
193
|
}
|
|
185
194
|
}
|
|
186
195
|
|
|
@@ -107,9 +107,7 @@ PathHierarchy make_single_path(const std::string &root) {
|
|
|
107
107
|
|
|
108
108
|
void append_single(PathHierarchy &hierarchy, std::string value) { hierarchy.emplace_back(PathEntry::single(std::move(value))); }
|
|
109
109
|
|
|
110
|
-
void append_multi_volume(PathHierarchy &hierarchy, std::vector<std::string> parts, PathEntry::Parts::Ordering ordering) {
|
|
111
|
-
hierarchy.emplace_back(PathEntry::multi_volume(std::move(parts), ordering));
|
|
112
|
-
}
|
|
110
|
+
void append_multi_volume(PathHierarchy &hierarchy, std::vector<std::string> parts, PathEntry::Parts::Ordering ordering) { hierarchy.emplace_back(PathEntry::multi_volume(std::move(parts), ordering)); }
|
|
113
111
|
|
|
114
112
|
PathHierarchy pathhierarchy_prefix_until(const PathHierarchy &hierarchy, size_t inclusive_index) {
|
|
115
113
|
if (hierarchy.empty() || inclusive_index >= hierarchy.size()) {
|
|
@@ -126,5 +124,4 @@ PathHierarchy parent_hierarchy(const PathHierarchy &hierarchy) {
|
|
|
126
124
|
return pathhierarchy_prefix_until(hierarchy, hierarchy.size() - 2);
|
|
127
125
|
}
|
|
128
126
|
|
|
129
|
-
|
|
130
127
|
} // namespace archive_r
|
|
@@ -73,10 +73,6 @@ bool determine_multi_volume_segments(const std::vector<PathHierarchy> &sources,
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
bool collect_multi_volume_parts(const std::vector<PathHierarchy> &sources, const CollapseSegments &segments, std::vector<std::string> &parts) {
|
|
76
|
-
if (sources.empty()) {
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
76
|
const std::size_t suffix_size = segments.suffix.size();
|
|
81
77
|
const std::size_t required_size = segments.multi_volume_depth + 1 + suffix_size;
|
|
82
78
|
|
|
@@ -111,14 +107,6 @@ bool collect_multi_volume_parts(const std::vector<PathHierarchy> &sources, const
|
|
|
111
107
|
return true;
|
|
112
108
|
}
|
|
113
109
|
|
|
114
|
-
bool flatten_single_entry(const PathEntry &entry, std::string &output) {
|
|
115
|
-
if (entry.is_single()) {
|
|
116
|
-
output = entry.single_value();
|
|
117
|
-
return true;
|
|
118
|
-
}
|
|
119
|
-
return flatten_entry_to_string(entry, output);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
110
|
} // namespace
|
|
123
111
|
|
|
124
112
|
const std::string *path_entry_component_at(const PathEntry &entry, std::size_t index) {
|
|
@@ -129,14 +117,10 @@ const std::string *path_entry_component_at(const PathEntry &entry, std::size_t i
|
|
|
129
117
|
return nullptr;
|
|
130
118
|
}
|
|
131
119
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return &parts[index];
|
|
136
|
-
}
|
|
137
|
-
return nullptr;
|
|
120
|
+
const auto &parts = entry.multi_volume_parts().values;
|
|
121
|
+
if (index < parts.size()) {
|
|
122
|
+
return &parts[index];
|
|
138
123
|
}
|
|
139
|
-
|
|
140
124
|
return nullptr;
|
|
141
125
|
}
|
|
142
126
|
|
|
@@ -162,11 +146,7 @@ std::string pathhierarchy_volume_entry_name(const PathHierarchy &logical, std::s
|
|
|
162
146
|
return {};
|
|
163
147
|
}
|
|
164
148
|
|
|
165
|
-
|
|
166
|
-
if (!flatten_single_entry(tail, entry_name)) {
|
|
167
|
-
return {};
|
|
168
|
-
}
|
|
169
|
-
return entry_name;
|
|
149
|
+
return tail.single_value();
|
|
170
150
|
}
|
|
171
151
|
|
|
172
152
|
const auto &parts = tail.multi_volume_parts().values;
|
|
@@ -241,20 +221,18 @@ std::string path_entry_display(const PathEntry &entry) {
|
|
|
241
221
|
if (entry.is_single()) {
|
|
242
222
|
return entry.single_value();
|
|
243
223
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
251
|
-
value += part;
|
|
252
|
-
first = false;
|
|
224
|
+
|
|
225
|
+
std::string value = "[";
|
|
226
|
+
bool first = true;
|
|
227
|
+
for (const auto &part : entry.multi_volume_parts().values) {
|
|
228
|
+
if (!first) {
|
|
229
|
+
value.push_back('|');
|
|
253
230
|
}
|
|
254
|
-
value
|
|
255
|
-
|
|
231
|
+
value += part;
|
|
232
|
+
first = false;
|
|
256
233
|
}
|
|
257
|
-
|
|
234
|
+
value.push_back(']');
|
|
235
|
+
return value;
|
|
258
236
|
}
|
|
259
237
|
|
|
260
238
|
std::string hierarchy_display(const PathHierarchy &hierarchy) {
|
|
@@ -4,106 +4,95 @@
|
|
|
4
4
|
#pragma once
|
|
5
5
|
#include <string>
|
|
6
6
|
|
|
7
|
+
#include <algorithm>
|
|
7
8
|
#include <chrono>
|
|
9
|
+
#include <iomanip>
|
|
8
10
|
#include <iostream>
|
|
9
11
|
#include <map>
|
|
10
|
-
#include <vector>
|
|
11
|
-
#include <algorithm>
|
|
12
|
-
#include <iomanip>
|
|
13
12
|
#include <mutex>
|
|
14
|
-
|
|
13
|
+
#include <vector>
|
|
15
14
|
|
|
16
15
|
namespace archive_r {
|
|
17
16
|
namespace internal {
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
18
|
class SimpleProfiler {
|
|
22
19
|
public:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
static SimpleProfiler &instance() {
|
|
21
|
+
static SimpleProfiler inst;
|
|
22
|
+
return inst;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
~SimpleProfiler() { report(); }
|
|
26
|
+
|
|
27
|
+
void start(const std::string &name) {
|
|
28
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
29
|
+
auto now = std::chrono::high_resolution_clock::now();
|
|
30
|
+
start_times_[name] = now;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void stop(const std::string &name) {
|
|
34
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
35
|
+
auto now = std::chrono::high_resolution_clock::now();
|
|
36
|
+
auto it = start_times_.find(name);
|
|
37
|
+
if (it != start_times_.end()) {
|
|
38
|
+
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(now - it->second).count();
|
|
39
|
+
durations_[name] += duration;
|
|
40
|
+
counts_[name]++;
|
|
26
41
|
}
|
|
42
|
+
}
|
|
27
43
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
44
|
+
void report() {
|
|
45
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
46
|
+
if (durations_.empty())
|
|
47
|
+
return;
|
|
31
48
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
std::cout << "\n=== Profiling Report (archive_r::internal) ===" << std::endl;
|
|
50
|
+
std::vector<std::pair<std::string, long long>> sorted_durations;
|
|
51
|
+
for (const auto &pair : durations_) {
|
|
52
|
+
sorted_durations.push_back(pair);
|
|
36
53
|
}
|
|
37
54
|
|
|
38
|
-
|
|
39
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
40
|
-
auto now = std::chrono::high_resolution_clock::now();
|
|
41
|
-
auto it = start_times_.find(name);
|
|
42
|
-
if (it != start_times_.end()) {
|
|
43
|
-
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(now - it->second).count();
|
|
44
|
-
durations_[name] += duration;
|
|
45
|
-
counts_[name]++;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
55
|
+
std::sort(sorted_durations.begin(), sorted_durations.end(), [](const auto &a, const auto &b) { return a.second > b.second; });
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
std::sort(sorted_durations.begin(), sorted_durations.end(),
|
|
60
|
-
[](const auto& a, const auto& b) { return a.second > b.second; });
|
|
61
|
-
|
|
62
|
-
std::cout << std::left << std::setw(40) << "Name"
|
|
63
|
-
<< std::right << std::setw(15) << "Total (ms)"
|
|
64
|
-
<< std::setw(10) << "Count"
|
|
65
|
-
<< std::setw(15) << "Avg (us)" << std::endl;
|
|
66
|
-
std::cout << std::string(80, '-') << std::endl;
|
|
67
|
-
|
|
68
|
-
for (const auto& pair : sorted_durations) {
|
|
69
|
-
const auto& name = pair.first;
|
|
70
|
-
long long total_ns = pair.second;
|
|
71
|
-
long long count = counts_[name];
|
|
72
|
-
double avg_ns = count > 0 ? (double)total_ns / count : 0;
|
|
73
|
-
|
|
74
|
-
std::cout << std::left << std::setw(40) << name
|
|
75
|
-
<< std::right << std::setw(15) << std::fixed << std::setprecision(3) << total_ns / 1000000.0
|
|
76
|
-
<< std::setw(10) << count
|
|
77
|
-
<< std::setw(15) << std::fixed << std::setprecision(3) << avg_ns / 1000.0
|
|
78
|
-
<< std::endl;
|
|
79
|
-
}
|
|
80
|
-
std::cout << "==============================================\n" << std::endl;
|
|
81
|
-
}
|
|
57
|
+
std::cout << std::left << std::setw(40) << "Name" << std::right << std::setw(15) << "Total (ms)" << std::setw(10) << "Count" << std::setw(15) << "Avg (us)" << std::endl;
|
|
58
|
+
std::cout << std::string(80, '-') << std::endl;
|
|
59
|
+
|
|
60
|
+
for (const auto &pair : sorted_durations) {
|
|
61
|
+
const auto &name = pair.first;
|
|
62
|
+
long long total_ns = pair.second;
|
|
63
|
+
long long count = counts_[name];
|
|
64
|
+
double avg_ns = count > 0 ? (double)total_ns / count : 0;
|
|
82
65
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
start_times_.clear();
|
|
86
|
-
durations_.clear();
|
|
87
|
-
counts_.clear();
|
|
66
|
+
std::cout << std::left << std::setw(40) << name << std::right << std::setw(15) << std::fixed << std::setprecision(3) << total_ns / 1000000.0 << std::setw(10) << count << std::setw(15)
|
|
67
|
+
<< std::fixed << std::setprecision(3) << avg_ns / 1000.0 << std::endl;
|
|
88
68
|
}
|
|
69
|
+
std::cout << "==============================================\n" << std::endl;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
void reset() {
|
|
73
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
74
|
+
start_times_.clear();
|
|
75
|
+
durations_.clear();
|
|
76
|
+
counts_.clear();
|
|
77
|
+
}
|
|
89
78
|
|
|
90
79
|
private:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
80
|
+
std::map<std::string, std::chrono::high_resolution_clock::time_point> start_times_;
|
|
81
|
+
std::map<std::string, long long> durations_;
|
|
82
|
+
std::map<std::string, long long> counts_;
|
|
83
|
+
std::mutex mutex_;
|
|
95
84
|
};
|
|
96
85
|
|
|
97
86
|
class ScopedTimer {
|
|
98
87
|
public:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
88
|
+
ScopedTimer(const std::string &name)
|
|
89
|
+
: name_(name) {
|
|
90
|
+
SimpleProfiler::instance().start(name_);
|
|
91
|
+
}
|
|
92
|
+
~ScopedTimer() { SimpleProfiler::instance().stop(name_); }
|
|
93
|
+
|
|
105
94
|
private:
|
|
106
|
-
|
|
95
|
+
std::string name_;
|
|
107
96
|
};
|
|
108
97
|
|
|
109
98
|
} // namespace internal
|
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
#include <cstdio>
|
|
12
12
|
#include <filesystem>
|
|
13
13
|
#include <stdexcept>
|
|
14
|
+
#include <string_view>
|
|
14
15
|
#include <sys/stat.h>
|
|
15
16
|
#include <system_error>
|
|
16
|
-
#include <string_view>
|
|
17
17
|
#include <utility>
|
|
18
18
|
#include <vector>
|
|
19
19
|
|
|
20
20
|
#if !defined(_WIN32)
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
21
|
+
#include <grp.h>
|
|
22
|
+
#include <pwd.h>
|
|
23
|
+
#include <unistd.h>
|
|
24
24
|
#endif
|
|
25
25
|
|
|
26
26
|
namespace archive_r {
|
|
@@ -66,21 +66,10 @@ static bool lookup_groupname(gid_t gid, std::string &name_out) {
|
|
|
66
66
|
} // namespace
|
|
67
67
|
|
|
68
68
|
SystemFileStream::SystemFileStream(PathHierarchy logical_path)
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (_logical_path.empty()) {
|
|
72
|
-
throw std::invalid_argument("Root file hierarchy cannot be empty");
|
|
73
|
-
}
|
|
69
|
+
: MultiVolumeStreamBase(std::move(logical_path), true)
|
|
70
|
+
, _handle(nullptr) {}
|
|
74
71
|
|
|
75
|
-
|
|
76
|
-
if (!root_entry.is_single() && !root_entry.is_multi_volume()) {
|
|
77
|
-
throw std::invalid_argument("Root file hierarchy must be a single file or multi-volume source");
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
SystemFileStream::~SystemFileStream() {
|
|
82
|
-
deactivate_active_part();
|
|
83
|
-
}
|
|
72
|
+
SystemFileStream::~SystemFileStream() { deactivate_active_part(); }
|
|
84
73
|
|
|
85
74
|
void SystemFileStream::open_single_part(const PathHierarchy &single_part) {
|
|
86
75
|
const PathEntry &entry = single_part.back();
|
|
@@ -100,7 +89,7 @@ void SystemFileStream::open_single_part(const PathHierarchy &single_part) {
|
|
|
100
89
|
// Enable larger buffering on Windows to improve performance
|
|
101
90
|
// Use 64KB buffer to match StreamArchive's buffer size
|
|
102
91
|
if (_handle) {
|
|
103
|
-
|
|
92
|
+
std::setvbuf(_handle, nullptr, _IOFBF, 65536);
|
|
104
93
|
}
|
|
105
94
|
#endif
|
|
106
95
|
}
|
|
@@ -227,9 +216,7 @@ FilesystemMetadataInfo collect_root_path_metadata(const PathHierarchy &hierarchy
|
|
|
227
216
|
info.filetype = filetype;
|
|
228
217
|
EntryMetadataMap metadata;
|
|
229
218
|
if (!allowed_keys.empty()) {
|
|
230
|
-
const auto wants = [&allowed_keys](std::string_view key) {
|
|
231
|
-
return allowed_keys.find(std::string(key)) != allowed_keys.end();
|
|
232
|
-
};
|
|
219
|
+
const auto wants = [&allowed_keys](std::string_view key) { return allowed_keys.find(std::string(key)) != allowed_keys.end(); };
|
|
233
220
|
|
|
234
221
|
// Path hierarchy / directory entry derived metadata
|
|
235
222
|
if (wants("pathname")) {
|
|
@@ -254,10 +241,10 @@ FilesystemMetadataInfo collect_root_path_metadata(const PathHierarchy &hierarchy
|
|
|
254
241
|
}
|
|
255
242
|
|
|
256
243
|
const bool needs_stat = (wants("size") && size == 0)
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
244
|
+
#if !defined(_WIN32)
|
|
245
|
+
|| wants("uid") || wants("gid") || wants("uname") || wants("gname")
|
|
246
|
+
#endif
|
|
247
|
+
;
|
|
261
248
|
|
|
262
249
|
struct stat stat_buffer;
|
|
263
250
|
bool have_stat = false;
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
#include <unordered_set>
|
|
11
11
|
#include <vector>
|
|
12
12
|
|
|
13
|
-
#include "archive_r/multi_volume_stream_base.h"
|
|
14
|
-
#include "archive_r/platform_compat.h"
|
|
15
13
|
#include "archive_r/entry_metadata.h"
|
|
14
|
+
#include "archive_r/multi_volume_stream_base.h"
|
|
16
15
|
#include "archive_r/path_hierarchy.h"
|
|
16
|
+
#include "archive_r/platform_compat.h"
|
|
17
17
|
|
|
18
18
|
namespace archive_r {
|
|
19
19
|
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
|
|
4
4
|
#include "archive_r/traverser.h"
|
|
5
5
|
#include "archive_r/entry.h"
|
|
6
|
+
#include "archive_r/entry_fault.h"
|
|
6
7
|
#include "archive_r/path_hierarchy.h"
|
|
7
8
|
#include "archive_r/path_hierarchy_utils.h"
|
|
8
|
-
#include "archive_r/entry_fault.h"
|
|
9
9
|
#include "archive_stack_orchestrator.h"
|
|
10
10
|
#include "archive_type.h"
|
|
11
11
|
#include "entry_fault_error.h"
|
|
@@ -48,14 +48,13 @@ Traverser::Traverser(std::vector<PathHierarchy> paths, TraverserOptions options)
|
|
|
48
48
|
throw std::invalid_argument("path hierarchy cannot be empty");
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
Traverser::Traverser(PathHierarchy path, TraverserOptions options)
|
|
55
|
-
: Traverser(std::vector<PathHierarchy>{std::move(path)}, std::move(options)) {}
|
|
54
|
+
: Traverser(std::vector<PathHierarchy>{ std::move(path) }, std::move(options)) {}
|
|
56
55
|
|
|
57
56
|
Traverser::Traverser(const std::string &path, TraverserOptions options)
|
|
58
|
-
: Traverser(std::vector<PathHierarchy>{make_single_path(path)}, std::move(options)) {}
|
|
57
|
+
: Traverser(std::vector<PathHierarchy>{ make_single_path(path) }, std::move(options)) {}
|
|
59
58
|
|
|
60
59
|
Traverser::~Traverser() = default;
|
|
61
60
|
|
|
@@ -65,7 +64,7 @@ Traverser::~Traverser() = default;
|
|
|
65
64
|
|
|
66
65
|
class Traverser::Iterator::Impl {
|
|
67
66
|
public:
|
|
68
|
-
|
|
67
|
+
Impl(std::vector<PathHierarchy> paths, bool at_end, const TraverserOptions &traverser_options)
|
|
69
68
|
: _paths(std::move(paths))
|
|
70
69
|
, _at_end(at_end)
|
|
71
70
|
, _archive_options(to_archive_option(traverser_options))
|
|
@@ -73,14 +72,9 @@ public:
|
|
|
73
72
|
if (_at_end) {
|
|
74
73
|
return;
|
|
75
74
|
}
|
|
76
|
-
if (_paths.empty()) {
|
|
77
|
-
throw std::invalid_argument("paths cannot be empty");
|
|
78
|
-
}
|
|
79
75
|
ensure_shared_orchestrator();
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
_at_end = true;
|
|
83
|
-
}
|
|
76
|
+
|
|
77
|
+
_at_end = !advance_to_next_root();
|
|
84
78
|
}
|
|
85
79
|
|
|
86
80
|
Entry &get_entry() {
|
|
@@ -100,7 +94,7 @@ public:
|
|
|
100
94
|
if (_current_entry->depth() == 0 && request_descend_into_archive && !_current_entry->is_directory()) {
|
|
101
95
|
request_descend_into_archive = false;
|
|
102
96
|
attempt_descend_into_root(_current_entry->path_hierarchy());
|
|
103
|
-
}
|
|
97
|
+
}
|
|
104
98
|
_current_entry.reset();
|
|
105
99
|
|
|
106
100
|
if (fetch_from_archive(request_descend_into_archive)) {
|
|
@@ -114,13 +108,13 @@ public:
|
|
|
114
108
|
if (advance_to_next_root()) {
|
|
115
109
|
return;
|
|
116
110
|
}
|
|
117
|
-
|
|
111
|
+
|
|
118
112
|
descend_pending_multi_volumes();
|
|
119
|
-
|
|
113
|
+
|
|
120
114
|
if (fetch_from_archive(false)) {
|
|
121
115
|
return;
|
|
122
116
|
}
|
|
123
|
-
|
|
117
|
+
|
|
124
118
|
_at_end = true;
|
|
125
119
|
}
|
|
126
120
|
|
|
@@ -128,10 +122,7 @@ public:
|
|
|
128
122
|
if (this == other) {
|
|
129
123
|
return true;
|
|
130
124
|
}
|
|
131
|
-
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
return _at_end && other->_at_end;
|
|
125
|
+
return other && _at_end && other->_at_end;
|
|
135
126
|
}
|
|
136
127
|
|
|
137
128
|
private:
|
|
@@ -143,9 +134,6 @@ private:
|
|
|
143
134
|
}
|
|
144
135
|
|
|
145
136
|
std::string normalize_path_string(const std::string &value) {
|
|
146
|
-
if (value.empty()) {
|
|
147
|
-
return value;
|
|
148
|
-
}
|
|
149
137
|
std::filesystem::path path_value(value);
|
|
150
138
|
return path_value.lexically_normal().string();
|
|
151
139
|
}
|
|
@@ -169,14 +157,9 @@ private:
|
|
|
169
157
|
}
|
|
170
158
|
ArchiveStackOrchestrator &orchestrator = *ensure_shared_orchestrator();
|
|
171
159
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
} catch (const EntryFaultError &error) {
|
|
178
|
-
EntryFault fault = enrich_orchestrator_error(error, orchestrator);
|
|
179
|
-
handle_orchestrator_error(fault);
|
|
160
|
+
if (orchestrator.advance(request_descend_into_archive)) {
|
|
161
|
+
set_current_entry(orchestrator.current_entry_hierarchy());
|
|
162
|
+
return true;
|
|
180
163
|
}
|
|
181
164
|
return false;
|
|
182
165
|
}
|
|
@@ -224,13 +207,9 @@ private:
|
|
|
224
207
|
}
|
|
225
208
|
}
|
|
226
209
|
|
|
227
|
-
void set_current_entry(PathHierarchy hierarchy) {
|
|
228
|
-
_current_entry = Entry::create(std::move(hierarchy), ensure_shared_orchestrator(), _default_descent);
|
|
229
|
-
}
|
|
210
|
+
void set_current_entry(PathHierarchy hierarchy) { _current_entry = Entry::create(std::move(hierarchy), ensure_shared_orchestrator(), _default_descent); }
|
|
230
211
|
|
|
231
|
-
void handle_orchestrator_error(const EntryFault &fault) {
|
|
232
|
-
dispatch_registered_fault(fault);
|
|
233
|
-
}
|
|
212
|
+
void handle_orchestrator_error(const EntryFault &fault) { dispatch_registered_fault(fault); }
|
|
234
213
|
|
|
235
214
|
void reset_source_state() {
|
|
236
215
|
reset_directory_traversal();
|
|
@@ -251,9 +230,6 @@ private:
|
|
|
251
230
|
if (fault.hierarchy.empty()) {
|
|
252
231
|
fault.hierarchy = orchestrator.current_entry_hierarchy();
|
|
253
232
|
}
|
|
254
|
-
if (fault.message.empty() && error.what()) {
|
|
255
|
-
fault.message = error.what();
|
|
256
|
-
}
|
|
257
233
|
return fault;
|
|
258
234
|
}
|
|
259
235
|
|
|
@@ -273,7 +249,7 @@ private:
|
|
|
273
249
|
// ============================================================================
|
|
274
250
|
|
|
275
251
|
Traverser::Iterator::Iterator(std::unique_ptr<Impl> impl)
|
|
276
|
-
|
|
252
|
+
: _impl(std::move(impl)) {}
|
|
277
253
|
|
|
278
254
|
Traverser::Iterator::~Iterator() = default;
|
|
279
255
|
|
data/lib/archive_r.rb
CHANGED
|
@@ -35,7 +35,11 @@ rescue LoadError
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
module Archive_r
|
|
38
|
-
|
|
38
|
+
version_path = File.expand_path('../VERSION', __dir__)
|
|
39
|
+
unless File.exist?(version_path)
|
|
40
|
+
version_path = File.expand_path('../../../VERSION', __dir__)
|
|
41
|
+
end
|
|
42
|
+
VERSION = File.read(version_path).strip
|
|
39
43
|
# Common archive formats excluding libarchive's mtree/raw pseudo formats
|
|
40
44
|
STANDARD_FORMATS = %w[
|
|
41
45
|
7zip ar cab cpio empty iso9660 lha rar tar warc xar zip
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- raizo.tcs
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2025-12-25 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: rake
|
|
@@ -51,6 +52,7 @@ files:
|
|
|
51
52
|
- LICENSE
|
|
52
53
|
- NOTICE
|
|
53
54
|
- README.md
|
|
55
|
+
- VERSION
|
|
54
56
|
- ext/archive_r/archive_r_ext.cc
|
|
55
57
|
- ext/archive_r/extconf.rb
|
|
56
58
|
- ext/archive_r/vendor/archive_r/LICENSE
|
|
@@ -94,6 +96,7 @@ metadata:
|
|
|
94
96
|
source_code_uri: https://github.com/raizo-tcs/archive_r
|
|
95
97
|
bug_tracker_uri: https://github.com/raizo-tcs/archive_r/issues
|
|
96
98
|
changelog_uri: https://github.com/raizo-tcs/archive_r/releases
|
|
99
|
+
post_install_message:
|
|
97
100
|
rdoc_options: []
|
|
98
101
|
require_paths:
|
|
99
102
|
- lib
|
|
@@ -108,7 +111,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
108
111
|
- !ruby/object:Gem::Version
|
|
109
112
|
version: '0'
|
|
110
113
|
requirements: []
|
|
111
|
-
rubygems_version: 4.
|
|
114
|
+
rubygems_version: 3.4.20
|
|
115
|
+
signing_key:
|
|
112
116
|
specification_version: 4
|
|
113
117
|
summary: 'Ruby bindings for archive_r: libarchive-based streaming traversal for recursive
|
|
114
118
|
nested archives (no temp files, no large in-memory buffers)'
|