Skip to content

Commit dba70e8

Browse files
committed
Fix win build
1 parent 488d4c3 commit dba70e8

6 files changed

Lines changed: 177 additions & 13 deletions

File tree

.github/scripts/build-and-test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ find . -name '*.lo' -o -name '*.o' | xargs rm -f 2>/dev/null || true
6767
find . -name '.libs' -type d | xargs rm -rf 2>/dev/null || true
6868

6969
phpize
70-
./configure --with-php-config="$(which php-config)" "$CONFIGURE_LIBARCHIVE"
70+
./configure --with-php-config="$(which php-config)" "$CONFIGURE_LIBARCHIVE" ${EXTRA_CONFIGURE_FLAGS:-}
7171
make -f Makefile -j"$(nproc)"
7272

7373
# ── Test ──────────────────────────────────────────────────────────────────────

config.m4

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ PHP_ARG_WITH([libarchive],
33
[AS_HELP_STRING([[--with-libarchive[=DIR]]],
44
[Include libarchive support])])
55

6+
PHP_ARG_WITH([libarchive-read-callbacks],
7+
[whether to use stream read callbacks],
8+
[AS_HELP_STRING([[--with-libarchive-read-callbacks]],
9+
[Use libarchive read callbacks instead of FILE* for stream sources (required on platforms without fopencookie)])],
10+
[no], [no])
11+
612
if test "$PHP_LIBARCHIVE" != "no"; then
713
if test -r $PHP_LIBARCHIVE/include/archive.h; then
814
LIBARCHIVE_DIR=$PHP_LIBARCHIVE
@@ -53,6 +59,13 @@ if test "$PHP_LIBARCHIVE" != "no"; then
5359

5460
extra_cflags="-Wall $cflags_null -fvisibility=hidden"
5561

62+
ext_sources="libarchive.c stream.c"
63+
if test "$PHP_LIBARCHIVE_READ_CALLBACKS" != "no"; then
64+
AC_DEFINE(HAVE_LIBARCHIVE_STREAM_CALLBACKS, 1,
65+
[Use stream read callbacks for archive sources])
66+
ext_sources="$ext_sources stream_callbacks.c"
67+
fi
68+
5669
PHP_SUBST(ARCHIVE_SHARED_LIBADD)
57-
PHP_NEW_EXTENSION(archive, libarchive.c stream.c, $ext_shared,,$extra_cflags)
70+
PHP_NEW_EXTENSION(archive, $ext_sources, $ext_shared,,$extra_cflags)
5871
fi

config.w32

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ if (PHP_LIBARCHIVE != "no") {
77
CHECK_HEADER_ADD_INCLUDE("archive.h", "CFLAGS_ARCHIVE",
88
PHP_LIBARCHIVE + "/include;" + PHP_PHP_BUILD + "/include")) {
99

10-
EXTENSION("archive", "libarchive.c stream.c", true, "/DLIBARCHIVE_STATIC");
10+
EXTENSION("archive", "libarchive.c stream.c stream_callbacks.c", true, "/DLIBARCHIVE_STATIC /Zc:preprocessor");
1111

1212
// Always-needed Windows system libs.
1313
var libs = "bcrypt.lib xmllite.lib crypt32.lib ws2_32.lib";

libarchive.c

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,20 @@ static void arch_oh_free_obj(zend_object *zobj)
437437
case ARCH_SOURCE_FILE:
438438
zend_string_release(obj->source.file_location);
439439
break;
440+
#ifndef HAVE_LIBARCHIVE_STREAM_CALLBACKS
440441
case ARCH_SOURCE_STREAM:
441442
zval_ptr_dtor(&obj->source.stream_zv);
442443
break;
444+
#else
445+
case ARCH_SOURCE_STREAM_CB:
446+
if (obj->archive == NULL) {
447+
/* Archive never opened; stream_close_cb won't fire. */
448+
zval_ptr_dtor(&obj->source.stream_cb->stream_zv);
449+
efree(obj->source.stream_cb);
450+
}
451+
/* else: archive_read_free below triggers stream_close_cb. */
452+
break;
453+
#endif
443454
case ARCH_SOURCE_NONE:
444455
break;
445456
}
@@ -579,36 +590,63 @@ static bool arch_obj_open_read(arch_object *arch_obj)
579590
* Switch the source so arch_obj_open_read_stream can take over and
580591
* the stream resource is kept alive for the lifetime of the archive. */
581592
zend_string_release(arch_obj->source.file_location);
593+
#ifdef HAVE_LIBARCHIVE_STREAM_CALLBACKS
594+
arch_stream_cb *d = emalloc(sizeof *d);
595+
php_stream_to_zval(stream, &d->stream_zv); /* transfer the only ref */
596+
arch_obj->source.stream_cb = d;
597+
arch_obj->source_kind = ARCH_SOURCE_STREAM_CB;
598+
#else
582599
arch_obj->source_kind = ARCH_SOURCE_STREAM;
583600
php_stream_to_zval(stream, &arch_obj->source.stream_zv);
601+
#endif
584602
return arch_obj_open_read_stream(arch_obj);
585603
}
586604

587605
return true;
588606
}
589607

608+
#ifdef HAVE_LIBARCHIVE_STREAM_CALLBACKS
609+
extern bool arch_open_archive_with_stream_callbacks(arch_object *arch_obj);
610+
#endif
611+
590612
static bool arch_obj_open_read_stream(arch_object *arch_obj)
591613
{
592614
php_stream *stream;
615+
#ifdef HAVE_LIBARCHIVE_STREAM_CALLBACKS
616+
php_stream_from_zval_no_verify(stream, &arch_obj->source.stream_cb->stream_zv);
617+
#else
593618
php_stream_from_zval_no_verify(stream, &arch_obj->source.stream_zv);
619+
#endif
594620
if (!stream) {
595621
zend_throw_exception(except_ce, "Invalid stream resource", -1);
596622
return false;
597623
}
598624

599-
FILE *fp;
600-
int res = php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void **)&fp, REPORT_ERRORS);
601-
if (res != SUCCESS) {
602-
zend_throw_exception(except_ce, "Could not cast stream to FILE*", -1);
603-
return false;
604-
}
605-
606625
arch_obj->archive = archive_read_new();
607626
arch_obj_setup_support(arch_obj);
608627
if (arch_obj->password_fci.size != 0) {
609628
archive_read_set_passphrase_callback(arch_obj->archive, arch_obj,
610629
arch_passphrase_callback);
611630
}
631+
632+
#ifdef HAVE_LIBARCHIVE_STREAM_CALLBACKS
633+
if (!arch_open_archive_with_stream_callbacks(arch_obj)) {
634+
zend_throw_exception_ex(
635+
except_ce, archive_errno(arch_obj->archive),
636+
"Could not open archive from stream: %s",
637+
archive_error_string(arch_obj->archive));
638+
return false;
639+
}
640+
return true;
641+
#else
642+
FILE *fp;
643+
int res = php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void **)&fp,
644+
REPORT_ERRORS);
645+
if (res != SUCCESS) {
646+
zend_throw_exception(except_ce, "Could not cast stream to FILE*", -1);
647+
return false;
648+
}
649+
612650
res = archive_read_open_FILE(arch_obj->archive, fp);
613651
if (res != ARCHIVE_OK) {
614652
zend_throw_exception_ex(
@@ -617,8 +655,8 @@ static bool arch_obj_open_read_stream(arch_object *arch_obj)
617655
archive_error_string(arch_obj->archive));
618656
return false;
619657
}
620-
621658
return true;
659+
#endif
622660
}
623661

624662
PHP_METHOD(libarchive_Archive, fromStream)
@@ -632,8 +670,15 @@ PHP_METHOD(libarchive_Archive, fromStream)
632670

633671
object_init_ex(return_value, arch_ce);
634672
arch_object *arch_obj = arch_object_from_zv(return_value);
673+
#ifdef HAVE_LIBARCHIVE_STREAM_CALLBACKS
674+
arch_stream_cb *d = emalloc(sizeof *d);
675+
ZVAL_COPY(&d->stream_zv, stream_zv);
676+
arch_obj->source.stream_cb = d;
677+
arch_obj->source_kind = ARCH_SOURCE_STREAM_CB;
678+
#else
635679
arch_obj->source_kind = ARCH_SOURCE_STREAM;
636680
ZVAL_COPY(&arch_obj->source.stream_zv, stream_zv);
681+
#endif
637682
arch_obj->write_disk_options = (int)flags;
638683
}
639684

php_libarchive.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,39 @@ ZEND_TSRMLS_CACHE_EXTERN()
3232
#define nullable _Nullable
3333
#define unspecnull _Null_unspecified
3434

35+
/* On Windows, where fopencookie and similar is unavailable, the callback path
36+
* is always available; on other platforms it is enabled when the extension was
37+
* built with --with-libarchive-read-callbacks. */
38+
#if defined(PHP_WIN32) && !defined(HAVE_LIBARCHIVE_STREAM_CALLBACKS)
39+
#define HAVE_LIBARCHIVE_STREAM_CALLBACKS 1
40+
#endif
41+
3542
typedef enum {
3643
ARCH_SOURCE_NONE,
3744
ARCH_SOURCE_FILE,
45+
#ifndef HAVE_LIBARCHIVE_STREAM_CALLBACKS
3846
ARCH_SOURCE_STREAM,
47+
#else
48+
ARCH_SOURCE_STREAM_CB,
49+
#endif
3950
} arch_source_kind;
4051

52+
#ifdef HAVE_LIBARCHIVE_STREAM_CALLBACKS
53+
typedef struct {
54+
zval stream_zv;
55+
char buf[65536];
56+
} arch_stream_cb;
57+
#endif
58+
4159
typedef struct _arch_object {
4260
arch_source_kind source_kind;
4361
union {
44-
zend_string *file_location; /* ARCH_SOURCE_FILE */
45-
zval stream_zv; /* ARCH_SOURCE_STREAM */
62+
zend_string *file_location; /* ARCH_SOURCE_FILE */
63+
#ifndef HAVE_LIBARCHIVE_STREAM_CALLBACKS
64+
zval stream_zv; /* ARCH_SOURCE_STREAM */
65+
#else
66+
arch_stream_cb *stream_cb; /* ARCH_SOURCE_STREAM_CB */
67+
#endif
4668
} source;
4769
struct archive *nullable archive;
4870
struct archive *nullable arch_disk;

stream_callbacks.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#ifdef HAVE_CONFIG_H
2+
#include "config.h"
3+
#endif
4+
5+
#ifndef HAVE_LIBARCHIVE_STREAM_CALLBACKS
6+
#error "stream_callbacks.c compiled without HAVE_LIBARCHIVE_STREAM_CALLBACKS"
7+
#endif
8+
9+
#include <php.h>
10+
#include <archive.h>
11+
#include <stdbool.h>
12+
#include "php_libarchive.h"
13+
14+
#define STREAM_BLOCK_SIZE sizeof(((arch_stream_cb *)0)->buf)
15+
16+
static la_ssize_t stream_read_cb(struct archive *a, void *client_data,
17+
const void **buffer)
18+
{
19+
arch_stream_cb *d = (arch_stream_cb *)client_data;
20+
php_stream *stream;
21+
size_t n;
22+
23+
(void)a;
24+
php_stream_from_zval_no_verify(stream, &d->stream_zv);
25+
*buffer = d->buf;
26+
n = php_stream_read(stream, d->buf, STREAM_BLOCK_SIZE);
27+
return (la_ssize_t)n; /* 0 signals EOF to libarchive */
28+
}
29+
30+
static la_int64_t stream_skip_cb(struct archive *a, void *client_data,
31+
la_int64_t request)
32+
{
33+
arch_stream_cb *d = (arch_stream_cb *)client_data;
34+
php_stream *stream;
35+
36+
(void)a;
37+
php_stream_from_zval_no_verify(stream, &d->stream_zv);
38+
if (php_stream_seek(stream, (zend_off_t)request, SEEK_CUR) == 0) {
39+
return request;
40+
}
41+
return 0; /* tell libarchive to use read-and-discard */
42+
}
43+
44+
static la_int64_t stream_seek_cb(struct archive *a, void *client_data,
45+
la_int64_t offset, int whence)
46+
{
47+
arch_stream_cb *d = (arch_stream_cb *)client_data;
48+
php_stream *stream;
49+
zend_off_t pos;
50+
51+
(void)a;
52+
php_stream_from_zval_no_verify(stream, &d->stream_zv);
53+
if (php_stream_seek(stream, (zend_off_t)offset, whence) != 0) {
54+
return ARCHIVE_FAILED;
55+
}
56+
pos = php_stream_tell(stream);
57+
if (pos < 0) {
58+
return ARCHIVE_FAILED;
59+
}
60+
return (la_int64_t)pos;
61+
}
62+
63+
static int stream_close_cb(struct archive *a, void *client_data)
64+
{
65+
arch_stream_cb *d = (arch_stream_cb *)client_data;
66+
67+
(void)a;
68+
zval_ptr_dtor(&d->stream_zv);
69+
efree(d);
70+
return ARCHIVE_OK;
71+
}
72+
73+
bool arch_open_archive_with_stream_callbacks(arch_object *arch_obj)
74+
{
75+
arch_stream_cb *d = arch_obj->source.stream_cb;
76+
77+
archive_read_set_read_callback(arch_obj->archive, stream_read_cb);
78+
archive_read_set_skip_callback(arch_obj->archive, stream_skip_cb);
79+
archive_read_set_seek_callback(arch_obj->archive, stream_seek_cb);
80+
archive_read_set_close_callback(arch_obj->archive, stream_close_cb);
81+
archive_read_set_callback_data(arch_obj->archive, d);
82+
83+
return archive_read_open1(arch_obj->archive) == ARCHIVE_OK;
84+
}

0 commit comments

Comments
 (0)