1078 lines
24 KiB
C
1078 lines
24 KiB
C
/** \ingroup py_c
|
|
* \file python/header-py.c
|
|
*/
|
|
|
|
#include "system.h"
|
|
|
|
#include "rpmio_internal.h"
|
|
#include "rpmcli.h" /* XXX for rpmCheckSig */
|
|
|
|
#include "legacy.h"
|
|
#include "misc.h"
|
|
#include "header_internal.h"
|
|
|
|
#include "rpmts.h" /* XXX rpmtsCreate/rpmtsFree */
|
|
|
|
#include "header-py.h"
|
|
#include "rpmds-py.h"
|
|
#include "rpmfi-py.h"
|
|
|
|
#include "debug.h"
|
|
|
|
/** \ingroup python
|
|
* \class Rpm
|
|
* \brief START HERE / RPM base module for the Python API
|
|
*
|
|
* The rpm base module provides the main starting point for
|
|
* accessing RPM from Python. For most usage, call
|
|
* the TransactionSet method to get a transaction set (rpmts).
|
|
*
|
|
* For example:
|
|
* \code
|
|
* import rpm
|
|
*
|
|
* ts = rpm.TransactionSet()
|
|
* \endcode
|
|
*
|
|
* The transaction set will open the RPM database as needed, so
|
|
* in most cases, you do not need to explicitly open the
|
|
* database. The transaction set is the workhorse of RPM.
|
|
*
|
|
* You can open another RPM database, such as one that holds
|
|
* all packages for a given Linux distribution, to provide
|
|
* packages used to solve dependencies. To do this, use
|
|
* the following code:
|
|
*
|
|
* \code
|
|
* rpm.addMacro('_dbpath', '/path/to/alternate/database')
|
|
* solvets = rpm.TransactionSet()
|
|
* solvets.openDB()
|
|
* rpm.delMacro('_dbpath')
|
|
*
|
|
* # Open default database
|
|
* ts = rpm.TransactionSet()
|
|
* \endcode
|
|
*
|
|
* This code gives you access to two RPM databases through
|
|
* two transaction sets (rpmts): ts is a transaction set
|
|
* associated with the default RPM database and solvets
|
|
* is a transaction set tied to an alternate database, which
|
|
* is very useful for resolving dependencies.
|
|
*
|
|
* The rpm methods used here are:
|
|
*
|
|
* - addMacro(macro, value)
|
|
* @param macro Name of macro to add
|
|
* @param value Value for the macro
|
|
*
|
|
* - delMacro(macro)
|
|
* @param macro Name of macro to delete
|
|
*
|
|
*/
|
|
|
|
/** \ingroup python
|
|
* \class Rpmhdr
|
|
* \brief A python header object represents an RPM package header.
|
|
*
|
|
* All RPM packages have headers that provide metadata for the package.
|
|
* Header objects can be returned by database queries or loaded from a
|
|
* binary package on disk.
|
|
*
|
|
* The ts.hdrFromFdno() function returns the package header from a
|
|
* package on disk, verifying package signatures and digests of the
|
|
* package while reading.
|
|
*
|
|
* Note: The older method rpm.headerFromPackage() which has been replaced
|
|
* by ts.hdrFromFdno() used to return a (hdr, isSource) tuple.
|
|
*
|
|
* If you need to distinguish source/binary headers, do:
|
|
* \code
|
|
* import os, rpm
|
|
*
|
|
* ts = rpm.TranssactionSet()
|
|
* fdno = os.open("/tmp/foo-1.0-1.i386.rpm", os.O_RDONLY)
|
|
* hdr = ts.hdrFromFdno(fdno)
|
|
* os.close(fdno)
|
|
* if hdr[rpm.RPMTAG_SOURCEPACKAGE]:
|
|
* print "header is from a source package"
|
|
* else:
|
|
* print "header is from a binary package"
|
|
* \endcode
|
|
*
|
|
* The Python interface to the header data is quite elegant. It
|
|
* presents the data in a dictionary form. We'll take the header we
|
|
* just loaded and access the data within it:
|
|
* \code
|
|
* print hdr[rpm.RPMTAG_NAME]
|
|
* print hdr[rpm.RPMTAG_VERSION]
|
|
* print hdr[rpm.RPMTAG_RELEASE]
|
|
* \endcode
|
|
* in the case of our "foo-1.0-1.i386.rpm" package, this code would
|
|
* output:
|
|
\verbatim
|
|
foo
|
|
1.0
|
|
1
|
|
\endverbatim
|
|
*
|
|
* You make also access the header data by string name:
|
|
* \code
|
|
* print hdr['name']
|
|
* print hdr['version']
|
|
* print hdr['release']
|
|
* \endcode
|
|
*
|
|
* This method of access is a teensy bit slower because the name must be
|
|
* translated into the tag number dynamically. You also must make sure
|
|
* the strings in header lookups don't get translated, or the lookups
|
|
* will fail.
|
|
*/
|
|
|
|
/** \ingroup python
|
|
* \name Class: rpm.hdr
|
|
*/
|
|
/*@{*/
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
struct hdrObject_s {
|
|
PyObject_HEAD
|
|
Header h;
|
|
char ** md5list;
|
|
char ** fileList;
|
|
char ** linkList;
|
|
int_32 * fileSizes;
|
|
int_32 * mtimes;
|
|
int_32 * uids, * gids; /* XXX these tags are not used anymore */
|
|
unsigned short * rdevs;
|
|
unsigned short * modes;
|
|
} ;
|
|
|
|
/*@unused@*/ static inline Header headerAllocated(Header h)
|
|
/*@modifies h @*/
|
|
{
|
|
h->flags |= HEADERFLAG_ALLOCATED;
|
|
return 0;
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
static PyObject * hdrKeyList(hdrObject * s)
|
|
/*@*/
|
|
{
|
|
PyObject * list, *o;
|
|
HeaderIterator hi;
|
|
int tag, type;
|
|
|
|
list = PyList_New(0);
|
|
|
|
hi = headerInitIterator(s->h);
|
|
while (headerNextIterator(hi, &tag, &type, NULL, NULL)) {
|
|
if (tag == HEADER_I18NTABLE) continue;
|
|
|
|
switch (type) {
|
|
case RPM_BIN_TYPE:
|
|
case RPM_INT32_TYPE:
|
|
case RPM_CHAR_TYPE:
|
|
case RPM_INT8_TYPE:
|
|
case RPM_INT16_TYPE:
|
|
case RPM_STRING_ARRAY_TYPE:
|
|
case RPM_STRING_TYPE:
|
|
PyList_Append(list, o=PyInt_FromLong(tag));
|
|
Py_DECREF(o);
|
|
}
|
|
}
|
|
headerFreeIterator(hi);
|
|
|
|
return list;
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords)
|
|
/*@*/
|
|
{
|
|
char * buf;
|
|
PyObject * rc;
|
|
int len, legacy = 0;
|
|
Header h;
|
|
static char *kwlist[] = { "legacyHeader", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
|
|
return NULL;
|
|
|
|
h = headerLink(s->h);
|
|
/* XXX this legacy switch is a hack, needs to be removed. */
|
|
if (legacy) {
|
|
h = headerCopy(s->h); /* XXX strip region tags, etc */
|
|
headerFree(s->h);
|
|
}
|
|
len = headerSizeof(h, 0);
|
|
buf = headerUnload(h);
|
|
h = headerFree(h);
|
|
|
|
if (buf == NULL || len == 0) {
|
|
PyErr_SetString(pyrpmError, "can't unload bad header\n");
|
|
return NULL;
|
|
}
|
|
|
|
rc = PyString_FromStringAndSize(buf, len);
|
|
buf = _free(buf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
static PyObject * hdrExpandFilelist(hdrObject * s)
|
|
/*@*/
|
|
{
|
|
expandFilelist (s->h);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
static PyObject * hdrCompressFilelist(hdrObject * s)
|
|
/*@*/
|
|
{
|
|
compressFilelist (s->h);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
/* make a header with _all_ the tags we need */
|
|
/** \ingroup py_c
|
|
*/
|
|
static void mungeFilelist(Header h)
|
|
/*@*/
|
|
{
|
|
const char ** fileNames = NULL;
|
|
int count = 0;
|
|
|
|
if (!headerIsEntry (h, RPMTAG_BASENAMES)
|
|
|| !headerIsEntry (h, RPMTAG_DIRNAMES)
|
|
|| !headerIsEntry (h, RPMTAG_DIRINDEXES))
|
|
compressFilelist(h);
|
|
|
|
rpmfiBuildFNames(h, RPMTAG_BASENAMES, &fileNames, &count);
|
|
|
|
if (fileNames == NULL || count <= 0)
|
|
return;
|
|
|
|
/* XXX Legacy tag needs to go away. */
|
|
headerAddEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
|
|
fileNames, count);
|
|
|
|
fileNames = _free(fileNames);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static PyObject * rhnUnload(hdrObject * s)
|
|
/*@*/
|
|
{
|
|
int len;
|
|
char * uh;
|
|
PyObject * rc;
|
|
Header h;
|
|
|
|
h = headerLink(s->h);
|
|
|
|
/* Retrofit a RHNPlatform: tag. */
|
|
if (!headerIsEntry(h, RPMTAG_RHNPLATFORM)) {
|
|
const char * arch;
|
|
int_32 at;
|
|
if (headerGetEntry(h, RPMTAG_ARCH, &at, (void **)&arch, NULL))
|
|
headerAddEntry(h, RPMTAG_RHNPLATFORM, at, arch, 1);
|
|
}
|
|
|
|
/* Legacy headers are forced into immutable region. */
|
|
if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
|
|
Header nh = headerReload(h, RPMTAG_HEADERIMMUTABLE);
|
|
/* XXX Another unload/load cycle to "seal" the immutable region. */
|
|
uh = headerUnload(nh);
|
|
headerFree(nh);
|
|
h = headerLoad(uh);
|
|
headerAllocated(h);
|
|
}
|
|
|
|
/* All headers have SHA1 digest, compute and add if necessary. */
|
|
if (!headerIsEntry(h, RPMTAG_SHA1HEADER)) {
|
|
int_32 uht, uhc;
|
|
const char * digest;
|
|
size_t digestlen;
|
|
DIGEST_CTX ctx;
|
|
|
|
headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, (void **)&uh, &uhc);
|
|
|
|
ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
|
|
rpmDigestUpdate(ctx, uh, uhc);
|
|
rpmDigestFinal(ctx, (void **)&digest, &digestlen, 1);
|
|
|
|
headerAddEntry(h, RPMTAG_SHA1RHN, RPM_STRING_TYPE, digest, 1);
|
|
|
|
uh = headerFreeData(uh, uht);
|
|
digest = _free(digest);
|
|
}
|
|
|
|
len = headerSizeof(h, 0);
|
|
uh = headerUnload(h);
|
|
headerFree(h);
|
|
|
|
rc = PyString_FromStringAndSize(uh, len);
|
|
uh = _free(uh);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
static PyObject * hdrFullFilelist(hdrObject * s)
|
|
/*@*/
|
|
{
|
|
mungeFilelist (s->h);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
static PyObject * hdrSprintf(hdrObject * s, PyObject * args, PyObject * kwds)
|
|
/*@*/
|
|
{
|
|
char * fmt;
|
|
char * r;
|
|
errmsg_t err;
|
|
PyObject * result;
|
|
char * kwlist[] = {"format", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &fmt))
|
|
return NULL;
|
|
|
|
r = headerSprintf(s->h, fmt, rpmTagTable, rpmHeaderFormats, &err);
|
|
if (!r) {
|
|
PyErr_SetString(pyrpmError, err);
|
|
return NULL;
|
|
}
|
|
|
|
result = Py_BuildValue("s", r);
|
|
r = _free(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static int hdr_compare(hdrObject * a, hdrObject * b)
|
|
/*@*/
|
|
{
|
|
return rpmVersionCompare(a->h, b->h);
|
|
}
|
|
|
|
static long hdr_hash(PyObject * h)
|
|
{
|
|
return (long) h;
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
/*@unchecked@*/ /*@observer@*/
|
|
static struct PyMethodDef hdr_methods[] = {
|
|
{"keys", (PyCFunction) hdrKeyList, METH_NOARGS,
|
|
NULL },
|
|
{"unload", (PyCFunction) hdrUnload, METH_VARARGS|METH_KEYWORDS,
|
|
NULL },
|
|
{"expandFilelist", (PyCFunction) hdrExpandFilelist,METH_NOARGS,
|
|
NULL },
|
|
{"compressFilelist",(PyCFunction) hdrCompressFilelist,METH_NOARGS,
|
|
NULL },
|
|
{"fullFilelist", (PyCFunction) hdrFullFilelist, METH_NOARGS,
|
|
NULL },
|
|
{"rhnUnload", (PyCFunction) rhnUnload, METH_NOARGS,
|
|
NULL },
|
|
{"sprintf", (PyCFunction) hdrSprintf, METH_VARARGS|METH_KEYWORDS,
|
|
NULL },
|
|
|
|
{"dsOfHeader", (PyCFunction)hdr_dsOfHeader, METH_NOARGS,
|
|
NULL},
|
|
{"dsFromHeader", (PyCFunction)hdr_dsFromHeader, METH_VARARGS|METH_KEYWORDS,
|
|
NULL},
|
|
{"fiFromHeader", (PyCFunction)hdr_fiFromHeader, METH_VARARGS|METH_KEYWORDS,
|
|
NULL},
|
|
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static PyObject * hdr_getattro(PyObject * o, PyObject * n)
|
|
/*@*/
|
|
{
|
|
return PyObject_GenericGetAttr(o, n);
|
|
}
|
|
|
|
static int hdr_setattro(PyObject * o, PyObject * n, PyObject * v)
|
|
/*@*/
|
|
{
|
|
return PyObject_GenericSetAttr(o, n, v);
|
|
}
|
|
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
static void hdr_dealloc(hdrObject * s)
|
|
/*@*/
|
|
{
|
|
if (s->h) headerFree(s->h);
|
|
s->md5list = _free(s->md5list);
|
|
s->fileList = _free(s->fileList);
|
|
s->linkList = _free(s->linkList);
|
|
PyObject_Del(s);
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
long tagNumFromPyObject (PyObject *item)
|
|
{
|
|
char * str;
|
|
int i;
|
|
|
|
if (PyInt_Check(item)) {
|
|
return PyInt_AsLong(item);
|
|
} else if (PyString_Check(item)) {
|
|
str = PyString_AsString(item);
|
|
for (i = 0; i < rpmTagTableSize; i++)
|
|
if (!xstrcasecmp(rpmTagTable[i].name + 7, str)) break;
|
|
if (i < rpmTagTableSize) return rpmTagTable[i].val;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
static PyObject * hdr_subscript(hdrObject * s, PyObject * item)
|
|
/*@*/
|
|
{
|
|
int type, count, i, tag = -1;
|
|
void * data;
|
|
PyObject * o, * metao;
|
|
char ** stringArray;
|
|
int forceArray = 0;
|
|
int freeData = 0;
|
|
char * str;
|
|
struct headerSprintfExtension_s * ext = NULL;
|
|
const struct headerSprintfExtension_s * extensions = rpmHeaderFormats;
|
|
|
|
if (PyCObject_Check (item))
|
|
ext = PyCObject_AsVoidPtr(item);
|
|
else
|
|
tag = tagNumFromPyObject (item);
|
|
if (tag == -1 && PyString_Check(item)) {
|
|
/* if we still don't have the tag, go looking for the header
|
|
extensions */
|
|
str = PyString_AsString(item);
|
|
while (extensions->name) {
|
|
if (extensions->type == HEADER_EXT_TAG
|
|
&& !xstrcasecmp(extensions->name + 7, str)) {
|
|
ext = extensions;
|
|
}
|
|
extensions++;
|
|
}
|
|
}
|
|
|
|
/* Retrieve data from extension or header. */
|
|
if (ext) {
|
|
ext->u.tagFunction(s->h, &type, (const void **) &data, &count, &freeData);
|
|
} else {
|
|
if (tag == -1) {
|
|
PyErr_SetString(PyExc_KeyError, "unknown header tag");
|
|
return NULL;
|
|
}
|
|
|
|
if (!rpmHeaderGetEntry(s->h, tag, &type, &data, &count)) {
|
|
switch (tag) {
|
|
case RPMTAG_EPOCH:
|
|
case RPMTAG_NAME:
|
|
case RPMTAG_VERSION:
|
|
case RPMTAG_RELEASE:
|
|
case RPMTAG_ARCH:
|
|
case RPMTAG_OS:
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
break;
|
|
default:
|
|
return PyList_New(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (tag) {
|
|
case RPMTAG_OLDFILENAMES:
|
|
case RPMTAG_FILESIZES:
|
|
case RPMTAG_FILESTATES:
|
|
case RPMTAG_FILEMODES:
|
|
case RPMTAG_FILEUIDS:
|
|
case RPMTAG_FILEGIDS:
|
|
case RPMTAG_FILERDEVS:
|
|
case RPMTAG_FILEMTIMES:
|
|
case RPMTAG_FILEMD5S:
|
|
case RPMTAG_FILELINKTOS:
|
|
case RPMTAG_FILEFLAGS:
|
|
case RPMTAG_ROOT:
|
|
case RPMTAG_FILEUSERNAME:
|
|
case RPMTAG_FILEGROUPNAME:
|
|
case RPMTAG_REQUIRENAME:
|
|
case RPMTAG_REQUIREFLAGS:
|
|
case RPMTAG_REQUIREVERSION:
|
|
case RPMTAG_PROVIDENAME:
|
|
case RPMTAG_PROVIDEFLAGS:
|
|
case RPMTAG_PROVIDEVERSION:
|
|
case RPMTAG_OBSOLETENAME:
|
|
case RPMTAG_OBSOLETEFLAGS:
|
|
case RPMTAG_OBSOLETEVERSION:
|
|
case RPMTAG_CONFLICTNAME:
|
|
case RPMTAG_CONFLICTFLAGS:
|
|
case RPMTAG_CONFLICTVERSION:
|
|
case RPMTAG_CHANGELOGTIME:
|
|
case RPMTAG_FILEVERIFYFLAGS:
|
|
forceArray = 1;
|
|
break;
|
|
case RPMTAG_SUMMARY:
|
|
case RPMTAG_GROUP:
|
|
case RPMTAG_DESCRIPTION:
|
|
freeData = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (type) {
|
|
case RPM_BIN_TYPE:
|
|
o = PyString_FromStringAndSize(data, count);
|
|
break;
|
|
|
|
case RPM_INT32_TYPE:
|
|
if (count != 1 || forceArray) {
|
|
metao = PyList_New(0);
|
|
for (i = 0; i < count; i++) {
|
|
o = PyInt_FromLong(((int *) data)[i]);
|
|
PyList_Append(metao, o);
|
|
Py_DECREF(o);
|
|
}
|
|
o = metao;
|
|
} else {
|
|
o = PyInt_FromLong(*((int *) data));
|
|
}
|
|
break;
|
|
|
|
case RPM_CHAR_TYPE:
|
|
case RPM_INT8_TYPE:
|
|
if (count != 1 || forceArray) {
|
|
metao = PyList_New(0);
|
|
for (i = 0; i < count; i++) {
|
|
o = PyInt_FromLong(((char *) data)[i]);
|
|
PyList_Append(metao, o);
|
|
Py_DECREF(o);
|
|
}
|
|
o = metao;
|
|
} else {
|
|
o = PyInt_FromLong(*((char *) data));
|
|
}
|
|
break;
|
|
|
|
case RPM_INT16_TYPE:
|
|
if (count != 1 || forceArray) {
|
|
metao = PyList_New(0);
|
|
for (i = 0; i < count; i++) {
|
|
o = PyInt_FromLong(((short *) data)[i]);
|
|
PyList_Append(metao, o);
|
|
Py_DECREF(o);
|
|
}
|
|
o = metao;
|
|
} else {
|
|
o = PyInt_FromLong(*((short *) data));
|
|
}
|
|
break;
|
|
|
|
case RPM_STRING_ARRAY_TYPE:
|
|
stringArray = data;
|
|
|
|
metao = PyList_New(0);
|
|
for (i = 0; i < count; i++) {
|
|
o = PyString_FromString(stringArray[i]);
|
|
PyList_Append(metao, o);
|
|
Py_DECREF(o);
|
|
}
|
|
free (stringArray);
|
|
o = metao;
|
|
break;
|
|
|
|
case RPM_STRING_TYPE:
|
|
if (count != 1 || forceArray) {
|
|
stringArray = data;
|
|
|
|
metao = PyList_New(0);
|
|
for (i=0; i < count; i++) {
|
|
o = PyString_FromString(stringArray[i]);
|
|
PyList_Append(metao, o);
|
|
Py_DECREF(o);
|
|
}
|
|
o = metao;
|
|
} else {
|
|
o = PyString_FromString(data);
|
|
if (freeData)
|
|
free (data);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
PyErr_SetString(PyExc_TypeError, "unsupported type in header");
|
|
return NULL;
|
|
}
|
|
|
|
return o;
|
|
}
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
/*@unchecked@*/ /*@observer@*/
|
|
static PyMappingMethods hdr_as_mapping = {
|
|
(inquiry) 0, /* mp_length */
|
|
(binaryfunc) hdr_subscript, /* mp_subscript */
|
|
(objobjargproc)0, /* mp_ass_subscript */
|
|
};
|
|
|
|
/**
|
|
*/
|
|
static char hdr_doc[] =
|
|
"";
|
|
|
|
/** \ingroup py_c
|
|
*/
|
|
/*@unchecked@*/ /*@observer@*/
|
|
PyTypeObject hdr_Type = {
|
|
PyObject_HEAD_INIT(&PyType_Type)
|
|
0, /* ob_size */
|
|
"rpm.hdr", /* tp_name */
|
|
sizeof(hdrObject), /* tp_size */
|
|
0, /* tp_itemsize */
|
|
(destructor) hdr_dealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
(getattrfunc) 0, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
(cmpfunc) hdr_compare, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
&hdr_as_mapping, /* tp_as_mapping */
|
|
hdr_hash, /* tp_hash */
|
|
0, /* tp_call */
|
|
0, /* tp_str */
|
|
(getattrofunc) hdr_getattro, /* tp_getattro */
|
|
(setattrofunc) hdr_setattro, /* tp_setattro */
|
|
0, /* tp_as_buffer */
|
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
hdr_doc, /* tp_doc */
|
|
#if Py_TPFLAGS_HAVE_ITER
|
|
0, /* tp_traverse */
|
|
0, /* tp_clear */
|
|
0, /* tp_richcompare */
|
|
0, /* tp_weaklistoffset */
|
|
0, /* tp_iter */
|
|
0, /* tp_iternext */
|
|
hdr_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 */
|
|
#endif
|
|
};
|
|
|
|
hdrObject * hdr_Wrap(Header h)
|
|
{
|
|
hdrObject * hdr = PyObject_New(hdrObject, &hdr_Type);
|
|
hdr->h = headerLink(h);
|
|
hdr->fileList = hdr->linkList = hdr->md5list = NULL;
|
|
hdr->uids = hdr->gids = hdr->mtimes = hdr->fileSizes = NULL;
|
|
hdr->modes = hdr->rdevs = NULL;
|
|
return hdr;
|
|
}
|
|
|
|
Header hdrGetHeader(hdrObject * s)
|
|
{
|
|
return s->h;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * hdrLoad(PyObject * self, PyObject * args, PyObject * kwds)
|
|
{
|
|
hdrObject * hdr;
|
|
char * copy = NULL;
|
|
char * obj;
|
|
Header h;
|
|
int len;
|
|
char * kwlist[] = {"headers", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &obj, &len))
|
|
return NULL;
|
|
|
|
/* malloc is needed to avoid surprises from data swab in headerLoad(). */
|
|
copy = malloc(len);
|
|
if (copy == NULL) {
|
|
PyErr_SetString(pyrpmError, "out of memory");
|
|
return NULL;
|
|
}
|
|
memcpy (copy, obj, len);
|
|
|
|
h = headerLoad(copy);
|
|
if (!h) {
|
|
PyErr_SetString(pyrpmError, "bad header");
|
|
return NULL;
|
|
}
|
|
headerAllocated(h);
|
|
compressFilelist (h);
|
|
providePackageNVR (h);
|
|
|
|
hdr = hdr_Wrap(h);
|
|
h = headerFree(h); /* XXX ref held by hdr */
|
|
|
|
return (PyObject *) hdr;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * rhnLoad(PyObject * self, PyObject * args, PyObject * kwds)
|
|
{
|
|
char * obj, * copy=NULL;
|
|
Header h;
|
|
int len;
|
|
char * kwlist[] = {"headers", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &obj, &len))
|
|
return NULL;
|
|
|
|
/* malloc is needed to avoid surprises from data swab in headerLoad(). */
|
|
copy = malloc(len);
|
|
if (copy == NULL) {
|
|
PyErr_SetString(pyrpmError, "out of memory");
|
|
return NULL;
|
|
}
|
|
memcpy (copy, obj, len);
|
|
|
|
h = headerLoad(copy);
|
|
if (!h) {
|
|
PyErr_SetString(pyrpmError, "bad header");
|
|
return NULL;
|
|
}
|
|
headerAllocated(h);
|
|
|
|
/* XXX avoid the false OK's from rpmverifyDigest() with missing tags. */
|
|
if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
|
|
PyErr_SetString(pyrpmError, "bad header, not immutable");
|
|
headerFree(h);
|
|
return NULL;
|
|
}
|
|
|
|
/* XXX avoid the false OK's from rpmverifyDigest() with missing tags. */
|
|
if (!headerIsEntry(h, RPMTAG_SHA1HEADER)
|
|
&& !headerIsEntry(h, RPMTAG_SHA1RHN)) {
|
|
PyErr_SetString(pyrpmError, "bad header, no digest");
|
|
headerFree(h);
|
|
return NULL;
|
|
}
|
|
|
|
/* Retrofit a RHNPlatform: tag. */
|
|
if (!headerIsEntry(h, RPMTAG_RHNPLATFORM)) {
|
|
const char * arch;
|
|
int_32 at;
|
|
if (headerGetEntry(h, RPMTAG_ARCH, &at, (void **)&arch, NULL))
|
|
headerAddEntry(h, RPMTAG_RHNPLATFORM, at, arch, 1);
|
|
}
|
|
|
|
return (PyObject *) hdr_Wrap(h);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * rpmReadHeaders (FD_t fd)
|
|
{
|
|
PyObject * list;
|
|
Header h;
|
|
hdrObject * hdr;
|
|
|
|
if (!fd) {
|
|
PyErr_SetFromErrno(pyrpmError);
|
|
return NULL;
|
|
}
|
|
|
|
list = PyList_New(0);
|
|
Py_BEGIN_ALLOW_THREADS
|
|
h = headerRead(fd, HEADER_MAGIC_YES);
|
|
Py_END_ALLOW_THREADS
|
|
|
|
while (h) {
|
|
compressFilelist(h);
|
|
providePackageNVR(h);
|
|
hdr = hdr_Wrap(h);
|
|
if (PyList_Append(list, (PyObject *) hdr)) {
|
|
Py_DECREF(list);
|
|
Py_DECREF(hdr);
|
|
return NULL;
|
|
}
|
|
Py_DECREF(hdr);
|
|
|
|
h = headerFree(h); /* XXX ref held by hdr */
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
h = headerRead(fd, HEADER_MAGIC_YES);
|
|
Py_END_ALLOW_THREADS
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args, PyObject * kwds)
|
|
{
|
|
FD_t fd;
|
|
int fileno;
|
|
PyObject * list;
|
|
char * kwlist[] = {"fd", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &fileno))
|
|
return NULL;
|
|
|
|
fd = fdDup(fileno);
|
|
|
|
list = rpmReadHeaders (fd);
|
|
Fclose(fd);
|
|
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args, PyObject *kwds)
|
|
{
|
|
char * filespec;
|
|
FD_t fd;
|
|
PyObject * list;
|
|
char * kwlist[] = {"file", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &filespec))
|
|
return NULL;
|
|
|
|
fd = Fopen(filespec, "r.fdio");
|
|
|
|
if (!fd) {
|
|
PyErr_SetFromErrno(pyrpmError);
|
|
return NULL;
|
|
}
|
|
|
|
list = rpmReadHeaders (fd);
|
|
Fclose(fd);
|
|
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
* This assumes the order of list matches the order of the new headers, and
|
|
* throws an exception if that isn't true.
|
|
*/
|
|
int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag)
|
|
{
|
|
Header h;
|
|
HeaderIterator hi;
|
|
int_32 * newMatch;
|
|
int_32 * oldMatch;
|
|
hdrObject * hdr;
|
|
int count = 0;
|
|
int type, c, tag;
|
|
void * p;
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
h = headerRead(fd, HEADER_MAGIC_YES);
|
|
Py_END_ALLOW_THREADS
|
|
|
|
while (h) {
|
|
if (!headerGetEntry(h, matchTag, NULL, (void **) &newMatch, NULL)) {
|
|
PyErr_SetString(pyrpmError, "match tag missing in new header");
|
|
return 1;
|
|
}
|
|
|
|
hdr = (hdrObject *) PyList_GetItem(list, count++);
|
|
if (!hdr) return 1;
|
|
|
|
if (!headerGetEntry(hdr->h, matchTag, NULL, (void **) &oldMatch, NULL)) {
|
|
PyErr_SetString(pyrpmError, "match tag missing in new header");
|
|
return 1;
|
|
}
|
|
|
|
if (*newMatch != *oldMatch) {
|
|
PyErr_SetString(pyrpmError, "match tag mismatch");
|
|
return 1;
|
|
}
|
|
|
|
hdr->md5list = _free(hdr->md5list);
|
|
hdr->fileList = _free(hdr->fileList);
|
|
hdr->linkList = _free(hdr->linkList);
|
|
|
|
for (hi = headerInitIterator(h);
|
|
headerNextIterator(hi, &tag, &type, (void *) &p, &c);
|
|
p = headerFreeData(p, type))
|
|
{
|
|
/* could be dupes */
|
|
headerRemoveEntry(hdr->h, tag);
|
|
headerAddEntry(hdr->h, tag, type, p, c);
|
|
}
|
|
|
|
headerFreeIterator(hi);
|
|
h = headerFree(h);
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
h = headerRead(fd, HEADER_MAGIC_YES);
|
|
Py_END_ALLOW_THREADS
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
PyObject *
|
|
rpmMergeHeadersFromFD(PyObject * self, PyObject * args, PyObject * kwds)
|
|
{
|
|
FD_t fd;
|
|
int fileno;
|
|
PyObject * list;
|
|
int rc;
|
|
int matchTag;
|
|
char * kwlist[] = {"list", "fd", "matchTag", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oii", kwlist, &list,
|
|
&fileno, &matchTag))
|
|
return NULL;
|
|
|
|
if (!PyList_Check(list)) {
|
|
PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
|
|
return NULL;
|
|
}
|
|
|
|
fd = fdDup(fileno);
|
|
|
|
rc = rpmMergeHeaders (list, fd, matchTag);
|
|
Fclose(fd);
|
|
|
|
if (rc) {
|
|
return NULL;
|
|
}
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject *
|
|
rpmSingleHeaderFromFD(PyObject * self, PyObject * args, PyObject * kwds)
|
|
{
|
|
FD_t fd;
|
|
int fileno;
|
|
off_t offset;
|
|
PyObject * tuple;
|
|
Header h;
|
|
char * kwlist[] = {"fd", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &fileno))
|
|
return NULL;
|
|
|
|
offset = lseek(fileno, 0, SEEK_CUR);
|
|
|
|
fd = fdDup(fileno);
|
|
|
|
if (!fd) {
|
|
PyErr_SetFromErrno(pyrpmError);
|
|
return NULL;
|
|
}
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
h = headerRead(fd, HEADER_MAGIC_YES);
|
|
Py_END_ALLOW_THREADS
|
|
|
|
Fclose(fd);
|
|
|
|
tuple = PyTuple_New(2);
|
|
|
|
if (h && tuple) {
|
|
PyTuple_SET_ITEM(tuple, 0, (PyObject *) hdr_Wrap(h));
|
|
PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(offset));
|
|
h = headerFree(h);
|
|
} else {
|
|
Py_INCREF(Py_None);
|
|
Py_INCREF(Py_None);
|
|
PyTuple_SET_ITEM(tuple, 0, Py_None);
|
|
PyTuple_SET_ITEM(tuple, 1, Py_None);
|
|
}
|
|
|
|
return tuple;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * versionCompare (PyObject * self, PyObject * args, PyObject * kwds)
|
|
{
|
|
hdrObject * h1, * h2;
|
|
char * kwlist[] = {"version0", "version1", NULL};
|
|
|
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!", kwlist, &hdr_Type,
|
|
&h1, &hdr_Type, &h2))
|
|
return NULL;
|
|
|
|
return Py_BuildValue("i", hdr_compare(h1, h2));
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static int compare_values(const char *str1, const char *str2)
|
|
{
|
|
if (!str1 && !str2)
|
|
return 0;
|
|
else if (str1 && !str2)
|
|
return 1;
|
|
else if (!str1 && str2)
|
|
return -1;
|
|
return rpmvercmp(str1, str2);
|
|
}
|
|
|
|
PyObject * labelCompare (PyObject * self, PyObject * args)
|
|
{
|
|
char *v1, *r1, *e1, *v2, *r2, *e2;
|
|
int rc;
|
|
|
|
if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
|
|
&e1, &v1, &r1, &e2, &v2, &r2))
|
|
return NULL;
|
|
|
|
rc = compare_values(e1, e2);
|
|
if (!rc) {
|
|
rc = compare_values(v1, v2);
|
|
if (!rc)
|
|
rc = compare_values(r1, r2);
|
|
}
|
|
return Py_BuildValue("i", rc);
|
|
}
|
|
|
|
/*@}*/
|