From 5b7d1f7876a40e6900331a9aa9a77263c3fe6a57 Mon Sep 17 00:00:00 2001 From: jbj Date: Tue, 24 Aug 1999 21:10:30 +0000 Subject: [PATCH] update python bindings from anaconda. CVS patchset: 3251 CVS date: 1999/08/24 21:10:30 --- CHANGES | 1 + python/hash.c | 171 +++++++++++++++++++ python/hash.h | 25 +++ python/rpmmodule.c | 447 +++++++++++++++++++++++++++++++++++++++++++----- python/upgrade.c | 485 +++++++++++++++++++++++++++++++++++++++++++++++++++++ python/upgrade.h | 18 ++ rpm.spec | 2 +- 7 files changed, 1104 insertions(+), 45 deletions(-) create mode 100644 python/hash.c create mode 100644 python/hash.h create mode 100644 python/upgrade.c create mode 100644 python/upgrade.h diff --git a/CHANGES b/CHANGES index 52c7ce9..0b60236 100644 --- a/CHANGES +++ b/CHANGES @@ -35,6 +35,7 @@ - add LC_ALL/LC_MESSAGES to query locale search. - fix: segfault with "--sign" w/o supplying files (#4651). - add headerWrite return code and check for errors. + - update python bindings from anaconda. 3.0.1 -> 3.0.2 - eliminate armv4 entries from rpmrc (Andrew E. Mileski). diff --git a/python/hash.c b/python/hash.c new file mode 100644 index 0000000..c3fad33 --- /dev/null +++ b/python/hash.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include + +#include "hash.h" + +#define CHUNK 4 + +struct bucket { + char **data; + int allocated; + int firstFree; /* as in data[firstFree] */ +}; + +struct hash_table { + int size; + int entries; + int totalData; + int overHead; + struct bucket *bucket; +}; + +struct hash_table *htNewTable(int size) +{ + struct hash_table *res; + int i = 0; + + res = malloc(sizeof(struct hash_table)); + res->bucket = malloc(sizeof(struct bucket) * size); + res->size = size; + res->totalData = 0; + res->entries = 0; + res->overHead = sizeof(struct bucket) * size + CHUNK * sizeof(char *); + + while (i < size) { + res->bucket[i].data = malloc(CHUNK * sizeof(char *)); + res->bucket[i].allocated = CHUNK; + res->bucket[i].firstFree = 0; + i++; + } + + return res; +} + +void htFreeHashTable(struct hash_table *ht) +{ + struct bucket * b; + + b = ht->bucket; + while (ht->size--) { + while (b->firstFree) { + b->firstFree--; + free(b->data[b->firstFree]); + } + + free(b->data); + b++; + } + free(ht->bucket); + free(ht); +} + +void htHashStats(struct hash_table *t) +{ + int i = 0; + int empty = 0; + + while (i < t->size) { + if (t->bucket[i].firstFree != 0) { + /*printf("Bucket %d used %d\n", i, t->bucket[i].firstFree);*/ + } else { + empty++; + } + i++; + } + + printf("Total Buckets : %d\n", t->size); + printf("Empty Buckets : %d\n", empty); + printf("Total Entries : %d\n", t->entries); + printf("Total Data : %d\n", t->totalData); + printf("Total Overhead: %d\n", t->overHead); + printf("Avergage Depth: %f\n", (double)t->entries / (double)t->size); +} + +static unsigned int htHashString(char *s) +{ + unsigned int res = 0; + + while (*s) + res = ((res<<1) + (int)(*(s++))); + + return res; +} + +static char *in_table_aux(struct hash_table *t, int hash, char *s) +{ + int x; + + x = 0; + while (x < t->bucket[hash].firstFree) { + if (! strcmp(t->bucket[hash].data[x], s)) { + return t->bucket[hash].data[x]; + } + x++; + } + + return NULL; +} + +char *htInTable(struct hash_table *t, char *s) +{ + int hash; + + hash = htHashString(s) % t->size; + return in_table_aux(t, hash, s); +} + +void htAddToTable(struct hash_table *t, char *s) +{ + int hash; + + if (s == NULL) + return; + + hash = htHashString(s) % t->size; + if (in_table_aux(t, hash, s)) { + return; + } + + if (t->bucket[hash].firstFree == t->bucket[hash].allocated) { + t->bucket[hash].allocated += CHUNK; + t->bucket[hash].data = + realloc(t->bucket[hash].data, + t->bucket[hash].allocated * sizeof(char *)); + /*printf("Bucket %d grew to %d\n", hash, t->bucket[hash].allocated);*/ + t->overHead += sizeof(char *) * CHUNK; + } + /*printf("In bucket %d, item %d\n", hash, t->bucket[hash].firstFree);*/ + t->bucket[hash].data[t->bucket[hash].firstFree++] = strdup(s); + t->totalData += strlen(s) + 1; + t->entries++; +} + +int htNumEntries(struct hash_table *t) { + return t->entries; +} + +void htIterStart(htIterator * iter) { + iter->bucket = 0; + iter->item = -1; +} + +int htIterGetNext(struct hash_table * t, htIterator * iter, char ** s) { + iter->item++; + + while (iter->bucket < t->size) { + if (iter->item < t->bucket[iter->bucket].firstFree) { + *s = t->bucket[iter->bucket].data[iter->item]; + return 1; + } + + iter->item++; + if (iter->item >= t->bucket[iter->bucket].firstFree) { + iter->bucket++; + iter->item = 0; + } + } + + return 0; +} diff --git a/python/hash.h b/python/hash.h new file mode 100644 index 0000000..26b6387 --- /dev/null +++ b/python/hash.h @@ -0,0 +1,25 @@ +#ifndef H_HASH +#define H_HASH + +struct hash_table; +typedef struct hash_table * hashTable; + +struct ht_iterator { + int bucket; + int item; +}; + +typedef struct ht_iterator htIterator; + +struct hash_table *htNewTable(int size); +void htFreeHashTable(struct hash_table *ht); +char *htInTable(struct hash_table *t, char *s); +void htAddToTable(struct hash_table *t, char *s); +void htPrintHashStats(struct hash_table *t); +int htNumEntries(struct hash_table *t); + +/* these use static storage */ +void htIterStart(htIterator * iter); +int htIterGetNext(struct hash_table * t, htIterator * iter, char ** s); + +#endif diff --git a/python/rpmmodule.c b/python/rpmmodule.c index f4e72aa..8cf30b6 100644 --- a/python/rpmmodule.c +++ b/python/rpmmodule.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,6 +7,7 @@ #include "Python.h" #include "rpmlib.h" +#include "upgrade.h" /* Forward types */ @@ -19,19 +21,29 @@ static void rpmdbDealloc(rpmdbObject * s); static PyObject * rpmdbGetAttr(rpmdbObject * s, char * name); static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args); static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args); +static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args); +static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args); +static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args); static int rpmdbLength(rpmdbObject * s); static hdrObject * rpmdbSubscript(rpmdbObject * s, PyObject * key); static void hdrDealloc(hdrObject * s); static PyObject * hdrGetAttr(hdrObject * s, char * name); -static PyObject * hdrSubscript(hdrObject * s, int item); +static PyObject * hdrSubscript(hdrObject * s, PyObject * item); +static PyObject * hdrKeyList(hdrObject * s, PyObject * args); +static PyObject * hdrUnload(hdrObject * s, PyObject * args); static PyObject * hdrVerifyFile(hdrObject * s, PyObject * args); void initrpm(void); static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args); -static PyObject * archScore(PyObject * self, PyObject * args); +static PyObject * hdrLoad(PyObject * self, PyObject * args); static PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args); -static PyObject * rpmHeaderFromList(PyObject * self, PyObject * args); +static PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args); +static PyObject * archScore(PyObject * self, PyObject * args); +static PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args); +static PyObject * findUpgradeSet(PyObject * self, PyObject * args); +static PyObject * errorSetCallback (PyObject * self, PyObject * args); +static PyObject * errorString (PyObject * self, PyObject * args); static PyObject * rpmtransCreate(PyObject * self, PyObject * args); static PyObject * rpmtransAdd(rpmtransObject * s, PyObject * args); @@ -46,11 +58,16 @@ static int rpmtransSetAttr(rpmtransObject * o, char * name, /* Types */ static PyMethodDef rpmModuleMethods[] = { - { "opendb", (PyCFunction) rpmOpenDB, METH_VARARGS, NULL }, + { "TransactionSet", (PyCFunction) rpmtransCreate, METH_VARARGS, NULL }, { "archscore", (PyCFunction) archScore, METH_VARARGS, NULL }, + { "findUpgradeSet", (PyCFunction) findUpgradeSet, METH_VARARGS, NULL }, { "headerFromPackage", (PyCFunction) rpmHeaderFromPackage, METH_VARARGS, NULL }, - { "readHeaderList", (PyCFunction) rpmHeaderFromList, METH_VARARGS, NULL }, - { "TransactionSet", (PyCFunction) rpmtransCreate, METH_VARARGS, NULL }, + { "headerLoad", (PyCFunction) hdrLoad, METH_VARARGS, NULL }, + { "opendb", (PyCFunction) rpmOpenDB, METH_VARARGS, NULL }, + { "readHeaderListFromFD", (PyCFunction) rpmHeaderFromFD, METH_VARARGS, NULL }, + { "readHeaderListFromFile", (PyCFunction) rpmHeaderFromFile, METH_VARARGS, NULL }, + { "errorSetCallback", (PyCFunction) errorSetCallback, METH_VARARGS, NULL }, + { "errorString", (PyCFunction) errorString, METH_VARARGS, NULL }, { NULL } } ; @@ -84,14 +101,10 @@ struct hdrObject_s { static PyObject * pyrpmError; -static PySequenceMethods hdrAsSequence = { - 0, /* length */ - 0, /* concat */ - 0, /* repeat */ - (intargfunc) hdrSubscript, /* item */ - 0, /* slice */ - 0, /* assign item */ - 0, /* assign slice */ +static PyMappingMethods hdrAsMapping = { + (inquiry) 0, /* mp_length */ + (binaryfunc) hdrSubscript, /* mp_subscript */ + (objobjargproc)0, /* mp_ass_subscript */ }; static PyTypeObject hdrType = { @@ -107,8 +120,8 @@ static PyTypeObject hdrType = { 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ - &hdrAsSequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ + 0, /* tp_as_sequence */ + &hdrAsMapping, /* tp_as_mapping */ }; static PyMappingMethods rpmdbAsMapping = { @@ -152,8 +165,11 @@ static PyTypeObject rpmtransType = { }; static struct PyMethodDef rpmdbMethods[] = { - {"firstkey", (PyCFunction) rpmdbFirst, 1 }, - {"nextkey", (PyCFunction) rpmdbNext, 1 }, + {"firstkey", (PyCFunction) rpmdbFirst, 1 }, + {"nextkey", (PyCFunction) rpmdbNext, 1 }, + {"findbyfile", (PyCFunction) rpmdbByFile, 1 }, + {"findbyname", (PyCFunction) rpmdbByName, 1 }, + {"findbyprovides", (PyCFunction) rpmdbByProvides, 1 }, {NULL, NULL} /* sentinel */ }; @@ -166,14 +182,19 @@ static struct PyMethodDef rpmtransMethods[] = { }; static struct PyMethodDef hdrMethods[] = { + {"keys", (PyCFunction) hdrKeyList, 1 }, + {"unload", (PyCFunction) hdrUnload, 1 }, {"verifyFile", (PyCFunction) hdrVerifyFile, 1 }, {NULL, NULL} /* sentinel */ }; +/* External functions */ +int mdfile(const char *fn, unsigned char *digest); + /* Code */ void initrpm(void) { - PyObject * m, * d, * tag; + PyObject * m, * d, * tag, * dict; int i; rpmReadConfigFiles(NULL, NULL); @@ -184,11 +205,17 @@ void initrpm(void) { pyrpmError = PyString_FromString("rpm.error"); PyDict_SetItemString(d, "error", pyrpmError); + dict = PyDict_New(); + for (i = 0; i < rpmTagTableSize; i++) { tag = PyInt_FromLong(rpmTagTable[i].val); PyDict_SetItemString(d, rpmTagTable[i].name, tag); + + PyDict_SetItem(dict, tag, PyString_FromString(rpmTagTable[i].name + 7)); } + PyDict_SetItemString(d, "tagnames", dict); + PyDict_SetItemString(d, "RPMFILE_STATE_NORMAL", PyInt_FromLong(RPMFILE_STATE_NORMAL)); PyDict_SetItemString(d, "RPMFILE_STATE_REPLACED", @@ -272,6 +299,113 @@ void initrpm(void) { PyInt_FromLong(RPMCALLBACK_UNINST_STOP)); } + +static int psGetArchScore(Header h) { + void * pkgArch; + int type, count; + + if (!headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count) || + type == RPM_INT8_TYPE) + return 150; + else + return rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch); +} + +static int pkgCompareVer(void * first, void * second) { + struct packageInfo ** a = first; + struct packageInfo ** b = second; + int ret, score1, score2; + + /* put packages w/o names at the end */ + if (!(*a)->name) return 1; + if (!(*b)->name) return -1; + + ret = strcasecmp((*a)->name, (*b)->name); + if (ret) return ret; + score1 = psGetArchScore((*a)->h); + if (!score1) return 1; + score2 = psGetArchScore((*b)->h); + if (!score2) return -1; + if (score1 < score2) return -1; + if (score1 > score2) return 1; + return rpmVersionCompare((*b)->h, (*a)->h); +} + +static void pkgSort(struct pkgSet * psp) { + int i; + char *name; + + qsort(psp->packages, psp->numPackages, sizeof(*psp->packages), + (void *) pkgCompareVer); + + name = psp->packages[0]->name; + if (!name) { + psp->numPackages = 0; + return; + } + for (i = 1; i < psp->numPackages; i++) { + if (!psp->packages[i]->name) break; + if (!strcmp(psp->packages[i]->name, name)) + psp->packages[i]->name = NULL; + else + name = psp->packages[i]->name; + } + + qsort(psp->packages, psp->numPackages, sizeof(*psp->packages), + (void *) pkgCompareVer); + + for (i = 0; i < psp->numPackages; i++) + if (!psp->packages[i]->name) break; + psp->numPackages = i; +} + +static PyObject * findUpgradeSet(PyObject * self, PyObject * args) { + PyObject * hdrList, * result; + char * root = "/"; + int i; + struct pkgSet list; + hdrObject * hdr; + + if (!PyArg_ParseTuple(args, "O|s", &hdrList, &root)) return NULL; + + if (!PyList_Check(hdrList)) { + PyErr_SetString(PyExc_TypeError, "list of headers expected"); + return NULL; + } + + list.numPackages = PyList_Size(hdrList); + list.packages = alloca(sizeof(list.packages) * list.numPackages); + for (i = 0; i < list.numPackages; i++) { + hdr = (hdrObject *) PyList_GetItem(hdrList, i); + if (hdr->ob_type != &hdrType) { + PyErr_SetString(PyExc_TypeError, "list of headers expected"); + return NULL; + } + list.packages[i] = alloca(sizeof(struct packageInfo)); + list.packages[i]->h = hdr->h; + list.packages[i]->selected = 0; + list.packages[i]->data = hdr; + + headerGetEntry(hdr->h, RPMTAG_NAME, NULL, + (void **) &list.packages[i]->name, NULL); + } + + pkgSort (&list); + + if (ugFindUpgradePackages(&list, root)) { + PyErr_SetString(pyrpmError, "error during upgrade check"); + return NULL; + } + + result = PyList_New(0); + for (i = 0; i < list.numPackages; i++) { + if (list.packages[i]->selected) + PyList_Append(result, list.packages[i]->data); + } + + return result; +} + static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) { rpmdbObject * o; char * root = ""; @@ -290,24 +424,20 @@ static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) { return o; } -static PyObject * rpmHeaderFromList(PyObject * self, PyObject * args) { - char * filespec; - FD_t fd; - Header header; +static PyObject * rpmReadHeaders (FD_t fd) { PyObject * list; + Header header; hdrObject * h; - if (!PyArg_ParseTuple(args, "s", &filespec)) return NULL; - fd = fdOpen(filespec, O_RDONLY, 0); - 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) { h = (hdrObject *) PyObject_NEW(PyObject, &hdrType); h->h = header; @@ -322,16 +452,122 @@ static PyObject * rpmHeaderFromList(PyObject * self, PyObject * args) { Py_DECREF(h); + Py_BEGIN_ALLOW_THREADS header = headerRead(fd, HEADER_MAGIC_YES); + Py_END_ALLOW_THREADS } + return list; +} + +static 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); fdClose(fd); return list; } + +static PyObject * hdrLoad(PyObject * self, PyObject * args) { + char * obj; + Header hdr; + hdrObject * h; + int len; + + if (!PyArg_ParseTuple(args, "s#", &obj, &len)) return NULL; + + hdr = headerLoad(obj); + if (!hdr) { + PyErr_SetString(pyrpmError, "bad header"); + return NULL; + } + + 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; +} + +static PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args) { + char * filespec; + FD_t fd; + PyObject * list; + + if (!PyArg_ParseTuple(args, "s", &filespec)) return NULL; + fd = fdOpen(filespec, O_RDONLY, 0); + + if (!fd) { + PyErr_SetFromErrno(pyrpmError); + return NULL; + } + + list = rpmReadHeaders (fd); + fdClose(fd); + + return list; +} + +static PyObject * errorCB = NULL, * errorData = NULL; + +static void errorcb (void) +{ + PyObject * result, * args = NULL; + + if (errorData) + args = Py_BuildValue("(O)", errorData); + + result = PyEval_CallObject(errorCB, args); + Py_XDECREF(args); + + if (result == NULL) { + PyErr_Print(); + PyErr_Clear(); + } + Py_DECREF (result); +} + +static PyObject * errorSetCallback (PyObject * self, PyObject * args) { + if (errorCB != NULL) { + Py_DECREF (errorCB); + errorCB = NULL; + } + + if (errorData != NULL) { + Py_DECREF (errorData); + errorData = NULL; + } + + if (!PyArg_ParseTuple(args, "O|O", &errorCB, &errorData)) return NULL; + + if (!PyCallable_Check (errorCB)) { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + return NULL; + } + + Py_INCREF (errorCB); + Py_XINCREF (errorData); + + rpmErrorSetCallback (errorcb); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * errorString (PyObject * self, PyObject * args) { + return PyString_FromString(rpmErrorString ()); +} + static PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args) { - PyObject * fileObj; hdrObject * h; Header header; int rc; @@ -382,7 +618,7 @@ static void rpmdbDealloc(rpmdbObject * s) { static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args) { int first; - if (!PyArg_Parse(args, "")) return NULL; + if (!PyArg_ParseTuple (args, "")) return NULL; first = rpmdbFirstRecNum(s->db); @@ -397,7 +633,7 @@ static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args) { static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args) { int where; - if (!PyArg_Parse(args, "i", &where)) return NULL; + if (!PyArg_ParseTuple (args, "i", &where)) return NULL; where = rpmdbNextRecNum(s->db, where); @@ -409,6 +645,60 @@ static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args) { return Py_BuildValue("i", where); } +static PyObject * handleDbResult(int rc, dbiIndexSet matches) { + PyObject * list; + int i; + + if (rc == -1) { + PyErr_SetString(pyrpmError, "error reading from database"); + return NULL; + } + + list = PyList_New(0); + + if (!rc) { + for (i = 0; i < matches.count; i++) + PyList_Append(list, PyInt_FromLong(matches.recs[i].recOffset)); + + dbiFreeIndexRecord(matches); + } + + return list; +} + +static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args) { + char * str; + dbiIndexSet matches; + int rc; + + if (!PyArg_ParseTuple(args, "s", &str)) return NULL; + + rc = rpmdbFindPackage(s->db, str, &matches); + return handleDbResult(rc, matches); +} + +static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args) { + char * str; + dbiIndexSet matches; + int rc; + + if (!PyArg_ParseTuple(args, "s", &str)) return NULL; + + rc = rpmdbFindByFile(s->db, str, &matches); + return handleDbResult(rc, matches); +} + +static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args) { + char * str; + dbiIndexSet matches; + int rc; + + if (!PyArg_ParseTuple(args, "s", &str)) return NULL; + + rc = rpmdbFindByProvides(s->db, str, &matches); + return handleDbResult(rc, matches); +} + static int rpmdbLength(rpmdbObject * s) { int first; int count = 0; @@ -463,13 +753,27 @@ static PyObject * hdrGetAttr(hdrObject * s, char * name) { return Py_FindMethod(hdrMethods, (PyObject * ) s, name); } -static PyObject * hdrSubscript(hdrObject * s, int tag) { - int type, count; +static PyObject * hdrSubscript(hdrObject * s, PyObject * item) { + int type, count, i, tag = -1; void * data; PyObject * o, * metao; - int i; char ** stringArray; int forceArray = 0; + char * str; + + if (PyInt_Check(item)) { + tag = PyInt_AsLong(item); + } else if (PyString_Check(item)) { + str = PyString_AsString(item); + for (i = 0; i < rpmTagTableSize; i++) + if (!strcasecmp(rpmTagTable[i].name + 7, str)) break; + if (i < rpmTagTableSize) tag = rpmTagTable[i].val; + } + + if (tag == -1) { + PyErr_SetString(PyExc_KeyError, "unknown header tag"); + return NULL; + } if (!headerGetEntry(s->h, tag, &type, &data, &count)) { Py_INCREF(Py_None); @@ -577,6 +881,50 @@ static PyObject * hdrSubscript(hdrObject * s, int tag) { return o; } +static PyObject * hdrKeyList(hdrObject * s, PyObject * args) { + PyObject * list; + 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, PyInt_FromLong(tag)); + } + } + + headerFreeIterator(iter); + + return list; +} + +static PyObject * hdrUnload(hdrObject * s, PyObject * args) { + char * buf; + int len; + PyObject * rc; + + len = headerSizeof(s->h, 0); + buf = headerUnload(s->h); + + rc = PyString_FromStringAndSize(buf, len); + free(buf); + + return rc; +} + /* Returns a list of these tuple for each part which failed: (attr_name, correctValue, currentValue) @@ -709,7 +1057,7 @@ static PyObject * hdrVerifyFile(hdrObject * s, PyObject * args) { PyTuple_SetItem(tuple, 0, attrName); sprintf(buf, "0x%-4x", s->rdevs[fileNumber]); PyTuple_SetItem(tuple, 1, PyString_FromString(buf)); - sprintf(buf, "0x%-4x", sb.st_rdev); + sprintf(buf, "0x%-4x", (unsigned int) sb.st_rdev); PyTuple_SetItem(tuple, 2, PyString_FromString(buf)); PyList_Append(list, tuple); } @@ -780,8 +1128,9 @@ static PyObject * rpmtransCreate(PyObject * self, PyObject * args) { o = (void *) PyObject_NEW(rpmtransObject, &rpmtransType); - Py_INCREF(db); + Py_XINCREF(db); o->dbo = db; + o->scriptFd = NULL; o->ts = rpmtransCreateSet(db ? db->db : NULL, rootPath); o->keyList = PyList_New(0); @@ -792,8 +1141,12 @@ static void rpmtransDealloc(PyObject * o) { rpmtransObject * trans = (void *) o; rpmtransFree(trans->ts); - if (trans->dbo) Py_DECREF(trans->dbo); + if (trans->dbo) { + Py_DECREF(trans->dbo); + } if (trans->scriptFd) fdClose(trans->scriptFd); + /* this will free the keyList, and decrement the ref count of all + the items on the list as well :-) */ Py_DECREF(trans->keyList); } @@ -826,23 +1179,26 @@ static PyObject * rpmtransAdd(rpmtransObject * s, PyObject * args) { hdrObject * h; PyObject * key; char * how = NULL; + int isUpgrade = 0; - if (!PyArg_ParseTuple(args, "OO|s", &h, &key, &s)) return NULL; + if (!PyArg_ParseTuple(args, "OO|s", &h, &key, &how)) return NULL; if (h->ob_type != &hdrType) { PyErr_SetString(PyExc_TypeError, "bad type for header argument"); return NULL; } - if (how && strcmp(how, "a") && strcmp(how, "u")) { - PyErr_SetString(PyExc_TypeError, "how argument must be \"u\" or \"a\""); + if (how && strcmp(how, "a") && strcmp(how, "u") && strcmp(how, "i")) { + PyErr_SetString(PyExc_TypeError, "how argument must be \"u\", \"a\", or \"i\""); return NULL; - } + } else if (how && !strcmp(how, "u")) + isUpgrade = 1; - if (how && strcmp(how, "a")) + if (how && !strcmp(how, "a")) rpmtransAvailablePackage(s->ts, h->h, key); else - rpmtransAddPackage(s->ts, h->h, NULL, key, how ? 1 : 0, NULL); + rpmtransAddPackage(s->ts, h->h, NULL, key, isUpgrade, NULL); + /* This should increment the usage count for me */ if (key) PyList_Append(s->keyList, key); Py_INCREF(Py_None); @@ -904,7 +1260,7 @@ static void * tsCallback(const Header h, const rpmCallbackType what, struct tsCallbackType * cbInfo = data; PyObject * args, * result; int fd; - FD_t fdt; + static FD_t fdt; if (cbInfo->pythonError) return NULL; @@ -925,11 +1281,14 @@ static void * tsCallback(const Header h, const rpmCallbackType what, return NULL; } fdt = fdDup(fd); - close(fd); Py_DECREF(result); return fdt; } + if (what == RPMCALLBACK_INST_CLOSE_FILE) { + fdClose (fdt); + } + Py_DECREF(result); return NULL; diff --git a/python/upgrade.c b/python/upgrade.c new file mode 100644 index 0000000..1bf863c --- /dev/null +++ b/python/upgrade.c @@ -0,0 +1,485 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "hash.h" +#include "upgrade.h" + +#define MAXPKGS 1024 + +#define USEDEBUG 0 + +#define DEBUG(x) { \ + if (USEDEBUG) \ + printf x; \ + } + +#if 0 +static void printMemStats(char *mess) +{ + char buf[1024]; + printf("%s\n", mess); + sprintf(buf, "cat /proc/%d/status | grep VmSize", getpid()); + system(buf); +} +#endif + +int pkgCompare(void * first, void * second) { + struct packageInfo ** a = first; + struct packageInfo ** b = second; + + /* put packages w/o names at the end */ + if (!(*a)->name) return 1; + if (!(*b)->name) return -1; + + return strcasecmp((*a)->name, (*b)->name); +} + + +static void compareFileList(int availFileCount, char **availFiles, + int installedFileCount, char **installedFiles, + struct hash_table *ht) +{ + int installedX, availX, rc; + + availX = 0; + installedX = 0; + while (installedX < installedFileCount) { + if (availX == availFileCount) { + /* All the rest have moved */ + DEBUG(("=> %s\n", installedFiles[installedX])); + if (strncmp(installedFiles[installedX], "/etc/rc.d/", 10)) + htAddToTable(ht, installedFiles[installedX]); + installedX++; + } else { + rc = strcmp(availFiles[availX], installedFiles[installedX]); + if (rc > 0) { + /* Avail > Installed -- file has moved */ + DEBUG (("=> %s\n", installedFiles[installedX])); + if (strncmp(installedFiles[installedX], "/etc/rc.d/", 10)) + htAddToTable(ht, installedFiles[installedX]); + installedX++; + } else if (rc < 0) { + /* Avail < Installed -- avail has some new files */ + availX++; + } else { + /* Files are equal -- file not moved */ + availX++; + installedX++; + } + } + } +} + +static void addLostFiles(rpmdb db, struct pkgSet *psp, struct hash_table *ht) +{ + int num; + Header h; + char *name; + struct packageInfo **pack; + struct packageInfo key; + struct packageInfo *keyaddr = &key; + char **installedFiles; + int installedFileCount; + + num = rpmdbFirstRecNum(db); + while (num) { + h = rpmdbGetRecord(db, num); + headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); + if (name && !strcmp(name, "metroess")) { + /* metro was removed from 5.1, but leave it if it's already + installed */ + headerFree(h); + num = rpmdbNextRecNum(db, num); + continue; + } + key.name = name; + + pack = bsearch(&keyaddr, psp->packages, psp->numPackages, + sizeof(*psp->packages), (void *)pkgCompare); + if (!pack) { + if (headerGetEntry(h, RPMTAG_FILENAMES, NULL, + (void **) &installedFiles, &installedFileCount)) { + compareFileList(0, NULL, installedFileCount, + installedFiles, ht); + free(installedFiles); + } + } + + headerFree(h); + num = rpmdbNextRecNum(db, num); + } +} + +static int findPackagesWithObsoletes(rpmdb db, struct pkgSet *psp) +{ + dbiIndexSet matches; + int rc, count, obsoletesCount; + struct packageInfo **pip; + char **obsoletes; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + if ((*pip)->selected) { + pip++; + continue; + } + + if (headerGetEntry((*pip)->h, RPMTAG_OBSOLETES, NULL, + (void **) &obsoletes, &obsoletesCount)) { + while (obsoletesCount--) { + rc = rpmdbFindPackage(db, obsoletes[obsoletesCount], &matches); + if (!rc) { + if (matches.count) { + (*pip)->selected = 1; + dbiFreeIndexRecord(matches); + break; + } + + dbiFreeIndexRecord(matches); + } + } + + free(obsoletes); + } + + pip++; + } + + return 0; +} + +static void errorFunction(void) +{ +} + +static int findUpgradePackages(rpmdb db, struct pkgSet *psp, + struct hash_table *ht) +{ + int skipThis; + Header h, installedHeader; + char *name, *version, *release; + dbiIndexSet matches; + int rc, i, count; + char **installedFiles, **availFiles; + int installedFileCount, availFileCount; + struct packageInfo **pip; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + h = (*pip)->h; + name = version = release = NULL; + headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); + headerGetEntry(h, RPMTAG_VERSION, NULL, (void **) &version, NULL); + headerGetEntry(h, RPMTAG_RELEASE, NULL, (void **) &release, NULL); + if (! (name && version && release)) { + /* bum header */ + /*logMessage("Failed with bad header");*/ + return(-1); + } + + DEBUG (("Avail: %s-%s-%s\n", name, version, release)); + rc = rpmdbFindPackage(db, name, &matches); + + if (rc == 0) { + skipThis = 0; + rpmErrorSetCallback(errorFunction); + for (i = 0; i < matches.count; i++) { + installedHeader = + rpmdbGetRecord(db, matches.recs[i].recOffset); + if (rpmVersionCompare(installedHeader, h) >= 0) { + /* already have a newer version installed */ + DEBUG (("Already have newer version\n")) + skipThis = 1; + headerFree(installedHeader); + break; + } + headerFree(installedHeader); + } + rpmErrorSetCallback(NULL); + if (! skipThis) { + DEBUG (("No newer version installed\n")) + } + } else { + skipThis = 1; + DEBUG (("Not installed\n")) + } + + if (skipThis) { + DEBUG (("DO NOT INSTALL\n")) + } else { + DEBUG (("UPGRADE\n")) + (*pip)->selected = 1; + + if (!headerGetEntry(h, RPMTAG_FILENAMES, NULL, + (void **) &availFiles, &availFileCount)) { + availFiles = NULL; + availFileCount = 0; + } + + for (i = 0; i < matches.count; i++) { + /* Compare the file lists */ + installedHeader = + rpmdbGetRecord(db, matches.recs[i].recOffset); + if (!headerGetEntry(installedHeader, RPMTAG_FILENAMES, NULL, + (void **) &installedFiles, + &installedFileCount)) { + installedFiles = NULL; + installedFileCount = 0; + } + + compareFileList(availFileCount, availFiles, + installedFileCount, installedFiles, ht); + + if (installedFiles) { + free(installedFiles); + } + headerFree(installedHeader); + } + + if (availFiles) { + free(availFiles); + } + } + + if (rc == 0) { + dbiFreeIndexRecord(matches); + } + + DEBUG (("\n\n")) + + pip++; + } + + return 0; +} + +static int removeMovedFilesAlreadyHandled(struct pkgSet *psp, + struct hash_table *ht) +{ + char *name; + int i, count; + Header h; + char **availFiles; + int availFileCount; + char *file; + struct packageInfo **pip; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + h = (*pip)->h; + if ((*pip)->selected) { + name = NULL; + headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); + + if (!headerGetEntry(h, RPMTAG_FILENAMES, NULL, + (void **) &availFiles, &availFileCount)) { + availFiles = NULL; + availFileCount = 0; + } + + for (i = 0; i < availFileCount; i++) { + if ((file = htInTable(ht, availFiles[i]))) { + *file = '\0'; + DEBUG (("File already in %s: %s\n", name, availFiles[i])) + break; + } + } + if (availFiles) { + free(availFiles); + } + } + + pip++; + } + + return 0; +} + +static int findPackagesWithRelocatedFiles(struct pkgSet *psp, + struct hash_table *ht) +{ + char *name; + int i, count; + Header h; + char **availFiles; + int availFileCount; + char *file; + struct packageInfo **pip; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + h = (*pip)->h; + if (! (*pip)->selected) { + name = NULL; + headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); + + availFiles = NULL; + availFileCount = 0; + if (headerGetEntry(h, RPMTAG_FILENAMES, NULL, + (void **) &availFiles, &availFileCount)) { + for (i = 0; i < availFileCount; i++) { + if ((file = htInTable(ht, availFiles[i]))) { + *file = '\0'; + DEBUG (("Found file in %s: %s\n", name, + availFiles[i])) + (*pip)->selected = 1; + break; + } + } + free(availFiles); + } + } + + pip++; + } + + return 0; +} + +/* +static void printCount(struct pkgSet *psp) +{ + int i, upgradeCount; + struct packageInfo *pip; + + upgradeCount = 0; + pip = psp->packages; + i = psp->numPackages; + while (i--) { + if (pip->selected) { + upgradeCount++; + } + pip++; + } + logMessage("marked %d packages for upgrade", upgradeCount); +} +*/ + +static int unmarkPackagesAlreadyInstalled(rpmdb db, struct pkgSet *psp) +{ + dbiIndexSet matches; + Header h, installedHeader; + char *name, *version, *release; + struct packageInfo **pip; + int count, rc, i; + + count = psp->numPackages; + pip = psp->packages; + while (count--) { + if ((*pip)->selected) { + h = (*pip)->h; + /* If this package is already installed, don't bother */ + name = version = release = NULL; + headerGetEntry(h, RPMTAG_NAME, NULL, (void **) &name, NULL); + headerGetEntry(h, RPMTAG_VERSION, NULL, (void **) &version, NULL); + headerGetEntry(h, RPMTAG_RELEASE, NULL, (void **) &release, NULL); + if (! (name && version && release)) { + /* bum header */ + /*logMessage("Failed with bad header");*/ + return(-1); + } + rc = rpmdbFindPackage(db, name, &matches); + if (rc == 0) { + rpmErrorSetCallback(errorFunction); + for (i = 0; i < matches.count; i++) { + installedHeader = + rpmdbGetRecord(db, matches.recs[i].recOffset); + if (rpmVersionCompare(installedHeader, h) >= 0) { + /* already have a newer version installed */ + DEBUG (("Already have newer version\n")) + (*pip)->selected = 0; + headerFree(installedHeader); + break; + } + headerFree(installedHeader); + } + rpmErrorSetCallback(NULL); + dbiFreeIndexRecord(matches); + } + } + + pip++; + } + + return 0; +} + +static void emptyErrorCallback(void) { +} + +int ugFindUpgradePackages(struct pkgSet *psp, char *installRoot) +{ + rpmdb db; + struct hash_table *hashTable; + rpmErrorCallBackType old; + + /*logDebugMessage(("ugFindUpgradePackages() ..."));*/ + + rpmReadConfigFiles(NULL, NULL); + + rpmSetVerbosity(RPMMESS_FATALERROR); + old = rpmErrorSetCallback(emptyErrorCallback); + + if (rpmdbOpenForTraversal(installRoot, &db)) { + /*logMessage("failed opening %s/var/lib/rpm/packages.rpm", + installRoot);*/ + return(-1); + } + + rpmErrorSetCallback(old); + rpmSetVerbosity(RPMMESS_NORMAL); + + hashTable = htNewTable(1103); + + /* For all packages that are installed, if there is no package */ + /* available by that name, add the package's files to the hash table */ + addLostFiles(db, psp, hashTable); + /*logDebugMessage(("added lost files")); + printCount(psp);*/ + + /* Find packges that are new, and mark them in installThisPackage, */ + /* updating availPkgs with the count. Also add files to the hash */ + /* table that do not exist in the new package - they may have moved */ + if (findUpgradePackages(db, psp, hashTable)) { + rpmdbClose(db); + return(-1); + } + /*logDebugMessage(("found basic packages to upgrade")); + printCount(psp); + hash_stats(hashTable);*/ + + /* Remove any files that were added to the hash table that are in */ + /* some other package marked for upgrade. */ + removeMovedFilesAlreadyHandled(psp, hashTable); + /*logDebugMessage(("removed extra files which have moved")); + printCount(psp);*/ + + findPackagesWithRelocatedFiles(psp, hashTable); + /*logDebugMessage(("found packages with relocated files")); + printCount(psp);*/ + + findPackagesWithObsoletes(db, psp); + /*logDebugMessage(("found packages that obsolete installed packages")); + printCount(psp);*/ + + unmarkPackagesAlreadyInstalled(db, psp); + /*logDebugMessage(("unmarked packages already installed")); + printCount(psp);*/ + + htFreeHashTable(hashTable); + + /*printMemStats("Done");*/ + + rpmdbClose(db); + + return 0; +} diff --git a/python/upgrade.h b/python/upgrade.h new file mode 100644 index 0000000..d971b7f --- /dev/null +++ b/python/upgrade.h @@ -0,0 +1,18 @@ +#ifndef H_UPGRADE +#define H_UPGRADE + +struct packageInfo { + Header h; + char selected; + char * name; + void * data; +} ; + +struct pkgSet { + struct packageInfo ** packages; + int numPackages; +}; + +int ugFindUpgradePackages(struct pkgSet *psp, char *installRoot); + +#endif diff --git a/rpm.spec b/rpm.spec index b109e28..41d5ea8 100644 --- a/rpm.spec +++ b/rpm.spec @@ -2,7 +2,7 @@ Summary: The Red Hat package management system. Name: rpm %define version 3.0.3 Version: %{version} -Release: 0.17 +Release: 0.18 Group: System Environment/Base Source: ftp://ftp.rpm.org/pub/rpm/dist/rpm-3.0.x/rpm-%{version}.tar.gz Copyright: GPL -- 2.7.4