/** \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)); } /*@}*/