From 5914d0ec2995d4f4d128c3e96b79f22ec8f48d64 Mon Sep 17 00:00:00 2001 From: Florian Festi Date: Tue, 15 Dec 2009 13:15:10 +0100 Subject: [PATCH] rpmdbKeyIterator: loop over keys in the database indexes --- lib/rpmdb.c | 106 +++++++++++++++++++++++++++++++++++++++- lib/rpmdb.h | 40 ++++++++++++++++ lib/rpmtypes.h | 1 + python/Makefile.am | 1 + python/rpmki-py.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++ python/rpmki-py.h | 12 +++++ python/rpmmodule.c | 5 ++ python/rpmts-py.c | 29 +++++++++++ 8 files changed, 331 insertions(+), 1 deletion(-) create mode 100644 python/rpmki-py.c create mode 100644 python/rpmki-py.h diff --git a/lib/rpmdb.c b/lib/rpmdb.c index cd8a4ff..73ca89a 100644 --- a/lib/rpmdb.c +++ b/lib/rpmdb.c @@ -512,9 +512,18 @@ struct rpmdbMatchIterator_s { }; -static rpmdb rpmdbRock; +struct rpmdbKeyIterator_s { + rpmdbKeyIterator ki_next; + rpmdb ki_db; + dbiIndex ki_dbi; + rpmTag ki_rpmtag; + DBC * ki_dbc; + DBT ki_key; +}; +static rpmdb rpmdbRock; static rpmdbMatchIterator rpmmiRock; +static rpmdbKeyIterator rpmkiRock; int rpmdbCheckTerminate(int terminate) { @@ -2252,6 +2261,101 @@ static int td2key(rpmtd tagdata, DBT *key, int *freedata) return 1; } +/* + * rpmdbKeyIterator + */ + +rpmdbKeyIterator rpmdbKeyIteratorInit(rpmdb db, rpmTag rpmtag) +{ + rpmdbKeyIterator ki; + dbiIndex dbi = NULL; + int rc = 0; + + if (db == NULL) + return NULL; + + (void) rpmdbCheckSignals(); + + rc = dbiOpen(db, rpmtag, &dbi, 0); + if (dbi == NULL) + return NULL; + + /* Chain cursors for teardown on abnormal exit. */ + ki = xcalloc(1, sizeof(*ki)); + ki->ki_next = rpmkiRock; + rpmkiRock = ki; + + ki->ki_db = rpmdbLink(db); + ki->ki_rpmtag = rpmtag; + ki->ki_dbi = dbi; + + return ki; +} + +int rpmdbKeyIteratorNext(rpmdbKeyIterator ki) +{ + int rc, xx; + DBT data; + + if (ki == NULL) + return 1; + + if (ki->ki_dbc == NULL) + xx = dbiCopen(ki->ki_dbi, &ki->ki_dbc, 0); + + memset(&data, 0, sizeof(data)); + data.flags = DB_DBT_PARTIAL; + rc = dbiGet(ki->ki_dbi, ki->ki_dbc, &ki->ki_key, &data, DB_NEXT); + + if (rc != 0 && rc != DB_NOTFOUND) { + rpmlog(RPMLOG_ERR, + _("error(%d:%s) getting next key from %s index\n"), + rc, db_strerror(rc), rpmTagGetName(ki->ki_rpmtag)); + } + return rc; +} + +const void * rpmdbKeyIteratorKey(rpmdbKeyIterator ki) +{ + if (ki == NULL) return NULL; + return ki->ki_key.data; +} + +size_t rpmdbKeyIteratorKeySize(rpmdbKeyIterator ki) +{ + if (ki == NULL) return (size_t) 0; + return (size_t)(ki->ki_key.size); +} + + +rpmdbKeyIterator rpmdbKeyIteratorFree(rpmdbKeyIterator ki) +{ + rpmdbKeyIterator * prev, next; + int xx; + + if (ki == NULL) + return ki; + + prev = &rpmkiRock; + while ((next = *prev) != NULL && next != ki) + prev = &next->ki_next; + if (next) { + *prev = next->ki_next; + next->ki_next = NULL; + } + + if (ki->ki_dbc) + xx = dbiCclose(ki->ki_dbi, ki->ki_dbc, 0); + ki->ki_dbc = NULL; + ki->ki_dbi = NULL; /* ??? */ + ki->ki_db = rpmdbUnlink(ki->ki_db); + + ki = _free(ki); + return ki; +} + + + static void logAddRemove(const char *dbiname, int removing, rpmtd tagdata) { diff --git a/lib/rpmdb.h b/lib/rpmdb.h index c130a42..ee5ebf7 100644 --- a/lib/rpmdb.h +++ b/lib/rpmdb.h @@ -216,6 +216,46 @@ rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi); int rpmdbRebuild(const char * prefix, rpmts ts, rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, char ** msg)); + + + +/** \ingroup rpmdb + * Get a key iterator for an index + * @param db rpm database + * @param rpmtag the index to iterate over + * @return the key iterator + */ +rpmdbKeyIterator rpmdbKeyIteratorInit(rpmdb db, rpmTag rpmtag); + +/** \ingroup rpmdb + * Get the next key - must be called before getting the first key + * @param ki key iterator + * @return 0 on success; != 0 on error or end of index + */ +int rpmdbKeyIteratorNext(rpmdbKeyIterator ki); + +/** \ingroup rpmdb + * Get current key + * @param ki key iterator + * @return pointer to key content. Keys are not zero terminated! + */ +const void * rpmdbKeyIteratorKey(rpmdbKeyIterator ki); + +/** \ingroup rpmdb + * Get length of key + * @param ki key iterator + * @return length of key + */ +size_t rpmdbKeyIteratorKeySize(rpmdbKeyIterator ki); + +/** \ingroup rpmdb + * Free key iterator + * @param ki key iterator + * return NULL + */ +rpmdbKeyIterator rpmdbKeyIteratorFree(rpmdbKeyIterator ki); + + #ifdef __cplusplus } #endif diff --git a/lib/rpmtypes.h b/lib/rpmtypes.h index c6f3805..8e2bb7d 100644 --- a/lib/rpmtypes.h +++ b/lib/rpmtypes.h @@ -67,6 +67,7 @@ typedef struct rpmdbMatchIterator_s * rpmdbMatchIterator; typedef struct rpmtsi_s * rpmtsi; typedef struct rpmps_s * rpmps; +typedef struct rpmdbKeyIterator_s * rpmdbKeyIterator; typedef const void * fnpyKey; typedef void * rpmCallbackData; /** @} */ diff --git a/python/Makefile.am b/python/Makefile.am index b952743..57bcb6b 100644 --- a/python/Makefile.am +++ b/python/Makefile.am @@ -23,6 +23,7 @@ _rpmmodule_la_SOURCES = rpmmodule.c rpmsystem-py.h \ rpmfi-py.c rpmfi-py.h \ rpmkeyring-py.c rpmkeyring-py.h \ rpmmi-py.c rpmmi-py.h \ + rpmki-py.c rpmki-py.h \ rpmps-py.c rpmps-py.h \ rpmmacro-py.c rpmmacro-py.h \ rpmtd-py.c rpmtd-py.h \ diff --git a/python/rpmki-py.c b/python/rpmki-py.c new file mode 100644 index 0000000..8ed0487 --- /dev/null +++ b/python/rpmki-py.c @@ -0,0 +1,138 @@ +#include "rpmsystem-py.h" + +#include + +#include "rpmki-py.h" +#include "header-py.h" + +#include "debug.h" + +/** \ingroup python + * \class Rpmki + * \brief A python rpm.ki key iterator object represents the keys of a + * database index. + * + * The rpm.ki class conains the following methods: + * - next() -> key Return the next key. + * + * To obtain a rpm.ki object to query the database used by a transaction, + * the ts.dbKeys(tag) method is used. + * + * Here's an example that prints the name of all installed packages: + * \code + * import rpm + * ts = rpm.TransactionSet() + * for name in ts.dbKeys("conflictname"): + * print name + * \endcode + * + * ts.dbMatch() can be used to get the packages containing the keys of interest + +/** \ingroup python + * \name Class: Rpmki + */ + +struct rpmkiObject_s { + PyObject_HEAD + PyObject *md_dict; /*!< to look like PyModuleObject */ + PyObject *ref; /* for db/ts refcounting */ + rpmdbKeyIterator ki; +}; + +static PyObject * +rpmki_iternext(rpmkiObject * s) +{ + if (s->ki == NULL || (rpmdbKeyIteratorNext(s->ki)) != 0) { + s->ki = rpmdbKeyIteratorFree(s->ki); + return NULL; + } + return PyString_FromStringAndSize(rpmdbKeyIteratorKey(s->ki), + rpmdbKeyIteratorKeySize(s->ki)); +}; + +static struct PyMethodDef rpmki_methods[] = { + {NULL, NULL} /* sentinel */ +}; + +static void rpmki_dealloc(rpmkiObject * s) +{ + s->ki = rpmdbKeyIteratorFree(s->ki); + Py_DECREF(s->ref); + Py_TYPE(s)->tp_free((PyObject *)s); +} + +static int rpmki_bool(rpmkiObject *s) +{ + return (s->ki != NULL); +} + +static PyNumberMethods rpmki_as_number = { + 0, /* nb_add */ + 0, /* nb_subtract */ + 0, /* nb_multiply */ + 0, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + 0, (inquiry)rpmki_bool, /* nb_bool/nonzero */ +}; + +static char rpmki_doc[] = +""; + +PyTypeObject rpmki_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "rpm.ki", /* tp_name */ + sizeof(rpmkiObject), /* tp_size */ + 0, /* tp_itemsize */ + (destructor) rpmki_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + &rpmki_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + rpmki_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc) rpmki_iternext, /* tp_iternext */ + rpmki_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ +}; + +PyObject * rpmki_Wrap(PyTypeObject *subtype, rpmdbKeyIterator ki, PyObject *s) +{ + rpmkiObject * kio = (rpmkiObject *)subtype->tp_alloc(subtype, 0); + if (kio == NULL) return NULL; + + kio->ki = ki; + kio->ref = s; + Py_INCREF(kio->ref); + return (PyObject *) kio; +} diff --git a/python/rpmki-py.h b/python/rpmki-py.h new file mode 100644 index 0000000..5fc3543 --- /dev/null +++ b/python/rpmki-py.h @@ -0,0 +1,12 @@ +#ifndef H_RPMKI_PY +#define H_RPMKI_PY + +typedef struct rpmkiObject_s rpmkiObject; + +extern PyTypeObject rpmki_Type; + +#define rpmkiObject_Check(v) ((v)->ob_type == &rpmki_Type) + +PyObject * rpmki_Wrap(PyTypeObject *subtype, rpmdbKeyIterator ki, PyObject *s); + +#endif diff --git a/python/rpmmodule.c b/python/rpmmodule.c index 78340a9..e396cd0 100644 --- a/python/rpmmodule.c +++ b/python/rpmmodule.c @@ -12,6 +12,7 @@ #include "rpmfi-py.h" #include "rpmkeyring-py.h" #include "rpmmi-py.h" +#include "rpmki-py.h" #include "rpmps-py.h" #include "rpmmacro-py.h" #include "rpmtd-py.h" @@ -202,6 +203,7 @@ static int prepareInitModule(void) if (PyType_Ready(&rpmfi_Type) < 0) return 0; if (PyType_Ready(&rpmKeyring_Type) < 0) return 0; if (PyType_Ready(&rpmmi_Type) < 0) return 0; + if (PyType_Ready(&rpmki_Type) < 0) return 0; if (PyType_Ready(&rpmProblem_Type) < 0) return 0; if (PyType_Ready(&rpmPubkey_Type) < 0) return 0; #if 0 @@ -301,6 +303,9 @@ static int initModule(PyObject *m) Py_INCREF(&rpmmi_Type); PyModule_AddObject(m, "mi", (PyObject *) &rpmmi_Type); + Py_INCREF(&rpmki_Type); + PyModule_AddObject(m, "ki", (PyObject *) &rpmki_Type); + Py_INCREF(&rpmProblem_Type); PyModule_AddObject(m, "prob", (PyObject *) &rpmProblem_Type); diff --git a/python/rpmts-py.c b/python/rpmts-py.c index 16a8243..13bb3aa 100644 --- a/python/rpmts-py.c +++ b/python/rpmts-py.c @@ -12,6 +12,7 @@ #include "rpmkeyring-py.h" #include "rpmfi-py.h" /* XXX for rpmfiNew */ #include "rpmmi-py.h" +#include "rpmki-py.h" #include "rpmps-py.h" #include "rpmte-py.h" @@ -628,6 +629,31 @@ exit: Py_XDECREF(str); return mio; } +static PyObject * +rpmts_Keys(rpmtsObject * s, PyObject * args, PyObject * kwds) +{ + rpmTag tag; + PyObject *mio = NULL; + char * kwlist[] = {"tag", "pattern", "type", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:Keys", kwlist, + tagNumFromPyObject, &tag)) + return NULL; + + /* XXX If not already opened, open the database O_RDONLY now. */ + if (rpmtsGetRdb(s->ts) == NULL) { + int rc = rpmtsOpenDB(s->ts, O_RDONLY); + if (rc || rpmtsGetRdb(s->ts) == NULL) { + PyErr_SetString(pyrpmError, "rpmdb open failed"); + goto exit; + } + } + + mio = rpmki_Wrap(&rpmki_Type, rpmdbKeyIteratorInit(rpmtsGetRdb(s->ts), tag), (PyObject*)s); + +exit: + return mio; +} static struct PyMethodDef rpmts_methods[] = { {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS, @@ -681,6 +707,9 @@ static struct PyMethodDef rpmts_methods[] = { {"dbMatch", (PyCFunction) rpmts_Match, METH_VARARGS|METH_KEYWORDS, "ts.dbMatch([TagN, [key]]) -> mi\n\ - Create a match iterator for the default transaction rpmdb.\n" }, + {"dbKeys", (PyCFunction) rpmts_Keys, METH_VARARGS|METH_KEYWORDS, +"ts.dbKeys(TagN) -> ki\n\ +-Create a key iterator for the default transaction rpmdb.\n" }, {NULL, NULL} /* sentinel */ }; -- 2.7.4