summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemi Collet <remi@remirepo.net>2023-10-12 12:48:34 +0200
committerRemi Collet <remi@php.net>2023-10-12 12:48:34 +0200
commit9104d986ab93577575eab6cc7c750b1adb84b46a (patch)
tree9fba62d46982147576c44989ee802d60431f34e2
parent858524052cd950ffe79d40464df8a83cedf19776 (diff)
implement rpm stream wrapper
-rw-r--r--package.xml9
-rw-r--r--php_rpminfo.h2
-rw-r--r--rpminfo.c179
-rw-r--r--tests/014-stream.phpt34
4 files changed, 218 insertions, 6 deletions
diff --git a/package.xml b/package.xml
index 20ec125..18e098f 100644
--- a/package.xml
+++ b/package.xml
@@ -13,10 +13,10 @@ Documentation: https://www.php.net/rpminfo
<email>remi@php.net</email>
<active>yes</active>
</lead>
- <date>2023-09-26</date>
+ <date>2023-10-12</date>
<version>
- <release>0.7.1dev</release>
- <api>0.7.0</api>
+ <release>0.8.0dev</release>
+ <api>0.0.0</api>
</version>
<stability>
<release>stable</release>
@@ -24,7 +24,7 @@ Documentation: https://www.php.net/rpminfo
</stability>
<license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license>
<notes>
--
+- implement rpm stream wrapper
</notes>
<contents>
<dir name="/">
@@ -56,6 +56,7 @@ Documentation: https://www.php.net/rpminfo
<file name="011-rpmvercmp_error8.phpt" role="test"/>
<file name="012-rpmaddtag.phpt" role="test"/>
<file name="013-rpmdbsearch-error.phpt" role="test"/>
+ <file name="014-stream.phpt" role="test"/>
<file name="bidon.rpm" role="test"/>
<file name="bidon-src.rpm" role="test"/>
</dir>
diff --git a/php_rpminfo.h b/php_rpminfo.h
index 2ba4727..7df010e 100644
--- a/php_rpminfo.h
+++ b/php_rpminfo.h
@@ -22,7 +22,7 @@
extern zend_module_entry rpminfo_module_entry;
#define phpext_rpminfo_ptr &rpminfo_module_entry
-#define PHP_RPMINFO_VERSION "0.7.1-dev"
+#define PHP_RPMINFO_VERSION "0.8.0-dev"
#ifdef PHP_WIN32
# define PHP_RPMINFO_API __declspec(dllexport)
diff --git a/rpminfo.c b/rpminfo.c
index 1212a7e..ab2182d 100644
--- a/rpminfo.c
+++ b/rpminfo.c
@@ -23,6 +23,7 @@
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
+#include "ext/standard/php_string.h"
#include <fcntl.h>
#include <rpm/rpmdb.h>
@@ -34,6 +35,17 @@
#include "rpminfo_arginfo.h"
+struct php_rpm_stream_data_t {
+ FD_t gzdi;
+ Header h;
+ rpmfiles files;
+ rpmfi fi;
+ php_stream *stream;
+};
+
+#define STREAM_DATA_FROM_STREAM() \
+ struct php_rpm_stream_data_t *self = (struct php_rpm_stream_data_t *) stream->abstract;
+
ZEND_DECLARE_MODULE_GLOBALS(rpminfo)
static rpmts rpminfo_getts(void) {
@@ -302,7 +314,7 @@ static unsigned char nibble(char c) {
if (c >= 'A' && c <= 'F') {
return (c - 'A') + 10;
}
- return 0;
+ return 0;
}
static int hex2bin(const char *hex, char *bin, int len) {
@@ -561,6 +573,169 @@ PHP_FUNCTION(rpmaddtag)
}
/* }}} */
+static ssize_t php_rpm_ops_read(php_stream *stream, char *buf, size_t count)
+{
+ ssize_t n = -1;
+ STREAM_DATA_FROM_STREAM();
+
+ if (self) {
+ n = rpmfiArchiveRead(self->fi, buf, count);
+ if (n == 0 || n < (ssize_t)count) {
+ stream->eof = 1;
+ }
+ }
+ return n;
+}
+
+static int php_rpm_ops_close(php_stream *stream, int close_handle)
+{
+ STREAM_DATA_FROM_STREAM();
+
+ if (self) {
+ if (close_handle) {
+ Fclose(self->gzdi);
+ rpmfilesFree(self->files);
+ rpmfiFree(self->fi);
+ headerFree(self->h);
+ }
+ efree(self);
+ }
+ stream->abstract = NULL;
+
+ return EOF;
+}
+
+
+const php_stream_ops php_stream_rpmio_ops = {
+ NULL, /* write */
+ php_rpm_ops_read,
+ php_rpm_ops_close,
+ NULL, /* flush */
+ "rpm",
+ NULL, /* seek */
+ NULL, /* cast */
+ NULL, /* stat */
+ NULL /* set_option */
+};
+
+php_stream *php_stream_rpm_opener(php_stream_wrapper *wrapper,
+ const char *path,
+ const char *mode,
+ int options,
+ zend_string **opened_path,
+ php_stream_context *context STREAMS_DC)
+{
+ size_t path_len;
+ zend_string *file_basename;
+ char file_dirname[MAXPATHLEN];
+ char *fragment;
+ size_t fragment_len;
+ php_stream *stream = NULL;
+ struct php_rpm_stream_data_t *self;
+ FD_t fdi;
+ FD_t gzdi;
+ int rc;
+ Header h;
+ char rpmio_flags[80];
+ const char *compr;
+ rpmfiles files;
+ rpmfi fi;
+ rpmts ts = rpminfo_getts();
+
+ fragment = strchr(path, '#');
+ if (!fragment) {
+ return NULL;
+ }
+ if (strncasecmp("rpm://", path, 6) == 0) {
+ path += 6;
+ }
+ fragment_len = strlen(fragment);
+ if (fragment_len < 1) {
+ return NULL;
+ }
+ path_len = strlen(path);
+ if (path_len >= MAXPATHLEN || mode[0] != 'r') {
+ return NULL;
+ }
+ memcpy(file_dirname, path, path_len - fragment_len);
+ file_dirname[path_len - fragment_len] = '\0';
+ file_basename = php_basename(path, path_len - fragment_len, NULL, 0);
+ fragment++;
+ if (php_check_open_basedir(file_dirname)) {
+ zend_string_release_ex(file_basename, 0);
+ return NULL;
+ }
+ fdi = Fopen(file_dirname, "r.ufdio");
+ if (Ferror(fdi)) {
+ zend_string_release_ex(file_basename, 0);
+ return NULL;
+ }
+ rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h);
+ if (rc != RPMRC_OK && rc != RPMRC_NOKEY && rc != RPMRC_NOTTRUSTED) {
+ zend_string_release_ex(file_basename, 0);
+ return NULL;
+ }
+
+ compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
+ snprintf(rpmio_flags, sizeof(rpmio_flags), "r.%s", compr ? compr : "gzip");
+ gzdi = Fdopen(fdi, rpmio_flags);
+ if (gzdi == NULL) {
+ zend_string_release_ex(file_basename, 0);
+ return NULL;
+ }
+
+ files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
+ fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE_CONTENT_FIRST);
+
+ while((rc = rpmfiNext(fi)) >=0) {
+ const char *fn = rpmfiFN(fi);
+ /*
+ printf("Name=%s, Size=%d, N=%d, mode=%d, reg=%d, content=%d\n", fn,
+ (int)rpmfiFSize(fi), (int)rpmfiFNlink(fi), (int)rpmfiFMode(fi),
+ (int)S_ISREG(rpmfiFMode(fi)), (int)rpmfiArchiveHasContent(fi));
+ */
+ if (!strcmp(fn, fragment)) {
+ break;
+ }
+ }
+ if (rc == RPMERR_ITER_END || !S_ISREG(rpmfiFMode(fi)) || !rpmfiArchiveHasContent(fi)) {
+ Fclose(gzdi);
+ rpmfilesFree(files);
+ rpmfiFree(fi);
+ headerFree(h);
+ } else {
+ self = emalloc(sizeof(*self));
+ self->gzdi = gzdi;
+ self->files = files;
+ self->fi = fi;
+ self->h = h;
+
+ stream = php_stream_alloc(&php_stream_rpmio_ops, self, NULL, mode);
+ }
+ zend_string_release_ex(file_basename, 0);
+
+ return stream;
+}
+
+static const php_stream_wrapper_ops rpm_stream_wops = {
+ php_stream_rpm_opener,
+ NULL, /* close */
+ NULL, /* fstat */
+ NULL, /* stat */
+ NULL, /* opendir */
+ "RPM wrapper",
+ NULL, /* unlink */
+ NULL, /* rename */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL /* metadata */
+};
+
+const php_stream_wrapper php_stream_rpm_wrapper = {
+ &rpm_stream_wops,
+ NULL,
+ 0 /* is_url */
+};
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(rpminfo)
@@ -606,6 +781,8 @@ PHP_MINIT_FUNCTION(rpminfo)
}
rpmtdFree(names);
+ php_register_url_stream_wrapper("rpm", &php_stream_rpm_wrapper);
+
return SUCCESS;
}
/* }}} */
diff --git a/tests/014-stream.phpt b/tests/014-stream.phpt
new file mode 100644
index 0000000..5a4fefa
--- /dev/null
+++ b/tests/014-stream.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Check for stream
+--SKIPIF--
+<?php if (!extension_loaded("rpminfo")) print "skip"; ?>
+--FILE--
+<?php
+$n = "rpm://" . __DIR__ . "/bidon.rpm#/usr/share/doc/bidon/README";
+
+var_dump(in_array('rpm', stream_get_wrappers()));
+
+var_dump($f = fopen($n, "r"));
+var_dump(trim(fread($f, 10)));
+var_dump(feof($f));
+var_dump(trim(fread($f, 100)));
+var_dump(feof($f));
+fclose($f);
+
+var_dump(trim(file_get_contents($n)));
+
+var_dump(file_get_contents(str_replace('README', 'TODO', $n)));
+?>
+Done
+--EXPECTF--
+bool(true)
+resource(%d) of type (stream)
+string(10) "Mon Feb 12"
+bool(false)
+string(17) "13:27:47 CET 2018"
+bool(true)
+string(28) "Mon Feb 12 13:27:47 CET 2018"
+
+Warning: file_get_contents(%s/bidon.rpm#/usr/share/doc/bidon/TODO): Failed to open stream: operation failed in %s on line %d
+bool(false)
+Done