Skip to content

Commit 66cdb46

Browse files
committed
Fix win build
1 parent 488d4c3 commit 66cdb46

7 files changed

Lines changed: 181 additions & 15 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 ──────────────────────────────────────────────────────────────────────

.github/workflows/tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ jobs:
134134
uses: actions/cache@v4
135135
with:
136136
path: C:\vcpkg\installed\x64-windows-static-md
137-
key: vcpkg-x64-windows-static-md-libarchive-v1
137+
key: vcpkg-x64-windows-static-md-libarchive-v2
138138

139139
- name: Install libarchive via vcpkg
140140
if: steps.vcpkg-cache.outputs.cache-hit != 'true'
@@ -144,7 +144,7 @@ jobs:
144144
New-Item -ItemType Directory -Force -Path $tripletDir | Out-Null
145145
Set-Content "$tripletDir\x64-windows-static-md.cmake" `
146146
"set(VCPKG_TARGET_ARCHITECTURE x64)`nset(VCPKG_CRT_LINKAGE dynamic)`nset(VCPKG_LIBRARY_LINKAGE static)`nset(VCPKG_BUILD_TYPE release)"
147-
C:\vcpkg\vcpkg.exe install libarchive `
147+
C:\vcpkg\vcpkg.exe install "libarchive[core,crypto]" `
148148
--triplet x64-windows-static-md `
149149
--overlay-triplets="$tripletDir" `
150150
--vcpkg-root C:\vcpkg

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

0 commit comments

Comments
 (0)