diff options
-rw-r--r-- | .github/workflows/ci.yaml | 102 | ||||
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | README.md | 62 | ||||
-rw-r--r-- | composer.json | 13 | ||||
-rw-r--r-- | config.m4 | 21 | ||||
-rw-r--r-- | package.xml | 133 | ||||
-rw-r--r-- | php_rpminfo.h | 12 | ||||
-rw-r--r-- | rpminfo.c | 479 | ||||
-rw-r--r-- | rpminfo.stub.php | 9 | ||||
-rw-r--r-- | rpminfo_arginfo.h | 30 | ||||
-rw-r--r-- | tests/002-rpmvercmp.phpt | 44 | ||||
-rw-r--r-- | tests/003-rpminfo.phpt | 2 | ||||
-rw-r--r-- | tests/004-constants.phpt | 2 | ||||
-rw-r--r-- | tests/005-rpminfo-full.phpt | 6 | ||||
-rw-r--r-- | tests/010-rpmvercmp_error7.phpt | 25 | ||||
-rw-r--r-- | tests/011-rpmvercmp_error8.phpt | 12 | ||||
-rw-r--r-- | tests/014-stream.phpt | 97 | ||||
-rw-r--r-- | tests/015-rpmmacro.phpt | 25 | ||||
-rw-r--r-- | tests/bidon.rpm | bin | 6972 -> 7599 bytes | |||
-rw-r--r-- | tests/bidon.spec | 42 |
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 @@ -55,6 +55,7 @@ modules run-tests.php run-tests.log tmp-php.ini +sendpackagist # Archives rpminfo-*.tgz @@ -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": [] + } +} @@ -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" @@ -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", ¯o, &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 Binary files differindex 6cbfa04..d8efb06 100644 --- a/tests/bidon.rpm +++ b/tests/bidon.rpm 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 |