summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yaml102
-rw-r--r--.gitignore1
-rw-r--r--README.md62
-rw-r--r--composer.json13
-rw-r--r--config.m421
-rw-r--r--package.xml133
-rw-r--r--php_rpminfo.h12
-rw-r--r--rpminfo.c479
-rw-r--r--rpminfo.stub.php9
-rw-r--r--rpminfo_arginfo.h30
-rw-r--r--tests/002-rpmvercmp.phpt44
-rw-r--r--tests/003-rpminfo.phpt2
-rw-r--r--tests/004-constants.phpt2
-rw-r--r--tests/005-rpminfo-full.phpt6
-rw-r--r--tests/010-rpmvercmp_error7.phpt25
-rw-r--r--tests/011-rpmvercmp_error8.phpt12
-rw-r--r--tests/014-stream.phpt97
-rw-r--r--tests/015-rpmmacro.phpt25
-rw-r--r--tests/bidon.rpmbin6972 -> 7599 bytes
-rw-r--r--tests/bidon.spec42
20 files changed, 980 insertions, 137 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
new file mode 100644
index 0000000..1663d4a
--- /dev/null
+++ b/.github/workflows/ci.yaml
@@ -0,0 +1,102 @@
+name: CI
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+jobs:
+ Linux_EL8:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ distro: ['rockylinux']
+ el: [8]
+ php: ['8.0', '8.2', 'remi-8.0', 'remi-8.1', 'remi-8.2', 'remi-8.3', 'remi-8.4']
+ container:
+ image: ${{ matrix.distro }}:${{ matrix.el }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Setup PHP module
+ if: ${{ matrix.php }}
+ run: |
+ dnf install -y "https://rpms.remirepo.net/enterprise/remi-release-${{ matrix.el }}.rpm"
+ dnf module enable -y "php:${{ matrix.php }}"
+ - name: Install PHP
+ run: |
+ dnf install -y "php" "php-devel" "rpm-devel"
+ - name: Show PHP version
+ run: php -v
+ - name: Make php-rpminfo
+ run: |
+ phpize
+ ./configure
+ make -j"$(nproc)"
+ - name: Test php-rpminfo
+ env:
+ TEST_PHP_ARGS: '-q --show-diff'
+ run: |
+ make test
+ Linux_EL9:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ distro: ['rockylinux']
+ el: [9]
+ php: [0, '8.1', '8.2', 'remi-8.0', 'remi-8.1', 'remi-8.2', 'remi-8.3', 'remi-8.4']
+ container:
+ image: ${{ matrix.distro }}:${{ matrix.el }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Setup PHP module
+ if: ${{ matrix.php }}
+ run: |
+ dnf install -y "https://rpms.remirepo.net/enterprise/remi-release-${{ matrix.el }}.rpm"
+ dnf module enable -y "php:${{ matrix.php }}"
+ - name: Install PHP
+ run: |
+ dnf install -y "php" "php-devel" "rpm-devel"
+ - name: Show PHP version
+ run: php -v
+ - name: Make php-rpminfo
+ run: |
+ phpize
+ ./configure
+ make -j"$(nproc)"
+ - name: Test php-rpminfo
+ env:
+ TEST_PHP_ARGS: '-q --show-diff'
+ run: |
+ make test
+ Linux_Fedora:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ fedora: [40, 41]
+ php: [0, 'remi-8.0', 'remi-8.1', 'remi-8.2', 'remi-8.3', 'remi-8.4']
+ container:
+ image: fedora:${{ matrix.fedora }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ - name: Setup PHP module
+ if: ${{ matrix.php }}
+ run: |
+ dnf install -y "https://rpms.remirepo.net/fedora/remi-release-${{ matrix.fedora }}.rpm"
+ dnf module enable -y "php:${{ matrix.php }}"
+ - name: Install PHP
+ run: |
+ dnf install -y "php" "php-devel" "rpm-devel"
+ - name: Show PHP version
+ run: php -v
+ - name: Make php-rpminfo
+ run: |
+ phpize
+ ./configure
+ make -j"$(nproc)"
+ - name: Test php-rpminfo
+ env:
+ TEST_PHP_ARGS: '-q --show-diff'
+ run: |
+ make test
diff --git a/.gitignore b/.gitignore
index 54b9e13..f9067ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,6 +55,7 @@ modules
run-tests.php
run-tests.log
tmp-php.ini
+sendpackagist
# Archives
rpminfo-*.tgz
diff --git a/README.md b/README.md
index 421d5a1..6efd10c 100644
--- a/README.md
+++ b/README.md
@@ -4,9 +4,6 @@ Retrieve RPM information from PHP code using librpm.
This extension can be considered as stable, and be used on production environement.
-But be aware that if its API will probably stay stable,
-some changes may occur before version 1.0.0.
-
----
@@ -17,7 +14,7 @@ some changes may occur before version 1.0.0.
# Build
-You need the rpm development files (rpm-devel) version >= 4.11.3.
+You need the rpm development files (rpm-devel) version >= 4.13.
From the sources tree
@@ -26,6 +23,15 @@ From the sources tree
$ make
$ make test
+From https://pecl.php.net/ using pecl command
+
+ $ pecl install rpminfo
+
+From https://packagist.org/ using PHP Installer for Extensions
+
+ $ pie install remi/rpminfo
+
+
----
# Usage
@@ -45,7 +51,7 @@ Allow to compare 2 EVR (epoch:version-release) strings. The return value is < 0
## rpminfo
- array rpminfo(string path [, bool full [, string &error]]);
+ rpminfo(string path [, bool full [, string &error]]): array;
Retrieve information from a rpm file, reading its metadata.
If given `error` will be used to store error message instead of raising a warning.
@@ -89,7 +95,7 @@ The return value is a hash table, or false if it fails.
## rpmdbinfo
- array rpmdbinfo(string path [, bool full ]);
+ rpmdbinfo(string path [, bool full ]): array;
Retrieve information from rpm database about an installed package.
The return value is an array of hash tables, or false if it fails.
@@ -185,6 +191,50 @@ The return value is an array of hash tables, or false if it fails.
)
)
+## rpmexpand
+
+ rpmexpand($text): string
+
+Retrieve expanded value of a RPM macro
+
+ $ php -a
+ php > var_dump(rpmexpand("%{?fedora:Fedora %{fedora}}%{?rhel:Enterprise Linux %{rhel}}"));
+ string(9) "Fedora 41"
+
+## rpmexpandnumeric
+
+ rpmexpandnumeric($text): int
+
+Retrieve numerical value of a RPM macro
+
+ $ php -a
+ php > var_dump(rpmexpandnumeric("%__isa_bits"));
+ int(64)
+
+## rpmdefine
+
+ rpmdefine($text): bool
+
+Define or change a RPM macro value.
+
+For example, can be used to set the Database path and backend
+
+ $ mock -r almalinux-8-x86_64 init
+ ...
+ $ mock -r fedora-41-x86_64 init
+ ...
+ $ php -a
+ php > // use an old database (bdb) from an EL-8 chroot
+ php > rpmdefine("_dbpath /var/lib/mock/almalinux-8-x86_64/root/var/lib/rpm");
+ php > rpmdefine("_db_backend bdb_ro");
+ php > var_dump(rpmdbinfo("almalinux-release")[0]["Summary"]);
+ string(22) "AlmaLinux release file"
+ php > // use a new database (sqlite) from a Fedora-41 chroot
+ php > rpmdefine("_dbpath /var/lib/mock/fedora-41-x86_64/root/usr/lib/sysimage/rpm");
+ php > rpmdefine("_db_backend sqlite");
+ php > var_dump(rpmdbinfo("fedora-release")[0]["Summary"]);
+ string(20) "Fedora release files"
+
----
# LICENSE
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..a76d2b7
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,13 @@
+{
+ "name": "remi/rpminfo",
+ "type": "php-ext",
+ "license": "PHP-3.01",
+ "description": "RPM information",
+ "require": {
+ "php": ">= 8.0.0"
+ },
+ "php-ext": {
+ "extension-name": "rpminfo",
+ "configure-options": []
+ }
+}
diff --git a/config.m4 b/config.m4
index 49f6f1d..abff0a9 100644
--- a/config.m4
+++ b/config.m4
@@ -4,27 +4,10 @@ PHP_ARG_ENABLE(rpminfo, whether to enable rpminfo support,
[ --enable-rpminfo Enable rpminfo support])
if test "$PHP_RPMINFO" != "no"; then
- dnl Write more examples of tests here...
- AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+ PKG_CHECK_MODULES([LIBRPM], [rpm >= 4.13])
- AC_MSG_CHECKING(for librpm)
- if test -x "$PKG_CONFIG" && $PKG_CONFIG --exists rpm; then
- if $PKG_CONFIG rpm --atleast-version 4.11.3; then
- LIBRPM_CFLAGS=`$PKG_CONFIG rpm --cflags`
- LIBRPM_LIBDIR=`$PKG_CONFIG rpm --libs`
- LIBRPM_VERSON=`$PKG_CONFIG rpm --modversion`
- AC_MSG_RESULT(from pkgconfig: version $LIBRPM_VERSON)
- if $PKG_CONFIG rpm --atleast-version 4.13; then
- AC_DEFINE(HAVE_WEAKDEP, 1, [ Indexes on weak dependency field since RPM 4.13 ])
- fi
- else
- AC_MSG_ERROR(system librpm is too old: version 4.11.3 required)
- fi
- else
- AC_MSG_ERROR(pkg-config not found)
- fi
- PHP_EVAL_LIBLINE($LIBRPM_LIBDIR, RPMINFO_SHARED_LIBADD)
+ PHP_EVAL_LIBLINE($LIBRPM_LIBS, RPMINFO_SHARED_LIBADD)
PHP_EVAL_INCLINE($LIBRPM_CFLAGS)
PHP_SUBST(RPMINFO_SHARED_LIBADD)
diff --git a/package.xml b/package.xml
index 38d8f04..27831c9 100644
--- a/package.xml
+++ b/package.xml
@@ -13,21 +13,19 @@ Documentation: https://www.php.net/rpminfo
<email>remi@php.net</email>
<active>yes</active>
</lead>
- <date>2020-09-23</date>
+ <date>2024-12-19</date>
<version>
- <release>0.6.0dev</release>
- <api>0.5.0</api>
+ <release>1.2.1dev</release>
+ <api>1.2.0</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
- <license>PHP 3.01</license>
- <notes>
-- generate arginfo from stub and add missing default values
-- raise dependency on PHP 7.2
-- raise exception on bad parameter value with PHP 8
- </notes>
+ <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license>
+ <notes><![CDATA[
+-
+ ]]></notes>
<contents>
<dir name="/">
<!-- sources -->
@@ -55,10 +53,11 @@ Documentation: https://www.php.net/rpminfo
<file name="007-rpmdbinfo.phpt" role="test"/>
<file name="008-rpmdbsearch.phpt" role="test"/>
<file name="009-rpmdbinfo2.phpt" role="test"/>
- <file name="010-rpmvercmp_error7.phpt" role="test"/>
<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="015-rpmmacro.phpt" role="test"/>
<file name="bidon.rpm" role="test"/>
<file name="bidon-src.rpm" role="test"/>
</dir>
@@ -67,7 +66,7 @@ Documentation: https://www.php.net/rpminfo
<dependencies>
<required>
<php>
- <min>7.2.0</min>
+ <min>8.0.0</min>
</php>
<pearinstaller>
<min>1.10.0</min>
@@ -78,6 +77,118 @@ Documentation: https://www.php.net/rpminfo
<extsrcrelease/>
<changelog>
<release>
+ <date>2024-12-19</date>
+ <version>
+ <release>1.2.0</release>
+ <api>1.2.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license>
+ <notes><![CDATA[
+- add rpmexpand, rpmexpandnumeric to retrieve rpm macro value
+- add rpmdefine to set rpm macro value
+ ]]></notes>
+ </release>
+ <release>
+ <date>2024-09-03</date>
+ <version>
+ <release>1.1.1</release>
+ <api>1.1.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license>
+ <notes><![CDATA[
+- display author and license in phpinfo
+- drop support for librpm < 4.13
+ ]]></notes>
+ </release>
+ <release>
+ <date>2023-11-10</date>
+ <version>
+ <release>1.1.0</release>
+ <api>1.1.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license>
+ <notes>
+- check open_basedir restriction
+- new function: rpmgetsymlink(string $path, string $name): ?string
+ </notes>
+ </release>
+ <release>
+ <date>2023-10-13</date>
+ <version>
+ <release>1.0.1</release>
+ <api>1.0.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license>
+ <notes>
+- fix stack smashing on 32-bit
+- allow retrieval of hardlink content
+ </notes>
+ </release>
+ <release>
+ <date>2023-10-12</date>
+ <version>
+ <release>1.0.0</release>
+ <api>1.0.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license>
+ <notes>
+- implement rpm stream wrapper with librpm >= 4.13
+ </notes>
+ </release>
+ <release>
+ <date>2023-09-26</date>
+ <version>
+ <release>0.7.0</release>
+ <api>0.7.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license>
+ <notes>
+- add optional operator to rpmcmpver for consistency with version_compare
+- drop support for PHP 7
+ </notes>
+ </release>
+ <release>
+ <date>2021-06-18</date>
+ <version>
+ <release>0.6.0</release>
+ <api>0.5.0</api>
+ </version>
+ <stability>
+ <release>stable</release>
+ <api>stable</api>
+ </stability>
+ <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license>
+ <notes>
+- generate arginfo from stub and add missing default values
+- raise dependency on PHP 7.2
+- raise exception on bad parameter value with PHP 8
+ </notes>
+ </release>
+ <release>
<date>2020-09-23</date>
<version>
<release>0.5.1</release>
diff --git a/php_rpminfo.h b/php_rpminfo.h
index 69ff71e..98b8439 100644
--- a/php_rpminfo.h
+++ b/php_rpminfo.h
@@ -22,15 +22,9 @@
extern zend_module_entry rpminfo_module_entry;
#define phpext_rpminfo_ptr &rpminfo_module_entry
-#define PHP_RPMINFO_VERSION "0.6.0-dev"
-
-#ifdef PHP_WIN32
-# define PHP_RPMINFO_API __declspec(dllexport)
-#elif defined(__GNUC__) && __GNUC__ >= 4
-# define PHP_RPMINFO_API __attribute__ ((visibility("default")))
-#else
-# define PHP_RPMINFO_API
-#endif
+#define PHP_RPMINFO_VERSION "1.2.1-dev"
+#define PHP_RPMINFO_AUTHOR "Remi Collet"
+#define PHP_RPMINFO_LICENSE "PHP-3.01"
#ifdef ZTS
#include "TSRM.h"
diff --git a/rpminfo.c b/rpminfo.c
index 53b9c6c..ae8b8e7 100644
--- a/rpminfo.c
+++ b/rpminfo.c
@@ -23,26 +23,29 @@
#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>
#include <rpm/rpmio.h>
#include <rpm/rpmlib.h>
#include <rpm/rpmts.h>
+#include <rpm/rpmmacro.h>
#include "php_rpminfo.h"
-/* For PHP < 8.0 */
-#ifndef ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE
-#define ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(pass_by_ref, name, type_hint, allow_null, default_value) \
- ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null)
-#endif
+#include "rpminfo_arginfo.h"
-#ifndef RETURN_THROWS
-#define RETURN_THROWS() return
-#endif
+struct php_rpm_stream_data_t {
+ FD_t gzdi;
+ Header h;
+ rpmfiles files;
+ rpmfi fi;
+ php_stream *stream;
+};
-#include "rpminfo_arginfo.h"
+#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)
@@ -67,6 +70,13 @@ static rpmdb rpminfo_getdb(void) {
return RPMINFO_G(db);
}
+static void rpminfo_closedb(void) {
+ if (RPMINFO_G(db)) {
+ rpmtsCloseDB(RPMINFO_G(ts));
+ RPMINFO_G(db) = NULL;
+ }
+}
+
static void rpm_header_to_zval(zval *return_value, Header h, zend_bool full)
{
HeaderIterator hi;
@@ -231,6 +241,9 @@ PHP_FUNCTION(rpminfo)
zval_dtor(error);
ZVAL_NULL(error);
}
+ if (php_check_open_basedir(path)) {
+ RETURN_NULL();
+ }
f = Fopen(path, "r");
if (f) {
@@ -287,7 +300,7 @@ PHP_FUNCTION(rpmdbinfo)
db = rpminfo_getdb();
di = rpmdbInitIterator(db, RPMDBI_LABEL, name, len);
if (!di) {
- // Not found
+ /* Not found */
RETURN_NULL();
}
@@ -312,7 +325,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) {
@@ -342,14 +355,12 @@ static int haveIndex(zend_long tag) {
tag == RPMDBI_INSTALLTID ||
tag == RPMDBI_SIGMD5 ||
tag == RPMDBI_SHA1HEADER ||
-#ifdef HAVE_WEAKDEP
tag == RPMDBI_FILETRIGGERNAME ||
tag == RPMDBI_TRANSFILETRIGGERNAME ||
tag == RPMDBI_RECOMMENDNAME ||
tag == RPMDBI_SUGGESTNAME ||
tag == RPMDBI_SUPPLEMENTNAME ||
tag == RPMDBI_ENHANCENAME ||
-#endif
tag == RPMDBI_INSTFILENAMES) {
return 1;
}
@@ -376,49 +387,29 @@ PHP_FUNCTION(rpmdbsearch)
RETURN_THROWS();
}
if (rpmTagGetType(crit) == RPM_NULL_TYPE) {
-#if PHP_VERSION_ID < 80000
- php_error_docref(NULL, E_WARNING, "Unkown rpmtag");
- RETURN_NULL();
-#else
zend_argument_value_error(2, "Unkown rpmtag");
RETURN_THROWS();
-#endif
}
if (mode != RPMMIRE_DEFAULT &&
mode != RPMMIRE_STRCMP &&
mode != RPMMIRE_REGEX &&
mode != RPMMIRE_GLOB &&
mode != -1) {
-#if PHP_VERSION_ID < 80000
- php_error_docref(NULL, E_WARNING, "Unkown rpmmire");
- RETURN_NULL();
-#else
zend_argument_value_error(3, "Unkown rpmmire");
RETURN_THROWS();
-#endif
}
if (crit == RPMTAG_PKGID) {
if (len != 32) {
-#if PHP_VERSION_ID < 80000
- php_error_docref(NULL, E_WARNING, "Bad length for PKGID, 32 expected");
- RETURN_NULL();
-#else
zend_argument_value_error(1, "Bad length for PKGID, 32 expected");
RETURN_THROWS();
-#endif
}
len = hex2bin(name, MD5, len);
name = MD5;
} else if (crit == RPMTAG_HDRID) {
if (len != 40) {
-#if PHP_VERSION_ID < 80000
- php_error_docref(NULL, E_WARNING, "Bad length for HDRID, 40 expected");
- RETURN_NULL();
-#else
zend_argument_value_error(1, "Bad length for HDRID, 40 expected");
RETURN_THROWS();
-#endif
}
} else if (crit == RPMTAG_INSTALLTID) {
tid = atol(name);
@@ -447,7 +438,7 @@ PHP_FUNCTION(rpmdbsearch)
}
}
if (!di) {
- // Not found
+ /* Not found */
RETURN_NULL();
}
@@ -469,16 +460,17 @@ PHP_FUNCTION(rpmvercmp)
char *in_evr1, *evr1, *v1, *r1;
char *in_evr2, *evr2, *v2, *r2;
char *p, empty[] = "";
+ char *op = NULL;
long e1, e2, r;
- size_t len1, len2;
+ size_t len1, len2, oplen;
- if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &in_evr1, &len1, &in_evr2, &len2) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|s", &in_evr1, &len1, &in_evr2, &len2, &op, &oplen) == FAILURE) {
RETURN_THROWS();
}
evr1 = estrdup(in_evr1);
evr2 = estrdup(in_evr2);
- // Epoch
+ /* Epoch */
p = strchr(evr1, ':');
if (p) {
v1 = p+1;
@@ -498,11 +490,11 @@ PHP_FUNCTION(rpmvercmp)
e2 = 0;
}
if (e1 < e2) {
- RETVAL_LONG(-1);
+ r = -1;
} else if (e1 > e2) {
- RETVAL_LONG(1);
+ r = 1;
} else {
- // Version
+ /* Version */
p = strchr(v1, '-');
if (p) {
r1 = p+1;
@@ -518,16 +510,39 @@ PHP_FUNCTION(rpmvercmp)
r2 = empty;
}
r = rpmvercmp(v1, v2);
- if (r) {
- RETVAL_LONG(r);
- } else {
- // Release
+ if (!r) {
+ /* Release*/
r = rpmvercmp(r1, r2);
- RETVAL_LONG(r);
}
}
efree(evr1);
efree(evr2);
+
+ if (!op) {
+ RETURN_LONG(r);
+ }
+
+ if (!strcmp(op, "<") || !strcmp(op, "lt")) {
+ RETURN_BOOL(r < 0);
+ }
+ if (!strcmp(op, "<=") || !strcmp(op, "le")) {
+ RETURN_BOOL(r <= 0);
+ }
+ if (!strcmp(op, ">") || !strcmp(op, "gt")) {
+ RETURN_BOOL(r > 0);
+ }
+ if (!strcmp(op, ">=") || !strcmp(op, "ge")) {
+ RETURN_BOOL(r >= 0);
+ }
+ if (!strcmp(op, "==") || !strcmp(op, "=") || !strcmp(op, "eq")) {
+ RETURN_BOOL(r == 0);
+ }
+ if (!strcmp(op, "!=") || !strcmp(op, "<>") || !strcmp(op, "ne")) {
+ RETURN_BOOL(r != 0);
+ }
+
+ zend_argument_value_error(3, "must be a valid comparison operator");
+ RETURN_THROWS();
}
/* }}} */
@@ -543,13 +558,8 @@ PHP_FUNCTION(rpmaddtag)
}
if (rpmTagGetType(tag) == RPM_NULL_TYPE) {
-#if PHP_VERSION_ID < 80000
- php_error_docref(NULL, E_WARNING, "Unkown rpmtag");
- RETURN_BOOL(0);
-#else
zend_argument_value_error(1, "Unkown rpmtag");
RETURN_THROWS();
-#endif
}
if (RPMINFO_G(tags)) {
@@ -572,12 +582,366 @@ 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 void php_rpm_ops_free(struct php_rpm_stream_data_t *self, int close_handle)
+{
+ if (self) {
+ if (close_handle) {
+ Fclose(self->gzdi);
+ rpmfilesFree(self->files);
+ rpmfiFree(self->fi);
+ headerFree(self->h);
+ }
+ efree(self);
+ }
+}
+
+static int php_rpm_ops_close(php_stream *stream, int close_handle)
+{
+ STREAM_DATA_FROM_STREAM();
+
+ php_rpm_ops_free(self, close_handle);
+ stream->abstract = NULL;
+
+ return EOF;
+}
+
+static int php_zip_ops_stat(php_stream *stream, php_stream_statbuf *ssb)
+{
+ STREAM_DATA_FROM_STREAM();
+
+ if (self) {
+ struct stat s[2]; /* librpm may use different size (32-bit) */
+ int rc;
+ rc = rpmfiStat(self->fi, 0, s);
+ memcpy(&ssb->sb, s, sizeof(ssb->sb));
+ return rc;
+ }
+ return -1;
+}
+
+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 */
+ php_zip_ops_stat,
+ NULL /* set_option */
+};
+
+static struct php_rpm_stream_data_t *php_stream_rpm_finder(const char *path, int want_content)
+{
+ size_t path_len;
+ zend_string *file_basename;
+ char file_dirname[MAXPATHLEN];
+ char *fragment;
+ size_t fragment_len;
+ struct php_rpm_stream_data_t *self = NULL;
+ 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) {
+ 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);
+ Fclose(fdi);
+ 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) {
+ headerFree(h);
+ Fclose(fdi);
+ zend_string_release_ex(file_basename, 0);
+ return NULL;
+ }
+
+ files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
+ fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE);
+
+ while((rc = rpmfiNext(fi)) >=0) {
+ const char *fn = rpmfiFN(fi);
+ /*
+ printf("Name=%s, Size=%d, N=%d, mode=%d, reg=%d, content=%d, rdev=%d, inode=%d link=%s\n", fn,
+ (int)rpmfiFSize(fi), (int)rpmfiFNlink(fi), (int)rpmfiFMode(fi),
+ (int)S_ISREG(rpmfiFMode(fi)), (int)rpmfiArchiveHasContent(fi),
+ (int)rpmfiFRdev(fi), (int)rpmfiFInode(fi), rpmfiFLink(fi));
+ */
+ if (!strcmp(fn, fragment)) {
+ if (want_content && S_ISREG(rpmfiFMode(fi)) && !rpmfiArchiveHasContent(fi)) {
+ rpm_rdev_t rdev = rpmfiFRdev(fi);
+ rpm_ino_t inode = rpmfiFInode(fi);
+ while((rc = rpmfiNext(fi)) >=0) {
+ if (rdev == rpmfiFRdev(fi) && inode == rpmfiFInode(fi) && rpmfiArchiveHasContent(fi)) {
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ if (rc == RPMERR_ITER_END) {
+ 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;
+ }
+ zend_string_release_ex(file_basename, 0);
+
+ return self;
+}
+
+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)
+{
+ struct php_rpm_stream_data_t *self;
+
+ if (mode[0] != 'r') {
+ return NULL;
+ }
+ self = php_stream_rpm_finder(path, 1);
+ if (self) {
+ if (opened_path) {
+ *opened_path = zend_string_init(path, strlen(path), 0);
+ }
+ if (!S_ISREG(rpmfiFMode(self->fi)) || !rpmfiArchiveHasContent(self->fi)) {
+ php_rpm_ops_free(self, 1);
+ } else {
+ return php_stream_alloc(&php_stream_rpmio_ops, self, NULL, mode);
+ }
+ }
+
+ return NULL;
+}
+
+static int php_stream_rpm_stat(php_stream_wrapper *wrapper, const char *url, int flags,
+ php_stream_statbuf *ssb, php_stream_context *context)
+{
+ struct php_rpm_stream_data_t *self;
+ int rc = -1;
+
+ self = php_stream_rpm_finder(url, 0);
+ if (self) {
+ struct stat s[2]; /* librpm may use different size (32-bit) */
+ rc = rpmfiStat(self->fi, 0, s);
+ memcpy(&ssb->sb, s, sizeof(ssb->sb));
+ php_rpm_ops_free(self, 1);
+ }
+
+ return rc;
+}
+
+static const php_stream_wrapper_ops rpm_stream_wops = {
+ php_stream_rpm_opener,
+ NULL, /* close */
+ NULL, /* fstat */
+ php_stream_rpm_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 */
+};
+
+/* {{{ proto array rpmgetsymlink(string path , string name)
+ Retrieve soft link target of en entry */
+PHP_FUNCTION(rpmgetsymlink)
+{
+ char *path, *name;
+ const char *link;
+ size_t plen, nlen;
+ 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();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "pp", &path, &plen, &name, &nlen) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ if (php_check_open_basedir(path)) {
+ RETURN_NULL();
+ }
+ fdi = Fopen(path, "r.ufdio");
+ if (Ferror(fdi)) {
+ RETURN_NULL();
+ }
+ rc = rpmReadPackageFile(ts, fdi, "rpm2cpio", &h);
+ if (rc != RPMRC_OK && rc != RPMRC_NOKEY && rc != RPMRC_NOTTRUSTED) {
+ Fclose(fdi);
+ 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) {
+ headerFree(h);
+ Fclose(fdi);
+ RETURN_NULL();
+ }
+
+ files = rpmfilesNew(NULL, h, 0, RPMFI_KEEPHEADER);
+ fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE);
+
+ rc = rpmfiFindFN(fi, name);
+ rpmfiSetFX(fi, rc); /* return value have change in 4.18 (from previous to new) */
+ if (rc < 0
+ || rpmfiFX(fi) != rc
+ || (link = rpmfiFLink(fi)) == NULL) {
+ RETVAL_NULL();
+ } else {
+ RETVAL_STRING(link);
+ }
+ rpmfiFree(fi);
+ rpmfilesFree(files);
+ headerFree(h);
+ Fclose(gzdi);
+}
+/* }}} */
+
+/* {{{ proto array rpmexpand(string $text): string
+ Expand macro in text */
+PHP_FUNCTION(rpmexpand)
+{
+ char *text, *result;
+ size_t len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &text, &len) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ (void)rpminfo_getts(); /* read config files */
+
+ result = rpmExpand(text, NULL);
+ RETVAL_STRING(result);
+ free(result);
+}
+/* }}} */
+
+/* {{{ proto array rpmexpandnumeric(string $text): int
+ Expand macro in text */
+PHP_FUNCTION(rpmexpandnumeric)
+{
+ char *text;
+ size_t len;
+ int result;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &text, &len) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ (void)rpminfo_getts(); /* read config files */
+
+ result = rpmExpandNumeric(text);
+
+ RETURN_LONG(result);
+}
+/* }}} */
+
+/* {{{ proto array rpmdefine(string $macro): bool
+ Define a new macro */
+PHP_FUNCTION(rpmdefine)
+{
+ char *macro;
+ size_t len;
+ int result;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &macro, &len) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ (void)rpminfo_getts(); /* read config files */
+
+ rpminfo_closedb(); /* Close the DB to allow path change */
+
+ result = rpmDefineMacro(NULL, macro, RMIL_GLOBAL);
+
+ RETURN_BOOL(result == 0);
+}
+/* }}} */
+
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(rpminfo)
{
- const char *tagname;
- rpmtd names;
+ const char *tagname;
+ rpmtd names;
REGISTER_STRING_CONSTANT("RPMVERSION", (char *)RPMVERSION, CONST_CS | CONST_PERSISTENT);
@@ -617,6 +981,8 @@ PHP_MINIT_FUNCTION(rpminfo)
}
rpmtdFree(names);
+ php_register_url_stream_wrapper("rpm", &php_stream_rpm_wrapper);
+
return SUCCESS;
}
/* }}} */
@@ -642,10 +1008,8 @@ PHP_RINIT_FUNCTION(rpminfo)
PHP_RSHUTDOWN_FUNCTION(rpminfo)
{
if (RPMINFO_G(ts)) {
- if (RPMINFO_G(db)) {
- rpmtsCloseDB(RPMINFO_G(ts));
- RPMINFO_G(db) = NULL;
- }
+ rpminfo_closedb();
+
rpmtsFree(RPMINFO_G(ts));
RPMINFO_G(ts) = NULL;
}
@@ -668,7 +1032,10 @@ PHP_MINFO_FUNCTION(rpminfo)
php_info_print_table_start();
php_info_print_table_header(2, "rpminfo support", "enabled");
php_info_print_table_row(2, "Extension version", PHP_RPMINFO_VERSION);
+ php_info_print_table_row(2, "Author", PHP_RPMINFO_AUTHOR);
+ php_info_print_table_row(2, "License", PHP_RPMINFO_LICENSE);
php_info_print_table_row(2, "RPM library version", RPMVERSION);
+ php_info_print_table_row(2, "RPM stream wrapper", "yes");
php_info_print_table_end();
/* Remove comments if you have entries in php.ini
diff --git a/rpminfo.stub.php b/rpminfo.stub.php
index 543cc5f..026df4b 100644
--- a/rpminfo.stub.php
+++ b/rpminfo.stub.php
@@ -10,6 +10,13 @@ function rpmdbsearch(string $pattern, int $rpmtag = RPMTAG_NAME, int $rpmmire =
function rpminfo(string $path, bool $full = false, ?string &$error = null): Array|null {}
-function rpmvercmp(string $evr1, string $evr2): int {}
+function rpmvercmp(string $evr1, string $evr2, ?string $operator = null): int|bool {}
+function rpmgetsymlink(string $path, string $name): string|null {}
+
+function rpmexpand(string $text): string {}
+
+function rpmexpandnumeric(string $text): int {}
+
+function rpmdefine(string $macro): bool {}
diff --git a/rpminfo_arginfo.h b/rpminfo_arginfo.h
index 20c501f..6db4fed 100644
--- a/rpminfo_arginfo.h
+++ b/rpminfo_arginfo.h
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 6b4dfeada2b5de5c5453d2b38c1a861e01bf958e */
+ * Stub hash: dc980a56084190700162f5a8c70b54fcdbc30ced */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmaddtag, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, rpmtag, IS_LONG, 0)
@@ -23,9 +23,27 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpminfo, 0, 1, IS_ARRAY, 1)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(1, error, IS_STRING, 1, "null")
ZEND_END_ARG_INFO()
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmvercmp, 0, 2, IS_LONG, 0)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_rpmvercmp, 0, 2, MAY_BE_LONG|MAY_BE_BOOL)
ZEND_ARG_TYPE_INFO(0, evr1, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, evr2, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, operator, IS_STRING, 1, "null")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmgetsymlink, 0, 2, IS_STRING, 1)
+ ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmexpand, 0, 1, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, text, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmexpandnumeric, 0, 1, IS_LONG, 0)
+ ZEND_ARG_TYPE_INFO(0, text, IS_STRING, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmdefine, 0, 1, _IS_BOOL, 0)
+ ZEND_ARG_TYPE_INFO(0, macro, IS_STRING, 0)
ZEND_END_ARG_INFO()
@@ -34,6 +52,10 @@ ZEND_FUNCTION(rpmdbinfo);
ZEND_FUNCTION(rpmdbsearch);
ZEND_FUNCTION(rpminfo);
ZEND_FUNCTION(rpmvercmp);
+ZEND_FUNCTION(rpmgetsymlink);
+ZEND_FUNCTION(rpmexpand);
+ZEND_FUNCTION(rpmexpandnumeric);
+ZEND_FUNCTION(rpmdefine);
static const zend_function_entry ext_functions[] = {
@@ -42,5 +64,9 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(rpmdbsearch, arginfo_rpmdbsearch)
ZEND_FE(rpminfo, arginfo_rpminfo)
ZEND_FE(rpmvercmp, arginfo_rpmvercmp)
+ ZEND_FE(rpmgetsymlink, arginfo_rpmgetsymlink)
+ ZEND_FE(rpmexpand, arginfo_rpmexpand)
+ ZEND_FE(rpmexpandnumeric, arginfo_rpmexpandnumeric)
+ ZEND_FE(rpmdefine, arginfo_rpmdefine)
ZEND_FE_END
};
diff --git a/tests/002-rpmvercmp.phpt b/tests/002-rpmvercmp.phpt
index d83cf67..c53a183 100644
--- a/tests/002-rpmvercmp.phpt
+++ b/tests/002-rpmvercmp.phpt
@@ -29,11 +29,53 @@ $ok = true;
foreach ($cases as $case) {
list($a,$b,$expected) = $case;
$result = rpmvercmp($a,$b);
- if ($result != $expected) {
+ if ($result !== $expected) {
$ok = false;
printf("rpmvercmp(%s, %s) = %d when %d expected\n", $a, $b, $result, $expected);
}
}
+
+$cases = [
+ ['1', '2', '>', false],
+ ['1', '2', 'gt', false],
+ ['1', '2', '>=', false],
+ ['1', '2', 'ge', false],
+ ['1', '1', '>=', true],
+ ['1', '1', 'ge', true],
+
+ ['1', '2', '<', true],
+ ['1', '2', 'lt', true],
+ ['1', '2', '<=', true],
+ ['1', '2', 'le', true],
+ ['1', '1', '<=', true],
+ ['1', '1', 'le', true],
+
+ ['1', '1', '=', true],
+ ['1', '1', '==', true],
+ ['1', '1', 'eq', true],
+
+ ['1', '2', '=', false],
+ ['1', '2', '==', false],
+ ['1', '2', 'eq', false],
+
+ ['1', '1', '!=', false],
+ ['1', '1', '<>', false],
+ ['1', '1', 'ne', false],
+
+ ['1', '2', '!=', true],
+ ['1', '2', '<>', true],
+ ['1', '2', 'ne', true],
+];
+foreach ($cases as $case) {
+ list($a,$b,$op,$expected) = $case;
+ $result = rpmvercmp($a,$b,$op);
+ if ($result !== $expected) {
+ $ok = false;
+ printf("rpmvercmp(%s, %s, %s) = %s when %s expected\n",
+ $a, $b, $op, $result ? "true" : "false", $expected ? "true" : "false");
+ }
+}
+
if ($ok) echo "OK\n";
?>
Done
diff --git a/tests/003-rpminfo.phpt b/tests/003-rpminfo.phpt
index beb7b47..919bcc9 100644
--- a/tests/003-rpminfo.phpt
+++ b/tests/003-rpminfo.phpt
@@ -14,7 +14,7 @@ array(5) {
["Version"]=>
string(1) "1"
["Release"]=>
- string(11) "1.fc27.remi"
+ string(1) "3"
["Summary"]=>
string(5) "Bidon"
["Arch"]=>
diff --git a/tests/004-constants.phpt b/tests/004-constants.phpt
index 397c97f..18104cc 100644
--- a/tests/004-constants.phpt
+++ b/tests/004-constants.phpt
@@ -8,5 +8,5 @@ var_dump(RPMVERSION);
?>
Done
--EXPECTF--
-string(%d) "4.%s"
+string(%d) "%s"
Done
diff --git a/tests/005-rpminfo-full.phpt b/tests/005-rpminfo-full.phpt
index 38f5bab..15c158d 100644
--- a/tests/005-rpminfo-full.phpt
+++ b/tests/005-rpminfo-full.phpt
@@ -24,9 +24,11 @@ Done
--- bidon.rpm ---
string(5) "bidon"
string(15) "A dummy package"
-array(1) {
+array(2) {
[0]=>
- string(8) "- create"
+ string(14) "- add symlinks"
+ [1]=>
+ string(20) "- add some hardlinks"
}
bool(false)
array(1) {
diff --git a/tests/010-rpmvercmp_error7.phpt b/tests/010-rpmvercmp_error7.phpt
deleted file mode 100644
index c9b3875..0000000
--- a/tests/010-rpmvercmp_error7.phpt
+++ /dev/null
@@ -1,25 +0,0 @@
---TEST--
-Check for rpmvercmp function error
---SKIPIF--
-<?php
-if (!extension_loaded("rpminfo")) print "skip";
-if (PHP_VERSION_ID >= 80000) print "skip only for PHP 7";
-?>
---FILE--
-<?php
-var_dump(rpmvercmp());
-var_dump(rpmvercmp("a"));
-var_dump(rpmvercmp("a", "b", "c"));
-?>
-Done
---EXPECTF--
-
-Warning: rpmvercmp() expects exactly 2 parameters, 0 given in %s
-NULL
-
-Warning: rpmvercmp() expects exactly 2 parameters, 1 given in %s
-NULL
-
-Warning: rpmvercmp() expects exactly 2 parameters, 3 given in %s
-NULL
-Done
diff --git a/tests/011-rpmvercmp_error8.phpt b/tests/011-rpmvercmp_error8.phpt
index 4430975..2fe6aa1 100644
--- a/tests/011-rpmvercmp_error8.phpt
+++ b/tests/011-rpmvercmp_error8.phpt
@@ -19,13 +19,19 @@ try {
}
try {
var_dump(rpmvercmp("a", "b", "c"));
+} catch (ValueError $e) {
+ echo $e->getMessage(), "\n";
+}
+try {
+ var_dump(rpmvercmp("a", "b", "c", "d"));
} catch (ArgumentCountError $e) {
echo $e->getMessage(), "\n";
}
?>
Done
--EXPECTF--
-rpmvercmp() expects exactly 2 %s, 0 given
-rpmvercmp() expects exactly 2 %s, 1 given
-rpmvercmp() expects exactly 2 %s, 3 given
+rpmvercmp() expects at least 2 %s, 0 given
+rpmvercmp() expects at least 2 %s, 1 given
+rpmvercmp(): Argument #3 ($operator) must be a valid comparison operator
+rpmvercmp() expects at most 3 %s, 4 given
Done
diff --git a/tests/014-stream.phpt b/tests/014-stream.phpt
new file mode 100644
index 0000000..69b881e
--- /dev/null
+++ b/tests/014-stream.phpt
@@ -0,0 +1,97 @@
+--TEST--
+Check for stream
+--SKIPIF--
+<?php
+if (!extension_loaded("rpminfo")) print "skip";
+if (version_compare(RPMVERSION, '4.13', 'lt')) print("skip librpm is older than 4.13");
+?>
+--FILE--
+<?php
+$d = "rpm://" . __DIR__ . "/bidon.rpm#/usr/share/doc/bidon";
+$n = "rpm://" . __DIR__ . "/bidon.rpm#/usr/share/doc/bidon/README";
+$x = "rpm://" . __DIR__ . "/bidon.rpm#/usr/share/doc/bidon/MISSING";
+$foo = "rpm://" . __DIR__ . "/bidon.rpm#/etc/foo.conf";
+$bar = "rpm://" . __DIR__ . "/bidon.rpm#/etc/bar.conf";
+$toto = "rpm://" . __DIR__ . "/bidon.rpm#/etc/toto.conf";
+
+echo "+ wrapper\n";
+var_dump(in_array('rpm', stream_get_wrappers()));
+
+echo "+ stat\n";
+$s = stat($d); // S_ISDIR
+var_dump($s['size'], $s['mode'] , ($s['mode'] & 0170000) == 0040000 ? "OK" : "KO");
+var_dump(file_exists($d), is_dir($d), is_file($d), is_link($n));
+$s = stat($n); // S_ISREG
+var_dump($s['size'], $s['mode'] , ($s['mode'] & 0170000) == 0100000 ? "OK" : "KO");
+var_dump(file_exists($n), is_dir($n), is_file($n), is_link($n));
+$s = stat($toto); // S_ISLNK
+var_dump($s['size'], $s['mode'] , ($s['mode'] & 0170000) == 0120000 ? "OK" : "KO");
+var_dump(file_exists($toto), is_dir($toto), is_file($toto), is_link($toto));
+
+echo "+ file\n";
+var_dump($f = fopen($n, "r"));
+$s = fstat($f);
+var_dump($s['size'], $s['mode']);
+var_dump(trim(fread($f, 10)));
+var_dump(feof($f));
+var_dump(trim(fread($f, 100)));
+var_dump(feof($f));
+fclose($f);
+
+echo "+ stream\n";
+var_dump(trim(file_get_contents($n))); // Existing file
+var_dump(trim(file_get_contents($foo))); // Hardlink with content
+var_dump(trim(file_get_contents($bar))); // hardlink without content
+var_dump(file_get_contents($x)); // Missing file
+
+echo "+ symlink\n";
+var_dump(rpmgetsymlink(__DIR__ . "/bidon.rpm", "missing"));
+var_dump(rpmgetsymlink(__DIR__ . "/bidon.rpm", "/etc/foo.conf")); // not a symlink
+var_dump(rpmgetsymlink(__DIR__ . "/bidon.rpm", "/etc/toto.conf")); // symlink
+?>
+Done
+--EXPECTF--
++ wrapper
+bool(true)
++ stat
+int(0)
+int(16877)
+string(2) "OK"
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+int(30)
+int(33188)
+string(2) "OK"
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+int(8)
+int(41471)
+string(2) "OK"
+bool(true)
+bool(false)
+bool(false)
+bool(true)
++ file
+resource(%d) of type (stream)
+int(30)
+int(33188)
+string(10) "Thu Oct 19"
+bool(false)
+string(18) "12:01:02 CEST 2023"
+bool(true)
++ stream
+string(29) "Thu Oct 19 12:01:02 CEST 2023"
+string(7) "content"
+string(7) "content"
+
+Warning: file_get_contents(%s/bidon.rpm#/usr/share/doc/bidon/MISSING): Failed to open stream: operation failed in %s on line %d
+bool(false)
++ symlink
+NULL
+string(0) ""
+string(8) "foo.conf"
+Done
diff --git a/tests/015-rpmmacro.phpt b/tests/015-rpmmacro.phpt
new file mode 100644
index 0000000..794cabf
--- /dev/null
+++ b/tests/015-rpmmacro.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Check for rpmdefine, rpmexpand, rpmexpandnumeric
+--SKIPIF--
+<?php if (!extension_loaded("rpminfo")) print "skip"; ?>
+--FILE--
+<?php
+var_dump(is_dir(rpmexpand("%{_dbpath}")));
+
+var_dump(rpmexpandnumeric("%__isa_bits") === PHP_INT_SIZE * 8);
+var_dump(is_int(rpmexpandnumeric("0%{?fedora}%{?rhel}")));
+
+$name = "_my_test_macro_for_rpminfo_";
+$val = __FILE__;
+var_dump(rpmexpand("%$name") === "%$name" );
+var_dump(rpmdefine("$name $val"));
+var_dump(rpmexpand("%$name") === __FILE__);
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+
diff --git a/tests/bidon.rpm b/tests/bidon.rpm
index 6cbfa04..d8efb06 100644
--- a/tests/bidon.rpm
+++ b/tests/bidon.rpm
Binary files differ
diff --git a/tests/bidon.spec b/tests/bidon.spec
new file mode 100644
index 0000000..b3ad790
--- /dev/null
+++ b/tests/bidon.spec
@@ -0,0 +1,42 @@
+%{!?ver: %global ver 1}
+
+Name: bidon
+Version: %{ver}
+Release: 3
+Summary: Bidon
+License: Public Domain
+URL: https://rpms.remirepo.net/
+
+Obsoletes: fooobs < 2
+
+
+%description
+A dummy package
+
+%prep
+date >README
+echo "content" >conf
+
+%build
+: nothing to build
+
+%install
+install -Dpm644 conf %{buildroot}%{_sysconfdir}/foo.conf
+cd %{buildroot}%{_sysconfdir}
+ln foo.conf bar.conf
+ln -s foo.conf toto.conf
+
+%files
+%doc README
+%config(noreplace) %{_sysconfdir}/*.conf
+
+
+%changelog
+* Thu Oct 19 2023 Remi Collet <remi@fedoraproject.org> - 1-3
+- add symlinks
+
+* Fri Oct 13 2023 Remi Collet <remi@fedoraproject.org> - 1-2
+- add some hardlinks
+
+* Wed Dec 24 2014 Remi Collet <remi@fedoraproject.org> - 1-1
+- create