summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemi Collet <remi@remirepo.net>2018-01-25 13:30:20 +0100
committerRemi Collet <remi@remirepo.net>2018-01-25 13:30:20 +0100
commit7adc0cf86d301028e268f1803ee117bdd74586d5 (patch)
tree72a553f8a633e7ce498fe7579e49db972720ee04
parent4daae0625ceaf2aa7aba7bf0a7230044d346e256 (diff)
New function: array rpminfo(string path [, bool full ]);
-rw-r--r--README.md3
-rw-r--r--REFLECTION20
-rw-r--r--examples/repomanage.php21
-rw-r--r--php_rpminfo.h10
-rw-r--r--rpminfo.c164
-rw-r--r--tests/003.phpt270
-rw-r--r--tests/bidon-src.rpmbin0 -> 6257 bytes
-rw-r--r--tests/bidon.rpmbin0 -> 6808 bytes
8 files changed, 459 insertions, 29 deletions
diff --git a/README.md b/README.md
index 7703d5b..1584173 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@ Experimental wrapper for librpm
For now, only expose
int rpmvercmp(string evr1, string evr2);
+ array rpminfo(string path [, bool full ]);
Mostly a PoC build for fun because of
@@ -38,5 +39,5 @@ Some benchmark results (find 15 old RPMs among 5000)
$ time php repomanage.php --old --keep 5 .
...
- real 0m0,634s
+ real 0m0,135s
diff --git a/REFLECTION b/REFLECTION
new file mode 100644
index 0000000..630606c
--- /dev/null
+++ b/REFLECTION
@@ -0,0 +1,20 @@
+Extension [ <persistent> extension #15 rpminfo version 0.1.0 ] {
+
+ - Functions {
+ Function [ <internal:rpminfo> function rpminfo ] {
+
+ - Parameters [2] {
+ Parameter #0 [ <required> $path ]
+ Parameter #1 [ <optional> $full ]
+ }
+ }
+ Function [ <internal:rpminfo> function rpmvercmp ] {
+
+ - Parameters [2] {
+ Parameter #0 [ <required> $evr1 ]
+ Parameter #1 [ <required> $evr2 ]
+ }
+ }
+ }
+}
+
diff --git a/examples/repomanage.php b/examples/repomanage.php
index 8428118..7682c3d 100644
--- a/examples/repomanage.php
+++ b/examples/repomanage.php
@@ -44,19 +44,20 @@ if (is_dir($rpms)) {
}
$tree = [];
-$handle = popen('rpm -qp --qf "%{NAME} %{EPOCHNUM} %{VERSION} %{RELEASE} %{ARCH} %{NEVR}\n" ' . $rpms . "/*.rpm", "r");
-while ($line = fgets($handle)) {
- $tab = explode(' ', trim($line));
- if (count($tab) == 6) {
- $tree[$tab[4]][$tab[0]][] = [
- 'name' => $tab[0],
- 'path' => $tab[5],
- 'evr' => "${tab[1]}:${tab[2]}-${tab[3]}",
- ];
+foreach(glob("$rpms/*.rpm") as $rpm) {
+ $info = rpminfo($rpm);
+ if (is_array($info)) {
+ $info['path'] = $rpm;
+ $info['evr'] = $info['Version'] . '-' . $info['Release'];
+ if (isset($info['Epoch'])) {
+ $info['evr'] = $info['Epoch'] . ":" . $info['evr'];
+ }
+ $tree[$info['Name']][$info['Arch']][] = $info;
} else {
- echo "Ignore $line\n";
+ echo "Skip $rpm\n";
}
}
+
foreach($tree as $arch => $subtree) {
foreach ($subtree as $name => $versions) {
if (count($versions) > $keep) {
diff --git a/php_rpminfo.h b/php_rpminfo.h
index 9c8319c..d90e9e1 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.1.0" /* Replace with version number for your extension */
+#define PHP_RPMINFO_VERSION "0.1.0-dev" /* Replace with version number for your extension */
#ifdef PHP_WIN32
# define PHP_RPMINFO_API __declspec(dllexport)
@@ -36,15 +36,9 @@ extern zend_module_entry rpminfo_module_entry;
#include "TSRM.h"
#endif
-/*
- Declare any global variables you may need between the BEGIN
- and END macros here:
-
ZEND_BEGIN_MODULE_GLOBALS(rpminfo)
- zend_long global_value;
- char *global_string;
+ rpmts ts;
ZEND_END_MODULE_GLOBALS(rpminfo)
-*/
/* Always refer to the globals in your function as RPMINFO_G(variable).
You are encouraged to rename these macros something shorter, see
diff --git a/rpminfo.c b/rpminfo.c
index b08e05b..30c003c 100644
--- a/rpminfo.c
+++ b/rpminfo.c
@@ -23,16 +23,17 @@
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
-#include "php_rpminfo.h"
+#include <rpm/rpmio.h>
#include <rpm/rpmlib.h>
+#include <rpm/rpmts.h>
+
+#include "php_rpminfo.h"
-/* If you declare any globals in php_rpminfo.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(rpminfo)
-*/
/* True global resources - no need for thread safety here */
-static int le_rpminfo;
+// static int le_rpminfo;
/* {{{ PHP_INI
*/
@@ -44,15 +45,130 @@ PHP_INI_END()
*/
/* }}} */
+static rpmts rpminfo_getts(rpmVSFlags flags) {
+ if (!RPMINFO_G(ts)) {
+ RPMINFO_G(ts) = rpmtsCreate();
+ }
+ if (RPMINFO_G(ts)) {
+ (void)rpmtsSetVSFlags(RPMINFO_G(ts), flags);
+ }
+ return RPMINFO_G(ts);
+}
+
+static void rpminfo_freets(void) {
+ if (RPMINFO_G(ts)) {
+ rpmtsFree(RPMINFO_G(ts));
+ RPMINFO_G(ts) = NULL;
+ }
+}
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_rpminfo, 0, 0, 1)
+ ZEND_ARG_INFO(0, path)
+ ZEND_ARG_INFO(0, full)
+ZEND_END_ARG_INFO()
+
+/* {{{ proto array rpminfo(string path [, bool full])
+ Retrieve information from a RPM file */
+PHP_FUNCTION(rpminfo)
+{
+ char *path, *msg=NULL, *val;
+ size_t len;
+ zend_bool full = 0;
+ FD_t f;
+ int rc;
+ Header h;
+ HeaderIterator hi;
+ rpmTagVal tag;
+ rpmTagType type;
+ rpmts ts = rpminfo_getts(_RPMVSF_NODIGESTS | _RPMVSF_NOSIGNATURES | RPMVSF_NOHDRCHK);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|b", &path, &len, &full) == FAILURE) {
+ return;
+ }
+
+ f = Fopen(path, "r");
+ if (f) {
+ rc = rpmReadPackageFile(ts, f, "rpminfo", &h);
+ if (rc == RPMRC_OK || rc == RPMRC_NOKEY || rc == RPMRC_NOTTRUSTED) {
+
+ array_init(return_value);
+ hi = headerInitIterator(h);
+ while ((tag=headerNextTag(hi)) != RPMTAG_NOT_FOUND) {
+ switch (tag) {
+ case RPMTAG_NAME:
+ case RPMTAG_VERSION:
+ case RPMTAG_RELEASE:
+ case RPMTAG_EPOCH:
+ case RPMTAG_ARCH:
+ break;
+ default:
+ if (!full) {
+ continue;
+ }
+ }
+
+ type = rpmTagGetTagType(tag);
+ switch (type) {
+ case RPM_STRING_TYPE:
+ case RPM_I18NSTRING_TYPE:
+ val = headerGetString(h, tag);
+ if (val) {
+ add_assoc_string(return_value, rpmTagGetName(tag), headerGetAsString(h, tag));
+ } else {
+ add_assoc_null(return_value, rpmTagGetName(tag));
+ }
+ break;
+ case RPM_CHAR_TYPE:
+ case RPM_INT8_TYPE:
+ case RPM_INT16_TYPE:
+ case RPM_INT32_TYPE:
+ case RPM_INT64_TYPE:
+ add_assoc_long(return_value, rpmTagGetName(tag), (zend_long)headerGetNumber(h, tag));
+ break;
+ default:
+ val = headerGetAsString(h, tag);
+ if (val) {
+ add_assoc_string(return_value, rpmTagGetName(tag), headerGetAsString(h, tag));
+ } else {
+ add_assoc_null(return_value, rpmTagGetName(tag));
+ }
+ }
+ }
+ if (full) {
+ add_assoc_bool(return_value, "IsSource", headerIsSource(h));
+ }
+ if (h) {
+ headerFree(h);
+ }
+ Fclose(f);
+ return;
+
+ } else if (rc == RPMRC_NOTFOUND) {
+ php_error_docref(NULL, E_WARNING, "Can't read '%s': Argument is not a RPM file", path);
+
+ } else if (rc == RPMRC_NOTFOUND) {
+ php_error_docref(NULL, E_WARNING, "Can't read '%s': Error reading header from package", path);
+
+ } else {
+ php_error_docref(NULL, E_WARNING, "Can't read '%s': Unkown error", path);
+ }
+
+ Fclose(f);
+ } else {
+ php_error_docref(NULL, E_WARNING, "Can't open '%s': %s", path, Fstrerror(f));
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
ZEND_BEGIN_ARG_INFO_EX(arginfo_rpmvercmp, 0, 0, 2)
ZEND_ARG_INFO(0, evr1)
ZEND_ARG_INFO(0, evr2)
ZEND_END_ARG_INFO()
-/* Every user-visible function in PHP should document itself in the source */
-/* {{{ proto string rpmcmpver(string evr1, string evr2)
- Return a string to confirm that the module is compiled in */
+/* {{{ proto int rpmcmpver(string evr1, string evr2)
+ Compare 2 RPM evr (epoch:version-release) strings */
PHP_FUNCTION(rpmvercmp)
{
char *evr1, *evr2;
@@ -64,6 +180,7 @@ PHP_FUNCTION(rpmvercmp)
RETURN_LONG(rpmvercmp(evr1, evr2));
}
+/* }}} */
/* {{{ php_rpminfo_init_globals
*/
@@ -135,12 +252,33 @@ PHP_MINFO_FUNCTION(rpminfo)
}
/* }}} */
+/* {{{ PHP_GINIT_FUNCTION
+ */
+static PHP_GINIT_FUNCTION(rpminfo) /* {{{ */
+{
+#if defined(COMPILE_DL_SESSION) && defined(ZTS)
+ ZEND_TSRMLS_CACHE_UPDATE();
+#endif
+
+ rpminfo_globals->ts = NULL;
+}
+/* }}} */
+
+/* {{{ PHP_GSHUTDOWN_FUNCTION
+*/
+PHP_GSHUTDOWN_FUNCTION(rpminfo)
+{
+ rpminfo_freets();
+}
+/* }}} */
+
/* {{{ rpminfo_functions[]
*
* Every user visible function must have an entry in rpminfo_functions[].
*/
const zend_function_entry rpminfo_functions[] = {
- PHP_FE(rpmvercmp, arginfo_rpmvercmp)
+ PHP_FE(rpminfo, arginfo_rpminfo)
+ PHP_FE(rpmvercmp, arginfo_rpmvercmp)
PHP_FE_END
};
/* }}} */
@@ -148,7 +286,9 @@ const zend_function_entry rpminfo_functions[] = {
/* {{{ rpminfo_module_entry
*/
zend_module_entry rpminfo_module_entry = {
- STANDARD_MODULE_HEADER,
+ STANDARD_MODULE_HEADER_EX,
+ NULL,
+ NULL,
"rpminfo",
rpminfo_functions,
PHP_MINIT(rpminfo),
@@ -157,7 +297,11 @@ zend_module_entry rpminfo_module_entry = {
PHP_RSHUTDOWN(rpminfo), /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(rpminfo),
PHP_RPMINFO_VERSION,
- STANDARD_MODULE_PROPERTIES
+ PHP_MODULE_GLOBALS(rpminfo),
+ PHP_GINIT(rpminfo),
+ PHP_GSHUTDOWN(rpminfo),
+ NULL,
+ STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */
diff --git a/tests/003.phpt b/tests/003.phpt
new file mode 100644
index 0000000..5a46dac
--- /dev/null
+++ b/tests/003.phpt
@@ -0,0 +1,270 @@
+--TEST--
+Check for rpminfo function
+--SKIPIF--
+<?php if (!extension_loaded("rpminfo")) print "skip"; ?>
+--FILE--
+<?php
+var_dump(rpminfo(__DIR__ . "/bidon.rpm"));
+var_dump(rpminfo(__DIR__ . "/bidon.rpm", true));
+var_dump(rpminfo(__DIR__ . "/bidon-src.rpm", true));
+// Errors
+var_dump(rpminfo(__DIR__ . "/missing.rpm"));
+var_dump(rpminfo(__FILE__));
+?>
+Done
+--EXPECTF--
+array(4) {
+ ["Name"]=>
+ string(5) "bidon"
+ ["Version"]=>
+ string(1) "1"
+ ["Release"]=>
+ string(11) "1.fc25.remi"
+ ["Arch"]=>
+ string(6) "x86_64"
+}
+array(63) {
+ ["Headeri18ntable"]=>
+ string(1) "C"
+ ["Sigsize"]=>
+ int(2304)
+ ["Sigmd5"]=>
+ string(32) "644819c3566819b1e10a5c97943de094"
+ ["Sha1header"]=>
+ string(40) "0a86742fe53973ac9ab4611187a83ffb44f1de5a"
+ ["Sha256header"]=>
+ string(64) "9aab7242a80212ad1fe4fdd3b250c0c4f176c0b3fb1355c0d62ff094fc3f7da0"
+ ["Name"]=>
+ string(5) "bidon"
+ ["Version"]=>
+ string(1) "1"
+ ["Release"]=>
+ string(11) "1.fc25.remi"
+ ["Summary"]=>
+ string(5) "Bidon"
+ ["Description"]=>
+ string(15) "A dummy package"
+ ["Buildtime"]=>
+ int(1516882146)
+ ["Buildhost"]=>
+ string(20) "builder.remirepo.net"
+ ["Size"]=>
+ int(29)
+ ["Vendor"]=>
+ string(11) "Remi Collet"
+ ["License"]=>
+ string(13) "Public Domain"
+ ["Packager"]=>
+ string(36) "Remi Collet <remi@fedoraproject.org>"
+ ["Group"]=>
+ string(11) "Unspecified"
+ ["Url"]=>
+ string(30) "http://blog.famillecollet.com/"
+ ["Os"]=>
+ string(5) "linux"
+ ["Arch"]=>
+ string(6) "x86_64"
+ ["Filesizes"]=>
+ int(0)
+ ["Filemodes"]=>
+ int(0)
+ ["Filerdevs"]=>
+ int(0)
+ ["Filemtimes"]=>
+ int(0)
+ ["Filedigests"]=>
+ NULL
+ ["Filelinktos"]=>
+ NULL
+ ["Fileflags"]=>
+ int(0)
+ ["Fileusername"]=>
+ NULL
+ ["Filegroupname"]=>
+ NULL
+ ["Sourcerpm"]=>
+ string(27) "bidon-1-1.fc25.remi.src.rpm"
+ ["Fileverifyflags"]=>
+ int(0)
+ ["Archivesize"]=>
+ int(428)
+ ["Providename"]=>
+ NULL
+ ["Requireflags"]=>
+ int(0)
+ ["Requirename"]=>
+ NULL
+ ["Requireversion"]=>
+ NULL
+ ["Rpmversion"]=>
+ string(6) "4.14.0"
+ ["Changelogtime"]=>
+ int(1419422400)
+ ["Changelogname"]=>
+ string(42) "Remi Collet <remi@fedoraproject.org> - 1-1"
+ ["Changelogtext"]=>
+ string(8) "- create"
+ ["Cookie"]=>
+ string(31) "builder.remirepo.net 1516882146"
+ ["Filedevices"]=>
+ int(0)
+ ["Fileinodes"]=>
+ int(0)
+ ["Filelangs"]=>
+ NULL
+ ["Provideflags"]=>
+ int(0)
+ ["Provideversion"]=>
+ NULL
+ ["Dirindexes"]=>
+ int(0)
+ ["Basenames"]=>
+ NULL
+ ["Dirnames"]=>
+ NULL
+ ["Optflags"]=>
+ string(219) "-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic"
+ ["Payloadformat"]=>
+ string(4) "cpio"
+ ["Payloadcompressor"]=>
+ string(2) "xz"
+ ["Payloadflags"]=>
+ string(1) "2"
+ ["Platform"]=>
+ string(23) "x86_64-redhat-linux-gnu"
+ ["Filecolors"]=>
+ int(0)
+ ["Fileclass"]=>
+ int(0)
+ ["Classdict"]=>
+ NULL
+ ["Sourcepkgid"]=>
+ string(32) "188da2a3966f4a5f0dd48e784be76846"
+ ["Filedigestalgo"]=>
+ int(8)
+ ["Encoding"]=>
+ string(5) "utf-8"
+ ["Payloaddigest"]=>
+ string(64) "ace77d50077cb8088d9bf224c9a9e89343a2aa40fe596b3e60ef10a9a200a3bd"
+ ["Payloaddigestalgo"]=>
+ int(8)
+ ["IsSource"]=>
+ bool(false)
+}
+array(54) {
+ ["Headeri18ntable"]=>
+ string(1) "C"
+ ["Sigsize"]=>
+ int(1753)
+ ["Sigmd5"]=>
+ string(32) "188da2a3966f4a5f0dd48e784be76846"
+ ["Sha1header"]=>
+ string(40) "994275fb4366d82043c791c50682cbe46e1c96d6"
+ ["Sha256header"]=>
+ string(64) "4c2f1cba929cc05ce58d4a9184d4652f2f7d7bdf05ba1dc92966ce9e9cefe93c"
+ ["Name"]=>
+ string(5) "bidon"
+ ["Version"]=>
+ string(1) "1"
+ ["Release"]=>
+ string(11) "1.fc25.remi"
+ ["Summary"]=>
+ string(5) "Bidon"
+ ["Description"]=>
+ string(15) "A dummy package"
+ ["Buildtime"]=>
+ int(1516882146)
+ ["Buildhost"]=>
+ string(20) "builder.remirepo.net"
+ ["Size"]=>
+ int(360)
+ ["Vendor"]=>
+ string(11) "Remi Collet"
+ ["License"]=>
+ string(13) "Public Domain"
+ ["Packager"]=>
+ string(36) "Remi Collet <remi@fedoraproject.org>"
+ ["Group"]=>
+ string(11) "Unspecified"
+ ["Url"]=>
+ string(30) "http://blog.famillecollet.com/"
+ ["Os"]=>
+ string(5) "linux"
+ ["Arch"]=>
+ string(6) "x86_64"
+ ["Filesizes"]=>
+ int(360)
+ ["Filemodes"]=>
+ int(33188)
+ ["Filerdevs"]=>
+ int(0)
+ ["Filemtimes"]=>
+ int(1516882140)
+ ["Filedigests"]=>
+ string(64) "195d7dd3ca9518024a1554e68b3f63fa7e2bdaa4efac59f06c1ab231283e6067"
+ ["Filelinktos"]=>
+ string(0) ""
+ ["Fileflags"]=>
+ int(32)
+ ["Fileusername"]=>
+ string(6) "extras"
+ ["Filegroupname"]=>
+ string(4) "remi"
+ ["Fileverifyflags"]=>
+ int(4294967295)
+ ["Archivesize"]=>
+ int(608)
+ ["Requireflags"]=>
+ int(0)
+ ["Requirename"]=>
+ NULL
+ ["Requireversion"]=>
+ NULL
+ ["Rpmversion"]=>
+ string(6) "4.14.0"
+ ["Changelogtime"]=>
+ int(1419422400)
+ ["Changelogname"]=>
+ string(42) "Remi Collet <remi@fedoraproject.org> - 1-1"
+ ["Changelogtext"]=>
+ string(8) "- create"
+ ["Cookie"]=>
+ string(31) "builder.remirepo.net 1516882146"
+ ["Filedevices"]=>
+ int(1)
+ ["Fileinodes"]=>
+ int(1)
+ ["Filelangs"]=>
+ string(0) ""
+ ["Sourcepackage"]=>
+ int(1)
+ ["Dirindexes"]=>
+ int(0)
+ ["Basenames"]=>
+ string(10) "bidon.spec"
+ ["Dirnames"]=>
+ string(0) ""
+ ["Payloadformat"]=>
+ string(4) "cpio"
+ ["Payloadcompressor"]=>
+ string(4) "gzip"
+ ["Payloadflags"]=>
+ string(1) "9"
+ ["Filedigestalgo"]=>
+ int(8)
+ ["Encoding"]=>
+ string(5) "utf-8"
+ ["Payloaddigest"]=>
+ string(64) "b104f6e80a0b761ca05b0c478c5a5e3f5fe57cf079cfca53d360351806c23951"
+ ["Payloaddigestalgo"]=>
+ int(8)
+ ["IsSource"]=>
+ bool(true)
+}
+
+Warning: rpminfo(): Can't open '%s/tests/missing.rpm': No such file or directory in %s/003.php on line 6
+bool(false)
+
+Warning: rpminfo(): Can't read '%s/tests/003.php': Argument is not a RPM file in %s/003.php on line 7
+bool(false)
+Done
diff --git a/tests/bidon-src.rpm b/tests/bidon-src.rpm
new file mode 100644
index 0000000..c1c05cf
--- /dev/null
+++ b/tests/bidon-src.rpm
Binary files differ
diff --git a/tests/bidon.rpm b/tests/bidon.rpm
new file mode 100644
index 0000000..259ddf6
--- /dev/null
+++ b/tests/bidon.rpm
Binary files differ