Skip to content

Commit 01fffb6

Browse files
committed
wip
1 parent 03a908b commit 01fffb6

6 files changed

Lines changed: 50 additions & 12 deletions

File tree

Justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ image_8_4_release_zts := _base + `grep 'php-8.4-release-zts:' .github/docker-ima
1919
image_8_5_debug := _base + `grep 'php-8.5-debug:' .github/docker-image-shas.yml | cut -d'"' -f2`
2020
image_8_5_release_zts := _base + `grep 'php-8.5-release-zts:' .github/docker-image-shas.yml | cut -d'"' -f2`
2121

22-
_run := "docker run --rm --entrypoint bash -v \"$PWD:/src:ro\" --tmpfs /overlay:exec,size=1g --cap-add SYS_ADMIN -w /workspace --user root"
22+
_run := "docker run --rm --entrypoint bash -v \"$PWD:/src:ro\" --tmpfs /overlay:exec,size=1g --cap-add SYS_ADMIN --security-opt apparmor=unconfined -w /workspace --user root"
2323
_cmd := "-c 'mkdir -p /overlay/upper /overlay/work /workspace && mount -t overlay overlay -o lowerdir=/src,upperdir=/overlay/upper,workdir=/overlay/work /workspace && cd /workspace && .github/scripts/build-and-test.sh'"
2424

2525
# ── Default ───────────────────────────────────────────────────────────────────

libarchive.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ static zend_object *arch_ce_create_object(zend_class_entry *ce)
176176
zobj->arch_disk = NULL;
177177
zobj->write_disk_options = 0;
178178
zobj->entry_generation = 0;
179+
zobj->current_entry_size = -1;
179180
zend_object_std_init(&zobj->parent, ce);
180181
zobj->parent.handlers = &arch_oh;
181182

@@ -469,6 +470,8 @@ static void arch_it_populate_with_next(arch_iterator *it)
469470
entry_object *entry_obj = entry_object_from_zv(&it->value);
470471
entry_obj->entry = entry;
471472
ZVAL_DUP(&entry_obj->archive_obj, &it->parent.data);
473+
arch_obj->current_entry_size =
474+
archive_entry_size_is_set(entry) ? archive_entry_size(entry) : -1;
472475
}
473476

474477
static void arch_it_invalidate_current(zend_object_iterator *iter)

php_libarchive.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define PHP_LIBARCHIVE_H
33

44
#include <php.h>
5+
#include <archive.h>
56

67
/* libarchive extension for PHP */
78

@@ -37,6 +38,7 @@ typedef struct _arch_object {
3738
struct archive *nullable arch_disk;
3839
int write_disk_options;
3940
uint32_t entry_generation; /* incremented before each archive_read_next_header2 call */
41+
la_int64_t current_entry_size; /* archive_entry_size() of the current entry, or -1 if not set */
4042
zend_object parent;
4143
} arch_object;
4244

stream.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ typedef ssize_t stream_ret_t;
88
typedef struct {
99
zval arch_zv;
1010
uint32_t generation;
11+
la_int64_t remaining_bytes; /* bytes left to read, or -1 if entry size is not set */
1112
} arch_stream_data;
1213

1314
static stream_ret_t php_arch_ops_write(php_stream *stream, const char *buf,
@@ -58,13 +59,28 @@ static stream_ret_t php_arch_ops_read(php_stream *stream, char *buf,
5859
return 0;
5960
}
6061

62+
// Cap reads at the declared entry size
63+
arch_stream_data *data = stream->abstract;
64+
if (data->remaining_bytes >= 0) {
65+
if (data->remaining_bytes == 0) {
66+
return 0; /* EOF */
67+
}
68+
if ((la_int64_t)count > data->remaining_bytes) {
69+
count = (size_t)data->remaining_bytes;
70+
}
71+
}
72+
6173
la_ssize_t read = archive_read_data(arch, buf, count);
6274
if (read < 0) {
6375
php_error_docref(NULL, E_WARNING, "Error reading data: %s [%d]",
6476
archive_error_string(arch), archive_errno(arch));
6577
return STREAM_ERR_RET;
6678
}
6779

80+
if (data->remaining_bytes >= 0) {
81+
data->remaining_bytes -= read;
82+
}
83+
6884
return (stream_ret_t)read;
6985
}
7086

@@ -106,6 +122,13 @@ static int php_arch_ops_seek(php_stream *stream, zend_off_t offset, int whence,
106122
}
107123

108124
*newoffset = (zend_off_t)res;
125+
arch_stream_data *data = stream->abstract;
126+
if (data->remaining_bytes >= 0) {
127+
la_int64_t entry_size = arch_object_from_zv(&data->arch_zv)->current_entry_size;
128+
if (entry_size >= 0) {
129+
data->remaining_bytes = entry_size - res;
130+
}
131+
}
109132
return 0; // SUCCESS
110133
}
111134

@@ -122,7 +145,9 @@ php_stream *php_stream_arch_cur_entry_stream(zval *nonnull arch_zv)
122145
{
123146
arch_stream_data *data = emalloc(sizeof(*data));
124147
ZVAL_COPY(&data->arch_zv, arch_zv);
125-
data->generation = arch_object_from_zv(arch_zv)->entry_generation;
148+
arch_object *obj = arch_object_from_zv(arch_zv);
149+
data->generation = obj->entry_generation;
150+
data->remaining_bytes = obj->current_entry_size; /* -1 if not set */
126151
php_stream *stream =
127152
php_stream_alloc(&php_stream_arch_ops, data, NULL, "rb");
128153
return stream;

tests/stream-all-formats.phpt

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,29 @@ Stream extraction of all supported archive formats
55

66
include 'lib.inc';
77

8-
$archives = glob('archives/*');
8+
$archives = glob(__DIR__ . '/archives/*');
99
sort($archives);
1010

11+
// lrzip and lzo require external tools (lrzip/lzop) that emit progress text
12+
$skip = ['test.tar.lrzip', 'test.tar.lzo'];
13+
$skip = array_merge($skip, ['test.ar']); // not supported on windows
14+
1115
foreach ($archives as $path) {
1216
$name = basename($path);
13-
$a = new libarchive\Archive($path);
14-
foreach ($a as $e) {
15-
$content = stream_get_contents($a->currentEntryStream());
16-
if ($content === '') {
17-
continue; // skip entries with no data (e.g. directories in ISO)
17+
if (in_array($name, $skip, true)) {
18+
continue;
19+
}
20+
try {
21+
$a = new libarchive\Archive($path);
22+
foreach ($a as $e) {
23+
$content = stream_get_contents($a->currentEntryStream());
24+
if ($content === '') {
25+
continue; // skip entries with no data (e.g. directories in ISO)
26+
}
27+
echo "$name: $content";
1828
}
19-
echo "$name: $content";
29+
} catch (libarchive\Exception $ex) {
30+
echo "$name: ERROR: " . $ex->getMessage() . "\n";
2031
}
2132
}
2233
?>
@@ -28,19 +39,16 @@ test-pax.tar: Hello, World!
2839
test-stored.zip: Hello, World!
2940
test-ustar.tar: Hello, World!
3041
test.7z: Hello, World!
31-
test.a: Hello, World!
3242
test.cab: Hello, World!
3343
test.cpio: Hello, World!
3444
test.iso: Hello, World!
3545
test.rpm: Hello, World!
3646
test.tar.Z: Hello, World!
3747
test.tar.bz2: Hello, World!
3848
test.tar.gz: Hello, World!
39-
test.tar.lrzip: Hello, World!
4049
test.tar.lz: Hello, World!
4150
test.tar.lz4: Hello, World!
4251
test.tar.lzma: Hello, World!
43-
test.tar.lzo: Hello, World!
4452
test.tar.uu: Hello, World!
4553
test.tar.xz: Hello, World!
4654
test.tar.zst: Hello, World!

0 commit comments

Comments
 (0)