1117 lines
26 KiB
C
1117 lines
26 KiB
C
/** \ingroup python
|
|
* \file python/header-py.c
|
|
*/
|
|
|
|
#include "Python.h"
|
|
#include "rpmio_internal.h"
|
|
#include "rpmcli.h" /* XXX for rpmCheckSig */
|
|
#include "depends.h" /* XXX for ts->rpmdb */
|
|
#include "legacy.h"
|
|
#include "misc.h"
|
|
#include "header_internal.h"
|
|
|
|
#include "header-py.h"
|
|
|
|
/** \ingroup python
|
|
* \class header
|
|
* \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 headerFromPackage function loads the package header from a
|
|
* package on disk. It returns a tuple of a "isSource" flag and the
|
|
* header object. The "isSource" flag is set to 1 if the package
|
|
* header was read from a source rpm or to 0 if the package header was
|
|
* read from a binary rpm.
|
|
*
|
|
* For example:
|
|
* \code
|
|
* import os, rpm
|
|
*
|
|
* fd = os.open("/tmp/foo-1.0-1.i386.rpm", os.O_RDONLY)
|
|
* (header, isSource) = rpm.headerFromPackage(fd)
|
|
* fd.close()
|
|
* \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 header[rpm.RPMTAG_NAME]
|
|
* print header[rpm.RPMTAG_VERSION]
|
|
* print header[rpm.RPMTAG_RELEASE]
|
|
* \endcode
|
|
* in the case of our "foor-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 header['name']
|
|
* \endcode
|
|
* This method of access is a 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: header
|
|
*/
|
|
/*@{*/
|
|
|
|
/** \ingroup python
|
|
*/
|
|
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) {
|
|
h->flags |= HEADERFLAG_ALLOCATED;
|
|
return 0;
|
|
}
|
|
|
|
/** \ingroup python
|
|
*/
|
|
static PyObject * hdrKeyList(hdrObject * s, PyObject * args) {
|
|
PyObject * list, *o;
|
|
HeaderIterator iter;
|
|
int tag, type;
|
|
|
|
if (!PyArg_ParseTuple(args, "")) return NULL;
|
|
|
|
list = PyList_New(0);
|
|
|
|
iter = headerInitIterator(s->h);
|
|
while (headerNextIterator(iter, &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(iter);
|
|
|
|
return list;
|
|
}
|
|
|
|
/** \ingroup python
|
|
*/
|
|
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, "hdrUnload 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, "hdrUnload s->h");
|
|
}
|
|
len = headerSizeof(h, 0);
|
|
buf = headerUnload(h);
|
|
h = headerFree(h, "hdrUnload h");
|
|
|
|
if (buf == NULL || len == 0) {
|
|
PyErr_SetString(pyrpmError, "can't unload bad header\n");
|
|
return NULL;
|
|
}
|
|
|
|
rc = PyString_FromStringAndSize(buf, len);
|
|
free(buf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/** \ingroup python
|
|
* Returns a list of these tuples for each item that failed:
|
|
* (attr_name, correctValue, currentValue)
|
|
* It should be passed the file number to verify.
|
|
*/
|
|
static PyObject * hdrVerifyFile(hdrObject * s, PyObject * args) {
|
|
int fileNumber;
|
|
rpmVerifyAttrs verifyResult = 0;
|
|
PyObject * list, * tuple, * attrName;
|
|
int type, count;
|
|
struct stat sb;
|
|
char buf[2048];
|
|
int i;
|
|
time_t timeInt;
|
|
struct tm * timeStruct;
|
|
|
|
if (!PyInt_Check(args)) {
|
|
PyErr_SetString(PyExc_TypeError, "integer expected");
|
|
return NULL;
|
|
}
|
|
|
|
fileNumber = (int) PyInt_AsLong(args);
|
|
|
|
{ rpmTransactionSet ts;
|
|
int scareMem = 1;
|
|
TFI_t fi;
|
|
int rc;
|
|
|
|
ts = rpmtransCreateSet(NULL, NULL);
|
|
fi = fiNew(ts, NULL, s->h, RPMTAG_BASENAMES, scareMem);
|
|
fi = tfiInit(fi, fileNumber);
|
|
if (fi != NULL && tfiNext(fi) >= 0) {
|
|
/* XXX this routine might use callbacks intelligently. */
|
|
rc = rpmVerifyFile(ts, fi, &verifyResult, RPMVERIFY_NONE);
|
|
} else
|
|
rc = 1;
|
|
|
|
fi = fiFree(fi, 1);
|
|
rpmtransFree(ts);
|
|
|
|
if (rc) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
}
|
|
|
|
list = PyList_New(0);
|
|
|
|
if (!verifyResult) return list;
|
|
|
|
/* XXX Legacy tag needs to go away. */
|
|
if (!s->fileList) {
|
|
headerGetEntry(s->h, RPMTAG_OLDFILENAMES, &type, (void **) &s->fileList,
|
|
&count);
|
|
}
|
|
|
|
lstat(s->fileList[fileNumber], &sb);
|
|
|
|
if (verifyResult & RPMVERIFY_MD5) {
|
|
if (!s->md5list) {
|
|
headerGetEntry(s->h, RPMTAG_FILEMD5S, &type, (void **) &s->md5list,
|
|
&count);
|
|
}
|
|
|
|
if (domd5(s->fileList[fileNumber], buf, 1)) {
|
|
strcpy(buf, "00000000000000000000000000000000");
|
|
}
|
|
|
|
tuple = PyTuple_New(3);
|
|
attrName = PyString_FromString("checksum");
|
|
PyTuple_SetItem(tuple, 0, attrName);
|
|
PyTuple_SetItem(tuple, 1, PyString_FromString(s->md5list[fileNumber]));
|
|
PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
|
|
PyList_Append(list, tuple);
|
|
Py_DECREF(tuple);
|
|
}
|
|
|
|
if (verifyResult & RPMVERIFY_FILESIZE) {
|
|
if (!s->fileSizes) {
|
|
headerGetEntry(s->h, RPMTAG_FILESIZES, &type, (void **) &s->fileSizes,
|
|
&count);
|
|
|
|
}
|
|
|
|
tuple = PyTuple_New(3);
|
|
attrName = PyString_FromString("size");
|
|
PyTuple_SetItem(tuple, 0, attrName);
|
|
|
|
sprintf(buf, "%d", 100);
|
|
PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
|
|
sprintf(buf, "%ld", (long)sb.st_size);
|
|
PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
|
|
PyList_Append(list, tuple);
|
|
Py_DECREF(tuple);
|
|
}
|
|
|
|
if (verifyResult & RPMVERIFY_LINKTO) {
|
|
if (!s->linkList) {
|
|
headerGetEntry(s->h, RPMTAG_FILELINKTOS, &type, (void **) &s->linkList,
|
|
&count);
|
|
}
|
|
|
|
i = readlink(s->fileList[fileNumber], buf, sizeof(buf));
|
|
if (i <= 0)
|
|
strcpy(buf, "(unknown)");
|
|
else
|
|
buf[i] = '\0';
|
|
|
|
tuple = PyTuple_New(3);
|
|
attrName = PyString_FromString("link");
|
|
PyTuple_SetItem(tuple, 0, attrName);
|
|
PyTuple_SetItem(tuple, 1, PyString_FromString(s->linkList[fileNumber]));
|
|
PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
|
|
PyList_Append(list, tuple);
|
|
Py_DECREF(tuple);
|
|
}
|
|
|
|
if (verifyResult & RPMVERIFY_MTIME) {
|
|
if (!s->mtimes) {
|
|
headerGetEntry(s->h, RPMTAG_FILEMTIMES, &type, (void **) &s->mtimes,
|
|
&count);
|
|
}
|
|
|
|
tuple = PyTuple_New(3);
|
|
attrName = PyString_FromString("time");
|
|
PyTuple_SetItem(tuple, 0, attrName);
|
|
|
|
timeInt = sb.st_mtime;
|
|
timeStruct = localtime(&timeInt);
|
|
strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
|
|
PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
|
|
|
|
timeInt = s->mtimes[fileNumber];
|
|
timeStruct = localtime(&timeInt);
|
|
strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
|
|
|
|
PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
|
|
|
|
PyList_Append(list, tuple);
|
|
Py_DECREF(tuple);
|
|
}
|
|
|
|
if (verifyResult & RPMVERIFY_RDEV) {
|
|
if (!s->rdevs) {
|
|
headerGetEntry(s->h, RPMTAG_FILERDEVS, &type, (void **) &s->rdevs,
|
|
&count);
|
|
}
|
|
|
|
tuple = PyTuple_New(3);
|
|
attrName = PyString_FromString("device");
|
|
|
|
PyTuple_SetItem(tuple, 0, attrName);
|
|
sprintf(buf, "0x%-4x", s->rdevs[fileNumber]);
|
|
PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
|
|
sprintf(buf, "0x%-4x", (unsigned int) sb.st_rdev);
|
|
PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
|
|
PyList_Append(list, tuple);
|
|
Py_DECREF(tuple);
|
|
}
|
|
|
|
/*
|
|
* RPMVERIFY_USER and RPM_VERIFY_GROUP are handled wrong here, but rpmlib.a
|
|
* doesn't do these correctly either. At least this is consistent.
|
|
*
|
|
* XXX Consistent? rpmlib.a verifies user/group quite well, thank you.
|
|
* XXX The code below does nothing useful. FILEUSERNAME needs to be
|
|
* XXX retrieved and looked up.
|
|
*/
|
|
if (verifyResult & RPMVERIFY_USER) {
|
|
if (!s->uids) {
|
|
headerGetEntry(s->h, RPMTAG_FILEUIDS, &type, (void **) &s->uids,
|
|
&count);
|
|
}
|
|
|
|
tuple = PyTuple_New(3);
|
|
attrName = PyString_FromString("uid");
|
|
PyTuple_SetItem(tuple, 0, attrName);
|
|
sprintf(buf, "%d", s->uids[fileNumber]);
|
|
PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
|
|
sprintf(buf, "%d", sb.st_uid);
|
|
PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
|
|
PyList_Append(list, tuple);
|
|
Py_DECREF(tuple);
|
|
}
|
|
|
|
/*
|
|
* XXX The code below does nothing useful. FILEGROUPNAME needs to be
|
|
* XXX retrieved and looked up.
|
|
*/
|
|
if (verifyResult & RPMVERIFY_GROUP) {
|
|
if (!s->gids) {
|
|
headerGetEntry(s->h, RPMTAG_FILEGIDS, &type, (void **) &s->gids,
|
|
&count);
|
|
}
|
|
|
|
tuple = PyTuple_New(3);
|
|
attrName = PyString_FromString("gid");
|
|
PyTuple_SetItem(tuple, 0, attrName);
|
|
sprintf(buf, "%d", s->gids[fileNumber]);
|
|
PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
|
|
sprintf(buf, "%d", sb.st_gid);
|
|
PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
|
|
PyList_Append(list, tuple);
|
|
Py_DECREF(tuple);
|
|
}
|
|
|
|
if (verifyResult & RPMVERIFY_MODE) {
|
|
if (!s->modes) {
|
|
headerGetEntry(s->h, RPMTAG_FILEMODES, &type, (void **) &s->modes,
|
|
&count);
|
|
}
|
|
|
|
tuple = PyTuple_New(3);
|
|
attrName = PyString_FromString("permissions");
|
|
PyTuple_SetItem(tuple, 0, attrName);
|
|
sprintf(buf, "0%-4o", s->modes[fileNumber]);
|
|
PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
|
|
sprintf(buf, "0%-4o", sb.st_mode);
|
|
PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
|
|
PyList_Append(list, tuple);
|
|
Py_DECREF(tuple);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
/** \ingroup python
|
|
*/
|
|
static PyObject * hdrExpandFilelist(hdrObject * s, PyObject * args) {
|
|
expandFilelist (s->h);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
/** \ingroup python
|
|
*/
|
|
static PyObject * hdrCompressFilelist(hdrObject * s, PyObject * args) {
|
|
compressFilelist (s->h);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
/* make a header with _all_ the tags we need */
|
|
/** \ingroup python
|
|
*/
|
|
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);
|
|
|
|
rpmBuildFileList(h, &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);
|
|
|
|
free((void *)fileNames);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
static PyObject * rhnUnload(hdrObject * s, PyObject * args) {
|
|
int len;
|
|
char * uh;
|
|
PyObject * rc;
|
|
Header h;
|
|
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return NULL;
|
|
|
|
h = headerLink(s->h, "rhnUnload 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, "rhnUnload 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, "rhnUnload h");
|
|
|
|
rc = PyString_FromStringAndSize(uh, len);
|
|
free(uh);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/** \ingroup python
|
|
*/
|
|
static PyObject * hdrFullFilelist(hdrObject * s, PyObject * args) {
|
|
if (!PyArg_ParseTuple(args, ""))
|
|
return NULL;
|
|
|
|
mungeFilelist (s->h);
|
|
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
/** \ingroup python
|
|
*/
|
|
static PyObject * hdrSprintf(hdrObject * s, PyObject * args) {
|
|
char * fmt;
|
|
char * r;
|
|
errmsg_t err;
|
|
PyObject * result;
|
|
|
|
if (!PyArg_ParseTuple(args, "s", &fmt))
|
|
return NULL;
|
|
|
|
r = headerSprintf(s->h, fmt, rpmTagTable, rpmHeaderFormats, &err);
|
|
if (!r) {
|
|
PyErr_SetString(pyrpmError, err);
|
|
return NULL;
|
|
}
|
|
|
|
result = Py_BuildValue("s", r);
|
|
free(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/** \ingroup python
|
|
*/
|
|
static struct PyMethodDef hdrMethods[] = {
|
|
{"keys", (PyCFunction) hdrKeyList, 1 },
|
|
{"unload", (PyCFunction) hdrUnload, METH_VARARGS|METH_KEYWORDS },
|
|
{"verifyFile", (PyCFunction) hdrVerifyFile, 1 },
|
|
{"expandFilelist", (PyCFunction) hdrExpandFilelist, 1 },
|
|
{"compressFilelist", (PyCFunction) hdrCompressFilelist, 1 },
|
|
{"fullFilelist", (PyCFunction) hdrFullFilelist, 1 },
|
|
{"rhnUnload", (PyCFunction) rhnUnload, METH_VARARGS },
|
|
{"sprintf", (PyCFunction) hdrSprintf, METH_VARARGS },
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
/** \ingroup python
|
|
*/
|
|
static PyObject * hdrGetAttr(hdrObject * s, char * name) {
|
|
return Py_FindMethod(hdrMethods, (PyObject * ) s, name);
|
|
}
|
|
|
|
/** \ingroup python
|
|
*/
|
|
static void hdrDealloc(hdrObject * s) {
|
|
if (s->h) headerFree(s->h, "hdrDealloc s->h");
|
|
if (s->md5list) free(s->md5list);
|
|
if (s->fileList) free(s->fileList);
|
|
if (s->linkList) free(s->linkList);
|
|
PyMem_DEL(s);
|
|
}
|
|
|
|
/** \ingroup python
|
|
*/
|
|
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 python
|
|
*/
|
|
static PyObject * hdrSubscript(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)) {
|
|
(const struct headerSprintfExtension *) ext = extensions;
|
|
}
|
|
extensions++;
|
|
}
|
|
}
|
|
|
|
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)) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
}
|
|
|
|
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:
|
|
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 python
|
|
*/
|
|
static PyMappingMethods hdrAsMapping = {
|
|
(inquiry) 0, /* mp_length */
|
|
(binaryfunc) hdrSubscript, /* mp_subscript */
|
|
(objobjargproc)0, /* mp_ass_subscript */
|
|
};
|
|
|
|
/** \ingroup python
|
|
*/
|
|
PyTypeObject hdrType = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0, /* ob_size */
|
|
"header", /* tp_name */
|
|
sizeof(hdrObject), /* tp_size */
|
|
0, /* tp_itemsize */
|
|
(destructor) hdrDealloc, /* tp_dealloc */
|
|
0, /* tp_print */
|
|
(getattrfunc) hdrGetAttr, /* tp_getattr */
|
|
0, /* tp_setattr */
|
|
0, /* tp_compare */
|
|
0, /* tp_repr */
|
|
0, /* tp_as_number */
|
|
0, /* tp_as_sequence */
|
|
&hdrAsMapping, /* tp_as_mapping */
|
|
};
|
|
|
|
hdrObject * createHeaderObject(Header h) {
|
|
hdrObject * ho;
|
|
|
|
ho = PyObject_NEW(hdrObject, &hdrType);
|
|
ho->h = headerLink(h, NULL);
|
|
ho->fileList = ho->linkList = ho->md5list = NULL;
|
|
ho->uids = ho->gids = ho->mtimes = ho->fileSizes = NULL;
|
|
ho->modes = ho->rdevs = NULL;
|
|
|
|
return ho;
|
|
}
|
|
|
|
Header hdrGetHeader(hdrObject * h) {
|
|
return h->h;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args) {
|
|
hdrObject * h;
|
|
Header header;
|
|
FD_t fd;
|
|
int rawFd;
|
|
int isSource = 0;
|
|
rpmRC rc;
|
|
|
|
if (!PyArg_ParseTuple(args, "i", &rawFd)) return NULL;
|
|
|
|
fd = fdDup(rawFd);
|
|
{ rpmTransactionSet ts;
|
|
ts = rpmtransCreateSet(NULL, NULL);
|
|
rc = rpmReadPackageFile(ts, fd, "rpmHeaderFromPackage", &header);
|
|
rpmtransFree(ts);
|
|
}
|
|
Fclose(fd);
|
|
|
|
switch (rc) {
|
|
case RPMRC_BADSIZE:
|
|
case RPMRC_OK:
|
|
h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
|
|
h->h = header;
|
|
h->fileList = h->linkList = h->md5list = NULL;
|
|
h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
|
|
h->modes = h->rdevs = NULL;
|
|
isSource = headerIsEntry(header, RPMTAG_SOURCEPACKAGE);
|
|
break;
|
|
|
|
case RPMRC_BADMAGIC:
|
|
Py_INCREF(Py_None);
|
|
h = (hdrObject *) Py_None;
|
|
break;
|
|
|
|
case RPMRC_FAIL:
|
|
case RPMRC_SHORTREAD:
|
|
default:
|
|
PyErr_SetString(pyrpmError, "error reading package");
|
|
return NULL;
|
|
}
|
|
|
|
return Py_BuildValue("(Ni)", h, isSource);
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * hdrLoad(PyObject * self, PyObject * args) {
|
|
char * obj, * copy=NULL;
|
|
Header hdr;
|
|
hdrObject * h;
|
|
int len;
|
|
|
|
if (!PyArg_ParseTuple(args, "s#", &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);
|
|
|
|
hdr = headerLoad(copy);
|
|
if (!hdr) {
|
|
PyErr_SetString(pyrpmError, "bad header");
|
|
return NULL;
|
|
}
|
|
headerAllocated(hdr);
|
|
compressFilelist (hdr);
|
|
providePackageNVR (hdr);
|
|
|
|
h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
|
|
h->h = hdr;
|
|
h->fileList = h->linkList = h->md5list = NULL;
|
|
h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
|
|
h->modes = h->rdevs = NULL;
|
|
|
|
return (PyObject *) h;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * rhnLoad(PyObject * self, PyObject * args) {
|
|
char * obj, * copy=NULL;
|
|
Header hdr;
|
|
hdrObject * h;
|
|
int len;
|
|
|
|
if (!PyArg_ParseTuple(args, "s#", &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);
|
|
|
|
hdr = headerLoad(copy);
|
|
if (!hdr) {
|
|
PyErr_SetString(pyrpmError, "bad header");
|
|
return NULL;
|
|
}
|
|
headerAllocated(hdr);
|
|
|
|
/* XXX avoid the false OK's from rpmverifyDigest() with missing tags. */
|
|
if (!headerIsEntry(hdr, RPMTAG_HEADERIMMUTABLE)) {
|
|
PyErr_SetString(pyrpmError, "bad header, not immutable");
|
|
headerFree(hdr, "rhnLoad hdr #1");
|
|
return NULL;
|
|
}
|
|
|
|
/* XXX avoid the false OK's from rpmverifyDigest() with missing tags. */
|
|
if (!headerIsEntry(hdr, RPMTAG_SHA1HEADER)
|
|
&& !headerIsEntry(hdr, RPMTAG_SHA1RHN)) {
|
|
PyErr_SetString(pyrpmError, "bad header, no digest");
|
|
headerFree(hdr, "rhnLoad hdr #2");
|
|
return NULL;
|
|
}
|
|
|
|
if (rpmVerifyDigest(hdr)) {
|
|
PyErr_SetString(pyrpmError, "bad header, digest check failed");
|
|
headerFree(hdr, "rhnLoad hdr #3");
|
|
return NULL;
|
|
}
|
|
|
|
/* Retrofit a RHNPlatform: tag. */
|
|
if (!headerIsEntry(hdr, RPMTAG_RHNPLATFORM)) {
|
|
const char * arch;
|
|
int_32 at;
|
|
if (headerGetEntry(hdr, RPMTAG_ARCH, &at, (void **)&arch, NULL))
|
|
headerAddEntry(hdr, RPMTAG_RHNPLATFORM, at, arch, 1);
|
|
}
|
|
|
|
h = createHeaderObject(hdr);
|
|
|
|
return (PyObject *) h;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * rpmReadHeaders (FD_t fd) {
|
|
PyObject * list;
|
|
Header header;
|
|
hdrObject * h;
|
|
|
|
if (!fd) {
|
|
PyErr_SetFromErrno(pyrpmError);
|
|
return NULL;
|
|
}
|
|
|
|
list = PyList_New(0);
|
|
Py_BEGIN_ALLOW_THREADS
|
|
header = headerRead(fd, HEADER_MAGIC_YES);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
while (header) {
|
|
compressFilelist (header);
|
|
providePackageNVR (header);
|
|
h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
|
|
h->h = header;
|
|
h->fileList = h->linkList = h->md5list = NULL;
|
|
h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
|
|
h->modes = h->rdevs = NULL;
|
|
if (PyList_Append(list, (PyObject *) h)) {
|
|
Py_DECREF(list);
|
|
Py_DECREF(h);
|
|
return NULL;
|
|
}
|
|
|
|
Py_DECREF(h);
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
header = headerRead(fd, HEADER_MAGIC_YES);
|
|
Py_END_ALLOW_THREADS
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args) {
|
|
FD_t fd;
|
|
int fileno;
|
|
PyObject * list;
|
|
|
|
if (!PyArg_ParseTuple(args, "i", &fileno)) return NULL;
|
|
fd = fdDup(fileno);
|
|
|
|
list = rpmReadHeaders (fd);
|
|
Fclose(fd);
|
|
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
*/
|
|
PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args) {
|
|
char * filespec;
|
|
FD_t fd;
|
|
PyObject * list;
|
|
|
|
if (!PyArg_ParseTuple(args, "s", &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 newH;
|
|
HeaderIterator iter;
|
|
int_32 * newMatch, * oldMatch;
|
|
hdrObject * ho;
|
|
int count = 0;
|
|
int type, c, tag;
|
|
void * p;
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
newH = headerRead(fd, HEADER_MAGIC_YES);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
while (newH) {
|
|
if (!headerGetEntry(newH, matchTag, NULL, (void **) &newMatch, NULL)) {
|
|
PyErr_SetString(pyrpmError, "match tag missing in new header");
|
|
return 1;
|
|
}
|
|
|
|
ho = (hdrObject *) PyList_GetItem(list, count++);
|
|
if (!ho) return 1;
|
|
|
|
if (!headerGetEntry(ho->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;
|
|
}
|
|
|
|
if (ho->md5list) free(ho->md5list);
|
|
if (ho->fileList) free(ho->fileList);
|
|
if (ho->linkList) free(ho->linkList);
|
|
|
|
ho->md5list = NULL;
|
|
ho->fileList = NULL;
|
|
ho->linkList = NULL;
|
|
|
|
iter = headerInitIterator(newH);
|
|
|
|
while (headerNextIterator(iter, &tag, &type, (void *) &p, &c)) {
|
|
/* could be dupes */
|
|
headerRemoveEntry(ho->h, tag);
|
|
headerAddEntry(ho->h, tag, type, p, c);
|
|
headerFreeData(p, type);
|
|
}
|
|
|
|
headerFreeIterator(iter);
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
newH = headerRead(fd, HEADER_MAGIC_YES);
|
|
Py_END_ALLOW_THREADS
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
PyObject * rpmMergeHeadersFromFD(PyObject * self, PyObject * args) {
|
|
FD_t fd;
|
|
int fileno;
|
|
PyObject * list;
|
|
int rc;
|
|
int matchTag;
|
|
|
|
if (!PyArg_ParseTuple(args, "Oii", &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 * versionCompare (PyObject * self, PyObject * args) {
|
|
hdrObject * h1, * h2;
|
|
|
|
if (!PyArg_ParseTuple(args, "O!O!", &hdrType, &h1, &hdrType, &h2)) return NULL;
|
|
|
|
return Py_BuildValue("i", rpmVersionCompare(h1->h, h2->h));
|
|
}
|
|
|
|
/**
|
|
*/
|
|
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;
|
|
|
|
if (e1 && !e2)
|
|
return Py_BuildValue("i", 1);
|
|
else if (!e1 && e2)
|
|
return Py_BuildValue("i", -1);
|
|
else if (e1 && e2) {
|
|
int ep1, ep2;
|
|
ep1 = atoi (e1);
|
|
ep2 = atoi (e2);
|
|
if (ep1 < ep2)
|
|
return Py_BuildValue("i", -1);
|
|
else if (ep1 > ep2)
|
|
return Py_BuildValue("i", 1);
|
|
}
|
|
|
|
rc = rpmvercmp(v1, v2);
|
|
if (rc)
|
|
return Py_BuildValue("i", rc);
|
|
|
|
return Py_BuildValue("i", rpmvercmp(r1, r2));
|
|
}
|
|
|
|
/*@}*/
|