rpm/python/db-py.c

500 lines
11 KiB
C

/** \ingroup python
* \file python/db-py.c
*/
#include <fcntl.h>
#include <unistd.h>
#include "Python.h"
#include "rpmio_internal.h"
#include "rpmcli.h" /* XXX for rpmCheckSig */
#include "misc.h"
#include "header_internal.h"
#include "upgrade.h"
#include "db-py.h"
#include "header-py.h"
/** \ingroup python
*/
typedef struct rpmdbMIObject_s rpmdbMIObject;
/** \ingroup python
* \class rpmdbMatchIterator
* \brief A python rpmdbMatchIterator object represents the result of an RPM
* database query.
*/
/** \ingroup python
* \name Class: rpmdbMatchIterator
*/
/*@{*/
/** \ingroup python
*/
struct rpmdbMIObject_s {
PyObject_HEAD;
rpmdbObject *db;
rpmdbMatchIterator mi;
} ;
/** \ingroup python
*/
static PyObject *
rpmdbMINext(rpmdbMIObject * s, PyObject * args) {
/* XXX assume header? */
Header h;
hdrObject * ho;
if (!PyArg_ParseTuple (args, "")) return NULL;
h = rpmdbNextIterator(s->mi);
if (!h) {
Py_INCREF(Py_None);
return Py_None;
}
ho = createHeaderObject(h);
return (PyObject *) ho;
}
/** \ingroup python
*/
static PyObject *
rpmdbMIpattern(rpmdbMIObject * s, PyObject * args) {
PyObject *index = NULL;
int type;
char * pattern;
int tag;
if (!PyArg_ParseTuple(args, "Ois", &index, &type, &pattern))
return NULL;
if (index == NULL)
tag = 0;
else if ((tag = tagNumFromPyObject (index)) == -1) {
PyErr_SetString(PyExc_TypeError, "unknown tag type");
return NULL;
}
rpmdbSetIteratorRE(s->mi, tag, type, pattern);
Py_INCREF (Py_None);
return Py_None;
}
/** \ingroup python
*/
static struct PyMethodDef rpmdbMIMethods[] = {
{"next", (PyCFunction) rpmdbMINext, 1 },
{"pattern", (PyCFunction) rpmdbMIpattern, 1 },
{NULL, NULL} /* sentinel */
};
/** \ingroup python
*/
static PyObject * rpmdbMIGetAttr (rpmdbObject *s, char *name) {
return Py_FindMethod (rpmdbMIMethods, (PyObject *) s, name);
}
/** \ingroup python
*/
static void rpmdbMIDealloc(rpmdbMIObject * s) {
if (s && s->mi) {
rpmdbFreeIterator(s->mi);
}
Py_DECREF (s->db);
PyMem_DEL(s);
}
/** \ingroup python
*/
PyTypeObject rpmdbMIType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"rpmdbMatchIterator", /* tp_name */
sizeof(rpmdbMIObject), /* tp_size */
0, /* tp_itemsize */
(destructor) rpmdbMIDealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc) rpmdbMIGetAttr, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
};
/*@}*/
/** \ingroup python
* \class rpmdb
* \brief A python rpmdb object represents an RPM database.
*
* Instances of the rpmdb object provide access to the records of a
* RPM database. The records are accessed by index number. To
* retrieve the header data in the RPM database, the rpmdb object is
* subscripted as you would access members of a list.
*
* The rpmdb class contains the following methods:
*
* - firstkey() Returns the index of the first record in the database.
* @deprecated Legacy, use rpmdbMatchIterator instead.
*
* - nextkey(index) Returns the index of the next record after "index" in the
* database.
* @param index current rpmdb location
* @deprecated Legacy, use rpmdbMatchIterator instead.
*
* - findbyfile(file) Returns a list of the indexes to records that own file
* "file".
* @param file absolute path to file
*
* - findbyname(name) Returns a list of the indexes to records for packages
* named "name".
* @param name package name
*
* - findbyprovides(dep) Returns a list of the indexes to records for packages
* that provide "dep".
* @param dep provided dependency string
*
* To obtain a rpmdb object, the opendb function in the rpm module
* must be called. The opendb function takes two optional arguments.
* The first optional argument is a boolean flag that specifies if the
* database is to be opened for read/write access or read-only access.
* The second argument specifies an alternate root directory for RPM
* to use.
*
* An example of opening a database and retrieving the first header in
* the database, then printing the name of the package that the header
* represents:
* \code
* import rpm
* rpmdb = rpm.opendb()
* index = rpmdb.firstkey()
* header = rpmdb[index]
* print header[rpm.RPMTAG_NAME]
* \endcode
* To print all of the packages in the database that match a package
* name, the code will look like this:
* \code
* import rpm
* rpmdb = rpm.opendb()
* indexes = rpmdb.findbyname("foo")
* for index in indexes:
* header = rpmdb[index]
* print "%s-%s-%s" % (header[rpm.RPMTAG_NAME],
* header[rpm.RPMTAG_VERSION],
* header[rpm.RPMTAG_RELEASE])
* \endcode
*/
/** \ingroup python
* \name Class: rpmdb
*/
/*@{*/
/**
*/
static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args) {
int first;
if (!PyArg_ParseTuple (args, "")) return NULL;
/* Acquire all offsets in one fell swoop. */
if (s->offsets == NULL || s->noffs <= 0) {
rpmdbMatchIterator mi;
Header h;
if (s->offsets)
free(s->offsets);
s->offsets = NULL;
s->noffs = 0;
mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
while ((h = rpmdbNextIterator(mi)) != NULL) {
s->noffs++;
s->offsets = realloc(s->offsets, s->noffs * sizeof(s->offsets[0]));
s->offsets[s->noffs-1] = rpmdbGetIteratorOffset(mi);
}
rpmdbFreeIterator(mi);
}
s->offx = 0;
if (s->offsets != NULL && s->offx < s->noffs)
first = s->offsets[s->offx++];
else
first = 0;
if (!first) {
PyErr_SetString(pyrpmError, "cannot find first entry in database\n");
return NULL;
}
return Py_BuildValue("i", first);
}
/**
*/
static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args) {
int where;
if (!PyArg_ParseTuple (args, "i", &where)) return NULL;
if (s->offsets == NULL || s->offx >= s->noffs) {
Py_INCREF(Py_None);
return Py_None;
}
where = s->offsets[s->offx++];
if (!where) {
Py_INCREF(Py_None);
return Py_None;
}
return Py_BuildValue("i", where);
}
/**
*/
static PyObject * handleDbResult(rpmdbMatchIterator mi) {
PyObject * list, *o;
list = PyList_New(0);
/* XXX FIXME: unnecessary header mallocs are side effect here */
if (mi != NULL) {
while (rpmdbNextIterator(mi)) {
PyList_Append(list, o=PyInt_FromLong(rpmdbGetIteratorOffset(mi)));
Py_DECREF(o);
}
rpmdbFreeIterator(mi);
}
return list;
}
/**
*/
static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args) {
char * str;
if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_BASENAMES, str, 0));
}
/**
*/
static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args) {
char * str;
if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_NAME, str, 0));
}
/**
*/
static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args) {
char * str;
if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_PROVIDENAME, str, 0));
}
/**
*/
static rpmdbMIObject *
py_rpmdbInitIterator (rpmdbObject * s, PyObject * args) {
PyObject *index = NULL;
char *key = NULL;
int len = 0, tag = -1;
rpmdbMIObject * mio;
if (!PyArg_ParseTuple(args, "|Ozi", &index, &key, &len))
return NULL;
if (index == NULL)
tag = 0;
else if ((tag = tagNumFromPyObject (index)) == -1) {
PyErr_SetString(PyExc_TypeError, "unknown tag type");
return NULL;
}
mio = (rpmdbMIObject *) PyObject_NEW(rpmdbMIObject, &rpmdbMIType);
if (mio == NULL) {
PyErr_SetString(pyrpmError, "out of memory creating rpmdbMIObject");
return NULL;
}
mio->mi = rpmdbInitIterator(s->db, tag, key, len);
mio->db = s;
Py_INCREF (mio->db);
return mio;
}
/**
*/
static struct PyMethodDef rpmdbMethods[] = {
{"firstkey", (PyCFunction) rpmdbFirst, 1 },
{"nextkey", (PyCFunction) rpmdbNext, 1 },
{"findbyfile", (PyCFunction) rpmdbByFile, 1 },
{"findbyname", (PyCFunction) rpmdbByName, 1 },
{"findbyprovides", (PyCFunction) rpmdbByProvides, 1 },
{"match", (PyCFunction) py_rpmdbInitIterator, 1 },
{NULL, NULL} /* sentinel */
};
/**
*/
static PyObject * rpmdbGetAttr(rpmdbObject * s, char * name) {
return Py_FindMethod(rpmdbMethods, (PyObject * ) s, name);
}
/**
*/
static void rpmdbDealloc(rpmdbObject * s) {
if (s->offsets) {
free(s->offsets);
}
if (s->db) {
rpmdbClose(s->db);
}
PyMem_DEL(s);
}
#ifndef DYINGSOON /* XXX OK, when? */
/**
*/
static int
rpmdbLength(rpmdbObject * s) {
int count = 0;
{ rpmdbMatchIterator mi;
/* RPMDBI_PACKAGES */
mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
while (rpmdbNextIterator(mi) != NULL)
count++;
rpmdbFreeIterator(mi);
}
return count;
}
/**
*/
static hdrObject *
rpmdbSubscript(rpmdbObject * s, PyObject * key) {
int offset;
hdrObject * ho;
Header h;
rpmdbMatchIterator mi;
if (!PyInt_Check(key)) {
PyErr_SetString(PyExc_TypeError, "integer expected");
return NULL;
}
offset = (int) PyInt_AsLong(key);
mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, &offset, sizeof(offset));
if (!(h = rpmdbNextIterator(mi))) {
rpmdbFreeIterator(mi);
PyErr_SetString(pyrpmError, "cannot read rpmdb entry");
return NULL;
}
ho = createHeaderObject(h);
headerFree(h, NULL);
return ho;
}
/**
*/
static PyMappingMethods rpmdbAsMapping = {
(inquiry) rpmdbLength, /* mp_length */
(binaryfunc) rpmdbSubscript, /* mp_subscript */
(objobjargproc)0, /* mp_ass_subscript */
};
#endif
/**
*/
PyTypeObject rpmdbType = {
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
"rpmdb", /* tp_name */
sizeof(rpmdbObject), /* tp_size */
0, /* tp_itemsize */
(destructor) rpmdbDealloc, /* tp_dealloc */
0, /* tp_print */
(getattrfunc) rpmdbGetAttr, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
#ifndef DYINGSOON
&rpmdbAsMapping, /* tp_as_mapping */
#else
0,
#endif
};
rpmdb dbFromDb(rpmdbObject * db) {
return db->db;
}
/**
*/
rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) {
rpmdbObject * o;
char * root = "";
int forWrite = 0;
if (!PyArg_ParseTuple(args, "|is", &forWrite, &root)) return NULL;
o = PyObject_NEW(rpmdbObject, &rpmdbType);
o->db = NULL;
o->offx = 0;
o->noffs = 0;
o->offsets = NULL;
if (rpmdbOpen(root, &o->db, forWrite ? O_RDWR | O_CREAT: O_RDONLY, 0644)) {
char * errmsg = "cannot open database in %s";
char * errstr = NULL;
int errsize;
Py_DECREF(o);
/* PyErr_SetString should take varargs... */
errsize = strlen(errmsg) + *root == '\0' ? 15 /* "/var/lib/rpm" */ : strlen(root);
errstr = alloca(errsize);
snprintf(errstr, errsize, errmsg, *root == '\0' ? "/var/lib/rpm" : root);
PyErr_SetString(pyrpmError, errstr);
return NULL;
}
return o;
}
/**
*/
PyObject * rebuildDB (PyObject * self, PyObject * args) {
char * root = "";
if (!PyArg_ParseTuple(args, "s", &root)) return NULL;
return Py_BuildValue("i", rpmdbRebuild(root));
}
/*@}*/