diff options
Diffstat (limited to 'rpminfo.c')
-rw-r--r-- | rpminfo.c | 413 |
1 files changed, 363 insertions, 50 deletions
@@ -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,17 +33,20 @@ #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 +#ifdef HAVE_ARCHIVE +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; +#endif ZEND_DECLARE_MODULE_GLOBALS(rpminfo) @@ -231,6 +235,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 +294,7 @@ PHP_FUNCTION(rpmdbinfo) db = rpminfo_getdb(); di = rpmdbInitIterator(db, RPMDBI_LABEL, name, len); if (!di) { - // Not found + /* Not found */ RETURN_NULL(); } @@ -312,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) { @@ -376,49 +383,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 +434,7 @@ PHP_FUNCTION(rpmdbsearch) } } if (!di) { - // Not found + /* Not found */ RETURN_NULL(); } @@ -469,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) { + 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 +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; @@ -518,16 +506,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 +554,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 +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); @@ -617,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; } /* }}} */ @@ -668,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 |