summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES1
-rw-r--r--python/hash.c171
-rw-r--r--python/hash.h25
-rw-r--r--python/rpmmodule.c447
-rw-r--r--python/upgrade.c485
-rw-r--r--python/upgrade.h18
-rw-r--r--rpm.spec2
7 files changed, 1104 insertions, 45 deletions
diff --git a/CHANGES b/CHANGES
index 52c7ce937..0b602365b 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 000000000..c3fad331d
--- /dev/null
+++ b/python/hash.c
@@ -0,0 +1,171 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 000000000..26b638787
--- /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 f4e72aa95..8cf30b6a5 100644
--- a/python/rpmmodule.c
+++ b/python/rpmmodule.c
@@ -1,3 +1,4 @@
+#include <alloca.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
@@ -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 000000000..1bf863cfd
--- /dev/null
+++ b/python/upgrade.c
@@ -0,0 +1,485 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <rpm/rpmlib.h>
+#include <rpm/header.h>
+#include <string.h>
+
+#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 000000000..d971b7f7b
--- /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 b109e28ee..41d5ea8c5 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