diff options
Diffstat (limited to 'rpminfo.c')
-rw-r--r-- | rpminfo.c | 488 |
1 files changed, 398 insertions, 90 deletions
@@ -1,6 +1,6 @@ /* +----------------------------------------------------------------------+ - | PHP Version 7 | + | rpminfo extension for PHP | +----------------------------------------------------------------------+ | Copyright (c) The PHP Group | +----------------------------------------------------------------------+ @@ -23,6 +23,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" +#include "ext/standard/php_string.h" #include <fcntl.h> #include <rpm/rpmdb.h> @@ -32,6 +33,21 @@ #include "php_rpminfo.h" +#include "rpminfo_arginfo.h" + +#ifdef HAVE_ARCHIVE +struct php_rpm_stream_data_t { + FD_t gzdi; + Header h; + rpmfiles files; + rpmfi fi; + php_stream *stream; +}; + +#define STREAM_DATA_FROM_STREAM() \ + struct php_rpm_stream_data_t *self = (struct php_rpm_stream_data_t *) stream->abstract; +#endif + ZEND_DECLARE_MODULE_GLOBALS(rpminfo) static rpmts rpminfo_getts(void) { @@ -199,16 +215,6 @@ static void rpm_header_to_zval(zval *return_value, Header h, zend_bool full) } } -#if PHP_VERSION_ID < 70200 -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpminfo, 0, 1, IS_ARRAY, NULL, 1) -#else -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpminfo, 0, 1, IS_ARRAY, 1) -#endif - ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, full, _IS_BOOL, 0) - ZEND_ARG_TYPE_INFO(1, error, IS_STRING, 1) -ZEND_END_ARG_INFO() - /* {{{ proto array rpminfo(string path [, bool full [, string &$error]) Retrieve information from a RPM file */ PHP_FUNCTION(rpminfo) @@ -222,13 +228,16 @@ PHP_FUNCTION(rpminfo) rpmts ts = rpminfo_getts(); if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|bz", &path, &len, &full, &error) == FAILURE) { - return; + RETURN_THROWS(); } if (error) { ZVAL_DEREF(error); zval_dtor(error); ZVAL_NULL(error); } + if (php_check_open_basedir(path)) { + RETURN_NULL(); + } f = Fopen(path, "r"); if (f) { @@ -267,15 +276,6 @@ PHP_FUNCTION(rpminfo) } /* }}} */ -#if PHP_VERSION_ID < 70200 -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmdbinfo, 0, 1, IS_ARRAY, NULL, 1) -#else -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmdbinfo, 0, 1, IS_ARRAY, 1) -#endif - ZEND_ARG_TYPE_INFO(0, nevr, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, full, _IS_BOOL, 0) -ZEND_END_ARG_INFO() - /* {{{ proto array rpmdbinfo(string nevr [, bool full]) Retrieve information from an installed RPM */ PHP_FUNCTION(rpmdbinfo) @@ -288,13 +288,13 @@ PHP_FUNCTION(rpmdbinfo) rpmdbMatchIterator di; if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|b", &name, &len, &full) == FAILURE) { - return; + RETURN_THROWS(); } db = rpminfo_getdb(); di = rpmdbInitIterator(db, RPMDBI_LABEL, name, len); if (!di) { - // Not found + /* Not found */ RETURN_NULL(); } @@ -319,7 +319,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) { @@ -363,17 +363,6 @@ static int haveIndex(zend_long tag) { return 0; } -#if PHP_VERSION_ID < 70200 -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmdbsearch, 0, 1, IS_ARRAY, NULL, 1) -#else -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmdbsearch, 0, 1, IS_ARRAY, 1) -#endif - ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, rpmtag, IS_LONG, 0) - ZEND_ARG_TYPE_INFO(0, rpmmire, IS_LONG, 0) - ZEND_ARG_TYPE_INFO(0, full, _IS_BOOL, 0) -ZEND_END_ARG_INFO() - /* {{{ proto array rpmdbsearch(string pattern [, integer tag_name = RPMTAG_NAME [, integer mode = -1 [, bool full = 0]]]) Search information from installed RPMs */ PHP_FUNCTION(rpmdbsearch) @@ -391,20 +380,32 @@ PHP_FUNCTION(rpmdbsearch) int useIndex = 1; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|llb", &name, &len, &crit, &mode, &full) == FAILURE) { - return; + RETURN_THROWS(); + } + if (rpmTagGetType(crit) == RPM_NULL_TYPE) { + zend_argument_value_error(2, "Unkown rpmtag"); + RETURN_THROWS(); + } + if (mode != RPMMIRE_DEFAULT && + mode != RPMMIRE_STRCMP && + mode != RPMMIRE_REGEX && + mode != RPMMIRE_GLOB && + mode != -1) { + zend_argument_value_error(3, "Unkown rpmmire"); + RETURN_THROWS(); } if (crit == RPMTAG_PKGID) { if (len != 32) { - php_error_docref(NULL, E_WARNING, "Bad length for PKGID, 32 expected"); - RETURN_NULL(); + zend_argument_value_error(1, "Bad length for PKGID, 32 expected"); + RETURN_THROWS(); } len = hex2bin(name, MD5, len); name = MD5; } else if (crit == RPMTAG_HDRID) { if (len != 40) { - php_error_docref(NULL, E_WARNING, "Bad length for HDRID, 40 expected"); - RETURN_NULL(); + zend_argument_value_error(1, "Bad length for HDRID, 40 expected"); + RETURN_THROWS(); } } else if (crit == RPMTAG_INSTALLTID) { tid = atol(name); @@ -433,7 +434,7 @@ PHP_FUNCTION(rpmdbsearch) } } if (!di) { - // Not found + /* Not found */ RETURN_NULL(); } @@ -448,15 +449,6 @@ PHP_FUNCTION(rpmdbsearch) } /* }}} */ -#if PHP_VERSION_ID < 70200 -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmvercmp, 0, 2, IS_LONG, NULL, 0) -#else -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmvercmp, 0, 2, IS_LONG, 0) -#endif - ZEND_ARG_TYPE_INFO(0, evr1, IS_STRING, 0) - ZEND_ARG_TYPE_INFO(0, evr2, IS_STRING, 0) -ZEND_END_ARG_INFO() - /* {{{ proto int rpmcmpver(string evr1, string evr2) Compare 2 RPM EVRs (epoch:version-release) strings */ PHP_FUNCTION(rpmvercmp) @@ -464,16 +456,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) { - return; + 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; @@ -493,11 +486,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; @@ -513,27 +506,42 @@ 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(); } /* }}} */ -#if PHP_VERSION_ID < 70200 -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmaddtag, 0, 1, _IS_BOOL, NULL, 0) -#else -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_rpmaddtag, 0, 1, _IS_BOOL, 0) -#endif - ZEND_ARG_TYPE_INFO(0, rpmtag, IS_LONG, 0) -ZEND_END_ARG_INFO() - /* {{{ proto int rpmaddtag(int tag) add a tag in the default set */ PHP_FUNCTION(rpmaddtag) @@ -542,7 +550,12 @@ PHP_FUNCTION(rpmaddtag) zend_long tag; if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &tag) == FAILURE) { - return; + RETURN_THROWS(); + } + + if (rpmTagGetType(tag) == RPM_NULL_TYPE) { + zend_argument_value_error(1, "Unkown rpmtag"); + RETURN_THROWS(); } if (RPMINFO_G(tags)) { @@ -551,8 +564,10 @@ PHP_FUNCTION(rpmaddtag) RETURN_BOOL(0); } } - RPMINFO_G(max_tags) += 16; - RPMINFO_G(tags) = erealloc(RPMINFO_G(tags), RPMINFO_G(max_tags) * sizeof(rpmTagVal)); + if (RPMINFO_G(nb_tags) == RPMINFO_G(max_tags)) { + RPMINFO_G(max_tags) += 16; + RPMINFO_G(tags) = erealloc(RPMINFO_G(tags), RPMINFO_G(max_tags) * sizeof(rpmTagVal)); + } } else { RPMINFO_G(max_tags) = 16; RPMINFO_G(tags) = emalloc(RPMINFO_G(max_tags) * sizeof(rpmTagVal)); @@ -563,12 +578,308 @@ PHP_FUNCTION(rpmaddtag) } /* }}} */ +#ifdef HAVE_ARCHIVE +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); +} +/* }}} */ +#endif /* HAVE_ARCHIVE */ + + /* {{{ 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); @@ -608,6 +919,10 @@ PHP_MINIT_FUNCTION(rpminfo) } rpmtdFree(names); +#ifdef HAVE_ARCHIVE + php_register_url_stream_wrapper("rpm", &php_stream_rpm_wrapper); +#endif + return SUCCESS; } /* }}} */ @@ -659,7 +974,14 @@ 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); +#ifdef HAVE_ARCHIVE + php_info_print_table_row(2, "RPM stream wrapper", "yes"); +#else + php_info_print_table_row(2, "RPM stream wrapper", "no"); +#endif php_info_print_table_end(); /* Remove comments if you have entries in php.ini @@ -680,20 +1002,6 @@ static PHP_GINIT_FUNCTION(rpminfo) /* {{{ */ } /* }}} */ -/* {{{ rpminfo_functions[] - * - * Every user visible function must have an entry in rpminfo_functions[]. - */ -const zend_function_entry rpminfo_functions[] = { - PHP_FE(rpmaddtag, arginfo_rpmaddtag) - PHP_FE(rpmdbinfo, arginfo_rpmdbinfo) - PHP_FE(rpmdbsearch, arginfo_rpmdbsearch) - PHP_FE(rpminfo, arginfo_rpminfo) - PHP_FE(rpmvercmp, arginfo_rpmvercmp) - PHP_FE_END -}; -/* }}} */ - /* {{{ rpminfo_module_entry */ zend_module_entry rpminfo_module_entry = { @@ -701,7 +1009,7 @@ zend_module_entry rpminfo_module_entry = { NULL, NULL, "rpminfo", - rpminfo_functions, + ext_functions, PHP_MINIT(rpminfo), NULL, PHP_RINIT(rpminfo), |