From 1283c2b083a4eb01ca207d8617f1158befe919c5 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 9 Feb 2025 20:32:52 +0100 Subject: [PATCH 1/4] Implement GH-17668: zlib streams should support locking --- ext/zlib/tests/zlib_wrapper_flock_basic.phpt | 6 +++--- ext/zlib/zlib_fopen_wrapper.c | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/ext/zlib/tests/zlib_wrapper_flock_basic.phpt b/ext/zlib/tests/zlib_wrapper_flock_basic.phpt index 95329dd003eb8..89656c7fca6bc 100644 --- a/ext/zlib/tests/zlib_wrapper_flock_basic.phpt +++ b/ext/zlib/tests/zlib_wrapper_flock_basic.phpt @@ -1,13 +1,13 @@ --TEST-- -Test function stream_get_meta_data on a zlib stream +Test function flock on a zlib stream --EXTENSIONS-- zlib --FILE-- --EXPECT-- -bool(false) +bool(true) diff --git a/ext/zlib/zlib_fopen_wrapper.c b/ext/zlib/zlib_fopen_wrapper.c index b414b33a8724e..9cce8a6522be4 100644 --- a/ext/zlib/zlib_fopen_wrapper.c +++ b/ext/zlib/zlib_fopen_wrapper.c @@ -95,6 +95,21 @@ static int php_gziop_flush(php_stream *stream) return gzflush(self->gz_file, Z_SYNC_FLUSH); } +static int php_gziop_set_option(php_stream *stream, int option, int value, void *ptrparam) +{ + struct php_gz_stream_data_t *self = stream->abstract; + + switch (option) { + case PHP_STREAM_OPTION_LOCKING: + case PHP_STREAM_OPTION_META_DATA_API: + return self->stream->ops->set_option(self->stream, option, value, ptrparam); + default: + break; + } + + return PHP_STREAM_OPTION_RETURN_NOTIMPL; +} + const php_stream_ops php_stream_gzio_ops = { php_gziop_write, php_gziop_read, php_gziop_close, php_gziop_flush, @@ -102,7 +117,7 @@ const php_stream_ops php_stream_gzio_ops = { php_gziop_seek, NULL, /* cast */ NULL, /* stat */ - NULL /* set_option */ + php_gziop_set_option /* set_option */ }; php_stream *php_stream_gzopen(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, From 2de6b69256c023f07fb753789088f238eeeaaeec Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 9 Feb 2025 21:06:28 +0100 Subject: [PATCH 2/4] Add missing error reporting to reading/writing zlib streams --- ext/zlib/zlib_fopen_wrapper.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/ext/zlib/zlib_fopen_wrapper.c b/ext/zlib/zlib_fopen_wrapper.c index 9cce8a6522be4..4f07926e5e206 100644 --- a/ext/zlib/zlib_fopen_wrapper.c +++ b/ext/zlib/zlib_fopen_wrapper.c @@ -30,6 +30,18 @@ struct php_gz_stream_data_t { php_stream *stream; }; +static void php_gziop_report_errors(php_stream *stream, size_t count, const char *verb) +{ + if (!(stream->flags & PHP_STREAM_FLAG_SUPPRESS_ERRORS)) { + struct php_gz_stream_data_t *self = stream->abstract; + int error = 0; + gzerror(self->gz_file, &error); + if (error == Z_ERRNO) { + php_error_docref(NULL, E_NOTICE, "%s of %zu bytes failed with errno=%d %s", verb, count, errno, strerror(errno)); + } + } +} + static ssize_t php_gziop_read(php_stream *stream, char *buf, size_t count) { struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract; @@ -38,6 +50,11 @@ static ssize_t php_gziop_read(php_stream *stream, char *buf, size_t count) /* XXX this needs to be looped for the case count > UINT_MAX */ read = gzread(self->gz_file, buf, count); + /* Notify user of error, like the standard file wrapper normally does (e.g. errno=13 on mandatory lock failure). */ + if (UNEXPECTED(read < 0)) { + php_gziop_report_errors(stream, count, "Read"); + } + if (gzeof(self->gz_file)) { stream->eof = 1; } @@ -50,7 +67,14 @@ static ssize_t php_gziop_write(php_stream *stream, const char *buf, size_t count struct php_gz_stream_data_t *self = (struct php_gz_stream_data_t *) stream->abstract; /* XXX this needs to be looped for the case count > UINT_MAX */ - return gzwrite(self->gz_file, (char *) buf, count); + int written = gzwrite(self->gz_file, (char *) buf, count); + + /* Notify user of error, like the standard file wrapper normally does (e.g. errno=13 on mandatory lock failure). */ + if (UNEXPECTED(written < 0)) { + php_gziop_report_errors(stream, count, "Write"); + } + + return written; } static int php_gziop_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs) From c67996fd4bbd5a6d9fdb914ca8d0fccf16e0d7da Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Sun, 9 Feb 2025 21:06:37 +0100 Subject: [PATCH 3/4] Add test for mandatory zlib locks Windows has mandatory locks, so we can test the exclusive lock reliably. --- .../tests/zlib_lock_mandatory_windows.phpt | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 ext/zlib/tests/zlib_lock_mandatory_windows.phpt diff --git a/ext/zlib/tests/zlib_lock_mandatory_windows.phpt b/ext/zlib/tests/zlib_lock_mandatory_windows.phpt new file mode 100644 index 0000000000000..f34c54a2df84b --- /dev/null +++ b/ext/zlib/tests/zlib_lock_mandatory_windows.phpt @@ -0,0 +1,52 @@ +--TEST-- +Test mandatory locking on Windows +--EXTENSIONS-- +zlib +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +without wrapper +bool(true) + +Notice: fread(): Read of 1 bytes failed with errno=13 Permission denied in %s on line %d +bool(false) +string(1) "W" + +with wrapper +bool(true) + +Notice: fread(): Read of 1 bytes failed with errno=13 Permission denied in %s on line %d +bool(false) +string(1) "W" From 7525680cbad3cd32fcb594db168bf7e94ecf2ee5 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 10 Feb 2025 23:10:33 +0100 Subject: [PATCH 4/4] Split file --- ext/zlib/tests/005.txt.gz | Bin 0 -> 150 bytes ext/zlib/tests/zlib_lock_mandatory_windows.phpt | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 ext/zlib/tests/005.txt.gz diff --git a/ext/zlib/tests/005.txt.gz b/ext/zlib/tests/005.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..07805db7558078115fc0dc63a4426a87508d382a GIT binary patch literal 150 zcmV;H0BQdpiwFo?U!X()128Z&E_8Tw06mQ{4gxU@1pB;VJ3d0g3#iS-cZmqL6gx!W z^%x}RygS!d1Kh@V0JhN>q*^qS#RPf;R27L%W^soQ` E06hOe-2eap literal 0 HcmV?d00001 diff --git a/ext/zlib/tests/zlib_lock_mandatory_windows.phpt b/ext/zlib/tests/zlib_lock_mandatory_windows.phpt index f34c54a2df84b..04ed2ab251056 100644 --- a/ext/zlib/tests/zlib_lock_mandatory_windows.phpt +++ b/ext/zlib/tests/zlib_lock_mandatory_windows.phpt @@ -10,7 +10,7 @@ if (PHP_OS_FAMILY !== "Windows") die("skip Only for Windows because it has manda