Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

python/rpmmodule.c

Go to the documentation of this file.
00001 
00005 #include <alloca.h>
00006 #include <errno.h>
00007 #include <fcntl.h>
00008 #include <sys/stat.h>
00009 #include <sys/time.h>
00010 #include <unistd.h>
00011 #include <glob.h>       /* XXX rpmio.h */
00012 #include <dirent.h>     /* XXX rpmio.h */
00013 #include <locale.h>
00014 
00015 #include "Python.h"
00016 #include "rpmlib.h"
00017 #include "misc.h"
00018 #include "rpmmacro.h"
00019 #include "upgrade.h"
00020 
00021 extern int _rpmio_debug;
00022 
00023 extern int mdfile(const char *fn, unsigned char *digest);
00024 
00025 void initrpm(void);
00026 
00027 /* from lib/misc.c */
00028 int rpmvercmp(const char * one, const char * two);
00029 
00030 
00033 typedef struct rpmdbObject_s rpmdbObject;
00034 
00037 typedef struct rpmdbMIObject_s rpmdbMIObject;
00038 
00041 typedef struct rpmtransObject_s rpmtransObject;
00042 
00045 typedef struct hdrObject_s hdrObject;
00046 
00049 static PyObject * pyrpmError;
00050 
00100 
00103 struct hdrObject_s {
00104     PyObject_HEAD;
00105     Header h;
00106     Header sigs;
00107     char ** md5list;
00108     char ** fileList;
00109     char ** linkList;
00110     int_32 * fileSizes;
00111     int_32 * mtimes;
00112     int_32 * uids, * gids;
00113     unsigned short * rdevs;
00114     unsigned short * modes;
00115 } ;
00116 
00119 static PyObject * hdrKeyList(hdrObject * s, PyObject * args) {
00120     PyObject * list, *o;
00121     HeaderIterator iter;
00122     int tag, type;
00123 
00124     if (!PyArg_ParseTuple(args, "")) return NULL;
00125 
00126     list = PyList_New(0);
00127 
00128     iter = headerInitIterator(s->h);
00129     while (headerNextIterator(iter, &tag, &type, NULL, NULL)) {
00130         if (tag == HEADER_I18NTABLE) continue;
00131 
00132         switch (type) {
00133           case RPM_BIN_TYPE:
00134           case RPM_INT32_TYPE:
00135           case RPM_CHAR_TYPE:
00136           case RPM_INT8_TYPE:
00137           case RPM_INT16_TYPE:
00138           case RPM_STRING_ARRAY_TYPE:
00139           case RPM_STRING_TYPE:
00140             PyList_Append(list, o=PyInt_FromLong(tag));
00141             Py_DECREF(o);
00142         }
00143     }
00144 
00145     headerFreeIterator(iter);
00146 
00147     return list;
00148 }
00149 
00152 static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords) {
00153     char * buf;
00154     PyObject * rc;
00155     int len, legacy = 0;
00156     static char *kwlist[] = { "legacyHeader", NULL};
00157 
00158     if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
00159         return NULL; 
00160 
00161     if (legacy) {
00162         Header h;
00163 
00164         h = headerCopy(s->h);
00165         len = headerSizeof(h, 0);
00166         buf = headerUnload(h);
00167     } else {
00168         len = headerSizeof(s->h, 0);
00169         buf = headerUnload(s->h);
00170     }
00171 
00172     rc = PyString_FromStringAndSize(buf, len);
00173     free(buf);
00174 
00175     return rc;
00176 }
00177 
00178 /* Returns a list of these tuple for each part which failed:
00179 
00180         (attr_name, correctValue, currentValue)
00181 
00182         It should be passwd the file number to verify.
00183 */
00186 static PyObject * hdrVerifyFile(hdrObject * s, PyObject * args) {
00187     int fileNumber;
00188     rpmVerifyAttrs verifyResult = 0;
00189     PyObject * list, * tuple, * attrName;
00190     int type, count;
00191     struct stat sb;
00192     char buf[2048];
00193     int i;
00194     time_t timeInt;
00195     struct tm * timeStruct;
00196 
00197     if (!PyInt_Check(args)) {
00198         PyErr_SetString(PyExc_TypeError, "integer expected");
00199         return NULL;
00200     }
00201 
00202     fileNumber = (int) PyInt_AsLong(args);
00203 
00204     if (rpmVerifyFile("", s->h, fileNumber, &verifyResult, RPMVERIFY_NONE)) {
00205         Py_INCREF(Py_None);
00206         return Py_None;
00207     }
00208 
00209     list = PyList_New(0);
00210 
00211     if (!verifyResult) return list;
00212 
00213     if (!s->fileList) {
00214         headerGetEntry(s->h, RPMTAG_OLDFILENAMES, &type, (void **) &s->fileList,
00215                  &count);
00216     }
00217 
00218     lstat(s->fileList[fileNumber], &sb);
00219 
00220     if (verifyResult & RPMVERIFY_MD5) {
00221         if (!s->md5list) {
00222             headerGetEntry(s->h, RPMTAG_FILEMD5S, &type, (void **) &s->md5list,
00223                      &count);
00224         }
00225 
00226         if (mdfile(s->fileList[fileNumber], buf)) {
00227             strcpy(buf, "(unknown)");
00228         }
00229 
00230         tuple = PyTuple_New(3);
00231         attrName = PyString_FromString("checksum");
00232         PyTuple_SetItem(tuple, 0, attrName);
00233         PyTuple_SetItem(tuple, 1, PyString_FromString(s->md5list[fileNumber]));
00234         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
00235         PyList_Append(list, tuple);
00236         Py_DECREF(tuple);
00237     }
00238 
00239     if (verifyResult & RPMVERIFY_FILESIZE) {
00240         if (!s->fileSizes) {
00241             headerGetEntry(s->h, RPMTAG_FILESIZES, &type, (void **) &s->fileSizes,
00242                      &count);
00243 
00244         }
00245 
00246         tuple = PyTuple_New(3);
00247         attrName = PyString_FromString("size");
00248         PyTuple_SetItem(tuple, 0, attrName);
00249 
00250         sprintf(buf, "%d", 100);
00251         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
00252         sprintf(buf, "%ld", sb.st_size);
00253         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
00254         PyList_Append(list, tuple);
00255         Py_DECREF(tuple);
00256     }
00257 
00258     if (verifyResult & RPMVERIFY_LINKTO) {
00259         if (!s->linkList) {
00260             headerGetEntry(s->h, RPMTAG_FILELINKTOS, &type, (void **) &s->linkList,
00261                      &count);
00262         }
00263 
00264         i = readlink(s->fileList[fileNumber], buf, sizeof(buf));
00265         if (i <= 0)
00266             strcpy(buf, "(unknown)");
00267         else
00268             buf[i] = '\0';
00269 
00270         tuple = PyTuple_New(3);
00271         attrName = PyString_FromString("link");
00272         PyTuple_SetItem(tuple, 0, attrName);
00273         PyTuple_SetItem(tuple, 1, PyString_FromString(s->linkList[fileNumber]));
00274         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
00275         PyList_Append(list, tuple);
00276         Py_DECREF(tuple);
00277     }
00278 
00279     if (verifyResult & RPMVERIFY_MTIME) {
00280         if (!s->mtimes) {
00281             headerGetEntry(s->h, RPMTAG_FILEMTIMES, &type, (void **) &s->mtimes,
00282                      &count);
00283         }
00284 
00285         tuple = PyTuple_New(3);
00286         attrName = PyString_FromString("time");
00287         PyTuple_SetItem(tuple, 0, attrName);
00288 
00289         timeInt = sb.st_mtime;
00290         timeStruct = localtime(&timeInt);
00291         strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
00292         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
00293 
00294         timeInt = s->mtimes[fileNumber];
00295         timeStruct = localtime(&timeInt);
00296         strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
00297 
00298         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
00299 
00300         PyList_Append(list, tuple);
00301         Py_DECREF(tuple);
00302     }
00303 
00304     if (verifyResult & RPMVERIFY_RDEV) {
00305         if (!s->rdevs) {
00306             headerGetEntry(s->h, RPMTAG_FILERDEVS, &type, (void **) &s->rdevs,
00307                      &count);
00308         }
00309 
00310         tuple = PyTuple_New(3);
00311         attrName = PyString_FromString("device");
00312 
00313         PyTuple_SetItem(tuple, 0, attrName);
00314         sprintf(buf, "0x%-4x", s->rdevs[fileNumber]);
00315         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
00316         sprintf(buf, "0x%-4x", (unsigned int) sb.st_rdev);
00317         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
00318         PyList_Append(list, tuple);
00319         Py_DECREF(tuple);
00320     }
00321 
00322     /* RPMVERIFY_USER and RPM_VERIFY_GROUP are handled wrong here, but rpmlib.a
00323        doesn't do these correctly either. At least this is consisten */
00324     if (verifyResult & RPMVERIFY_USER) {
00325         if (!s->uids) {
00326             headerGetEntry(s->h, RPMTAG_FILEUIDS, &type, (void **) &s->uids,
00327                      &count);
00328         }
00329 
00330         tuple = PyTuple_New(3);
00331         attrName = PyString_FromString("uid");
00332         PyTuple_SetItem(tuple, 0, attrName);
00333         sprintf(buf, "%d", s->uids[fileNumber]);
00334         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
00335         sprintf(buf, "%d", sb.st_uid);
00336         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
00337         PyList_Append(list, tuple);
00338         Py_DECREF(tuple);
00339     }
00340 
00341     if (verifyResult & RPMVERIFY_GROUP) {
00342         if (!s->gids) {
00343             headerGetEntry(s->h, RPMTAG_FILEGIDS, &type, (void **) &s->gids,
00344                      &count);
00345         }
00346 
00347         tuple = PyTuple_New(3);
00348         attrName = PyString_FromString("gid");
00349         PyTuple_SetItem(tuple, 0, attrName);
00350         sprintf(buf, "%d", s->gids[fileNumber]);
00351         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
00352         sprintf(buf, "%d", sb.st_gid);
00353         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
00354         PyList_Append(list, tuple);
00355         Py_DECREF(tuple);
00356     }
00357 
00358     if (verifyResult & RPMVERIFY_MODE) {
00359         if (!s->modes) {
00360             headerGetEntry(s->h, RPMTAG_FILEMODES, &type, (void **) &s->modes,
00361                      &count);
00362         }
00363 
00364         tuple = PyTuple_New(3);
00365         attrName = PyString_FromString("permissions");
00366         PyTuple_SetItem(tuple, 0, attrName);
00367         sprintf(buf, "0%-4o", s->modes[fileNumber]);
00368         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
00369         sprintf(buf, "0%-4o", sb.st_mode);
00370         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
00371         PyList_Append(list, tuple);
00372         Py_DECREF(tuple);
00373     }
00374 
00375     return list;
00376 }
00377 
00380 static PyObject * hdrExpandFilelist(hdrObject * s, PyObject * args) {
00381     expandFilelist (s->h);
00382 
00383     Py_INCREF(Py_None);
00384     return Py_None;
00385 }
00386 
00389 static PyObject * hdrCompressFilelist(hdrObject * s, PyObject * args) {
00390     compressFilelist (s->h);
00391 
00392     Py_INCREF(Py_None);
00393     return Py_None;
00394 }
00395 
00396 /* make a header with _all_ the tags we need */
00399 static void mungeFilelist(Header h)
00400 {
00401     const char ** fileNames = NULL;
00402     int count = 0;
00403 
00404     if (!headerIsEntry (h, RPMTAG_BASENAMES)
00405         || !headerIsEntry (h, RPMTAG_DIRNAMES)
00406         || !headerIsEntry (h, RPMTAG_DIRINDEXES))
00407         compressFilelist(h);
00408     
00409     rpmBuildFileList(h, &fileNames, &count);
00410 
00411     if (fileNames == NULL || count <= 0)
00412         return;
00413 
00414     headerAddEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
00415                         fileNames, count);
00416 
00417     free((void *)fileNames);
00418 }
00419 
00422 static PyObject * hdrFullFilelist(hdrObject * s, PyObject * args) {
00423     mungeFilelist (s->h);
00424 
00425     Py_INCREF(Py_None);
00426     return Py_None;
00427 }
00428 
00431 static struct PyMethodDef hdrMethods[] = {
00432         {"keys",        (PyCFunction) hdrKeyList,       1 },
00433         {"unload",      (PyCFunction) hdrUnload,        METH_VARARGS|METH_KEYWORDS },
00434         {"verifyFile",  (PyCFunction) hdrVerifyFile,    1 },
00435         {"expandFilelist",      (PyCFunction) hdrExpandFilelist,        1 },
00436         {"compressFilelist",    (PyCFunction) hdrCompressFilelist,      1 },
00437         {"fullFilelist",        (PyCFunction) hdrFullFilelist,  1 },
00438         {NULL,          NULL}           /* sentinel */
00439 };
00440 
00443 static PyObject * hdrGetAttr(hdrObject * s, char * name) {
00444     return Py_FindMethod(hdrMethods, (PyObject * ) s, name);
00445 }
00446 
00449 static void hdrDealloc(hdrObject * s) {
00450     if (s->h) headerFree(s->h);
00451     if (s->sigs) headerFree(s->sigs);
00452     if (s->md5list) free(s->md5list);
00453     if (s->fileList) free(s->fileList);
00454     if (s->linkList) free(s->linkList);
00455     PyMem_DEL(s);
00456 }
00457 
00460 static long tagNumFromPyObject (PyObject *item)
00461 {
00462     char * str;
00463     int i;
00464 
00465     if (PyInt_Check(item)) {
00466         return PyInt_AsLong(item);
00467     } else if (PyString_Check(item)) {
00468         str = PyString_AsString(item);
00469         for (i = 0; i < rpmTagTableSize; i++)
00470             if (!xstrcasecmp(rpmTagTable[i].name + 7, str)) break;
00471         if (i < rpmTagTableSize) return rpmTagTable[i].val;
00472     }
00473     return -1;
00474 }
00475 
00478 static PyObject * hdrSubscript(hdrObject * s, PyObject * item) {
00479     int type, count, i, tag = -1;
00480     void * data;
00481     PyObject * o, * metao;
00482     char ** stringArray;
00483     int forceArray = 0;
00484     int freeData = 0;
00485     char * str;
00486     struct headerSprintfExtension * ext = NULL;
00487     const struct headerSprintfExtension * extensions = rpmHeaderFormats;
00488 
00489     if (PyCObject_Check (item))
00490         ext = PyCObject_AsVoidPtr(item);
00491     else
00492         tag = tagNumFromPyObject (item);
00493     if (tag == -1 && PyString_Check(item)) {
00494         /* if we still don't have the tag, go looking for the header
00495            extensions */
00496         str = PyString_AsString(item);
00497         while (extensions->name) {
00498             if (extensions->type == HEADER_EXT_TAG
00499                 && !xstrcasecmp(extensions->name + 7, str)) {
00500                 (const struct headerSprintfExtension *) ext = extensions;
00501             }
00502             extensions++;
00503         }
00504     }
00505 
00506     if (ext) {
00507         ext->u.tagFunction(s->h, &type, (const void **) &data, &count, &freeData);
00508     } else {
00509         if (tag == -1) {
00510             PyErr_SetString(PyExc_KeyError, "unknown header tag");
00511             return NULL;
00512         }
00513         
00514         if (!rpmPackageGetEntry(NULL, s->sigs, s->h, tag, &type, &data, &count))
00515         {
00516             Py_INCREF(Py_None);
00517             return Py_None;
00518         }
00519     }
00520 
00521     switch (tag) {
00522       case RPMTAG_OLDFILENAMES:
00523       case RPMTAG_FILESIZES:
00524       case RPMTAG_FILESTATES:
00525       case RPMTAG_FILEMODES:
00526       case RPMTAG_FILEUIDS:
00527       case RPMTAG_FILEGIDS:
00528       case RPMTAG_FILERDEVS:
00529       case RPMTAG_FILEMTIMES:
00530       case RPMTAG_FILEMD5S:
00531       case RPMTAG_FILELINKTOS:
00532       case RPMTAG_FILEFLAGS:
00533       case RPMTAG_ROOT:
00534       case RPMTAG_FILEUSERNAME:
00535       case RPMTAG_FILEGROUPNAME:
00536         forceArray = 1;
00537         break;
00538       case RPMTAG_SUMMARY:
00539       case RPMTAG_GROUP:
00540       case RPMTAG_DESCRIPTION:
00541         freeData = 1;
00542         break;
00543       default:
00544         break;
00545     }
00546 
00547     switch (type) {
00548       case RPM_BIN_TYPE:
00549         o = PyString_FromStringAndSize(data, count);
00550         break;
00551 
00552       case RPM_INT32_TYPE:
00553         if (count != 1 || forceArray) {
00554             metao = PyList_New(0);
00555             for (i = 0; i < count; i++) {
00556                 o = PyInt_FromLong(((int *) data)[i]);
00557                 PyList_Append(metao, o);
00558                 Py_DECREF(o);
00559             }
00560             o = metao;
00561         } else {
00562             o = PyInt_FromLong(*((int *) data));
00563         }
00564         break;
00565 
00566       case RPM_CHAR_TYPE:
00567       case RPM_INT8_TYPE:
00568         if (count != 1 || forceArray) {
00569             metao = PyList_New(0);
00570             for (i = 0; i < count; i++) {
00571                 o = PyInt_FromLong(((char *) data)[i]);
00572                 PyList_Append(metao, o);
00573                 Py_DECREF(o);
00574             }
00575             o = metao;
00576         } else {
00577             o = PyInt_FromLong(*((char *) data));
00578         }
00579         break;
00580 
00581       case RPM_INT16_TYPE:
00582         if (count != 1 || forceArray) {
00583             metao = PyList_New(0);
00584             for (i = 0; i < count; i++) {
00585                 o = PyInt_FromLong(((short *) data)[i]);
00586                 PyList_Append(metao, o);
00587                 Py_DECREF(o);
00588             }
00589             o = metao;
00590         } else {
00591             o = PyInt_FromLong(*((short *) data));
00592         }
00593         break;
00594 
00595       case RPM_STRING_ARRAY_TYPE:
00596         stringArray = data;
00597 
00598         metao = PyList_New(0);
00599         for (i = 0; i < count; i++) {
00600             o = PyString_FromString(stringArray[i]);
00601             PyList_Append(metao, o);
00602             Py_DECREF(o);
00603         }
00604         free (stringArray);
00605         o = metao;
00606         break;
00607 
00608       case RPM_STRING_TYPE:
00609         if (count != 1 || forceArray) {
00610             stringArray = data;
00611 
00612             metao = PyList_New(0);
00613             for (i=0; i < count; i++) {
00614                 o = PyString_FromString(stringArray[i]);
00615                 PyList_Append(metao, o);
00616                 Py_DECREF(o);
00617             }
00618             o = metao;
00619         } else {
00620             o = PyString_FromString(data);
00621             if (freeData)
00622                 free (data);
00623         }
00624         break;
00625 
00626       default:
00627         PyErr_SetString(PyExc_TypeError, "unsupported type in header");
00628         return NULL;
00629     }
00630 
00631     return o;
00632 }
00633 
00636 static PyMappingMethods hdrAsMapping = {
00637         (inquiry) 0,                    /* mp_length */
00638         (binaryfunc) hdrSubscript,      /* mp_subscript */
00639         (objobjargproc)0,               /* mp_ass_subscript */
00640 };
00641 
00644 static PyTypeObject hdrType = {
00645         PyObject_HEAD_INIT(&PyType_Type)
00646         0,                              /* ob_size */
00647         "header",                       /* tp_name */
00648         sizeof(hdrObject),              /* tp_size */
00649         0,                              /* tp_itemsize */
00650         (destructor) hdrDealloc,        /* tp_dealloc */
00651         0,                              /* tp_print */
00652         (getattrfunc) hdrGetAttr,       /* tp_getattr */
00653         0,                              /* tp_setattr */
00654         0,                              /* tp_compare */
00655         0,                              /* tp_repr */
00656         0,                              /* tp_as_number */
00657         0,                              /* tp_as_sequence */
00658         &hdrAsMapping,                  /* tp_as_mapping */
00659 };
00660 
00673 
00676 struct rpmdbObject_s {
00677     PyObject_HEAD;
00678     rpmdb db;
00679     int offx;
00680     int noffs;
00681     int *offsets;
00682 } ;
00683 
00686 struct rpmdbMIObject_s {
00687     PyObject_HEAD;
00688     rpmdbObject *db;
00689     rpmdbMatchIterator mi;
00690 } ;
00691 
00694 static PyObject *
00695 rpmdbMINext(rpmdbMIObject * s, PyObject * args) {
00696     /* XXX assume header? */
00697     Header h;
00698     hdrObject * ho;
00699     
00700 
00701     h = rpmdbNextIterator(s->mi);
00702     if (!h) {
00703         Py_INCREF(Py_None);
00704         return Py_None;
00705     }
00706 
00707     ho = PyObject_NEW(hdrObject, &hdrType);
00708     ho->h = headerLink(h);
00709     ho->sigs = NULL;
00710     ho->fileList = ho->linkList = ho->md5list = NULL;
00711     ho->uids = ho->gids = ho->mtimes = ho->fileSizes = NULL;
00712     ho->modes = ho->rdevs = NULL;
00713     
00714     return (PyObject *) ho;
00715 }
00716 
00719 static struct PyMethodDef rpmdbMIMethods[] = {
00720         {"next",            (PyCFunction) rpmdbMINext,  1 },
00721         {NULL,          NULL}           /* sentinel */
00722 };
00723 
00726 static PyObject * rpmdbMIGetAttr (rpmdbObject *s, char *name) {
00727     return Py_FindMethod (rpmdbMIMethods, (PyObject *) s, name);
00728 }
00729 
00732 static void rpmdbMIDealloc(rpmdbMIObject * s) {
00733     if (s && s->mi) {
00734         rpmdbFreeIterator(s->mi);
00735     }
00736     Py_DECREF (s->db);
00737     PyMem_DEL(s);
00738 }
00739 
00742 static PyTypeObject rpmdbMIType = {
00743         PyObject_HEAD_INIT(&PyType_Type)
00744         0,                              /* ob_size */
00745         "rpmdbMatchIterator",           /* tp_name */
00746         sizeof(rpmdbMIObject),  /* tp_size */
00747         0,                              /* tp_itemsize */
00748         (destructor) rpmdbMIDealloc,    /* tp_dealloc */
00749         0,                              /* tp_print */
00750         (getattrfunc) rpmdbMIGetAttr,   /* tp_getattr */
00751         0,                              /* tp_setattr */
00752         0,                              /* tp_compare */
00753         0,                              /* tp_repr */
00754         0,                              /* tp_as_number */
00755         0,                              /* tp_as_sequence */
00756         0,                              /* tp_as_mapping */
00757 };
00758 
00827 
00830 static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args) {
00831     int first;
00832 
00833     if (!PyArg_ParseTuple (args, "")) return NULL;
00834 
00835     /* Acquire all offsets in one fell swoop. */
00836     if (s->offsets == NULL || s->noffs <= 0) {
00837         rpmdbMatchIterator mi;
00838         Header h;
00839 
00840         if (s->offsets)
00841             free(s->offsets);
00842         s->offsets = NULL;
00843         s->noffs = 0;
00844         mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
00845         while ((h = rpmdbNextIterator(mi)) != NULL) {
00846             s->noffs++;
00847             s->offsets = realloc(s->offsets, s->noffs * sizeof(s->offsets[0]));
00848             s->offsets[s->noffs-1] = rpmdbGetIteratorOffset(mi);
00849         }
00850         rpmdbFreeIterator(mi);
00851     }
00852 
00853     s->offx = 0;
00854     if (s->offsets != NULL && s->offx < s->noffs)
00855         first = s->offsets[s->offx++];
00856     else
00857         first = 0;
00858 
00859     if (!first) {
00860         PyErr_SetString(pyrpmError, "cannot find first entry in database\n");
00861         return NULL;
00862     }
00863 
00864     return Py_BuildValue("i", first);
00865 }
00866 
00869 static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args) {
00870     int where;
00871 
00872     if (!PyArg_ParseTuple (args, "i", &where)) return NULL;
00873 
00874     if (s->offsets == NULL || s->offx >= s->noffs) {
00875         Py_INCREF(Py_None);
00876         return Py_None;
00877     }
00878 
00879     where = s->offsets[s->offx++];
00880 
00881     if (!where) {
00882         Py_INCREF(Py_None);
00883         return Py_None;
00884     }
00885 
00886     return Py_BuildValue("i", where);
00887 }
00888 
00891 static PyObject * handleDbResult(rpmdbMatchIterator mi) {
00892     PyObject * list, *o;
00893 
00894     list = PyList_New(0);
00895 
00896     /* XXX FIXME: unnecessary header mallocs are side effect here */
00897     if (mi != NULL) {
00898         while (rpmdbNextIterator(mi)) {
00899             PyList_Append(list, o=PyInt_FromLong(rpmdbGetIteratorOffset(mi)));
00900             Py_DECREF(o);
00901         }
00902         rpmdbFreeIterator(mi);
00903     }
00904 
00905     return list;
00906 }
00907 
00910 static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args) {
00911     char * str;
00912 
00913     if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
00914 
00915     return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_BASENAMES, str, 0));
00916 }
00917 
00920 static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args) {
00921     char * str;
00922 
00923     if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
00924 
00925     return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_NAME, str, 0));
00926 }
00927 
00930 static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args) {
00931     char * str;
00932 
00933     if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
00934 
00935     return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_PROVIDENAME, str, 0));
00936 }
00937 
00940 static rpmdbMIObject *
00941 py_rpmdbInitIterator (rpmdbObject * s, PyObject * args) {
00942     PyObject *index = NULL;
00943     char *key = NULL;
00944     int len = 0, tag = -1;
00945     rpmdbMIObject * mio;
00946     
00947     if (!PyArg_ParseTuple(args, "|Ozi", &index, &key, &len))
00948         return NULL;
00949 
00950     if (index == NULL)
00951         tag = 0;
00952     else if ((tag = tagNumFromPyObject (index)) == -1) {
00953         PyErr_SetString(PyExc_TypeError, "unknown tag type");
00954         return NULL;
00955     }
00956     
00957     mio = (rpmdbMIObject *) PyObject_NEW(rpmdbMIObject, &rpmdbMIType);
00958     if (mio == NULL) {
00959         PyErr_SetString(pyrpmError, "out of memory creating rpmdbMIObject");
00960         return NULL;
00961     }
00962     
00963     mio->mi = rpmdbInitIterator(s->db, tag, key, len);
00964     mio->db = s;
00965     Py_INCREF (mio->db);
00966     
00967     return mio;
00968 }
00969 
00972 static struct PyMethodDef rpmdbMethods[] = {
00973         {"firstkey",        (PyCFunction) rpmdbFirst,   1 },
00974         {"nextkey",         (PyCFunction) rpmdbNext,    1 },
00975         {"findbyfile",      (PyCFunction) rpmdbByFile, 1 },
00976         {"findbyname",      (PyCFunction) rpmdbByName, 1 },
00977         {"findbyprovides",  (PyCFunction) rpmdbByProvides, 1 },
00978         {"match",           (PyCFunction) py_rpmdbInitIterator, 1 },
00979         {NULL,          NULL}           /* sentinel */
00980 };
00981 
00984 static PyObject * rpmdbGetAttr(rpmdbObject * s, char * name) {
00985     return Py_FindMethod(rpmdbMethods, (PyObject * ) s, name);
00986 }
00987 
00990 static void rpmdbDealloc(rpmdbObject * s) {
00991     if (s->offsets) {
00992         free(s->offsets);
00993     }
00994     if (s->db) {
00995         rpmdbClose(s->db);
00996     }
00997     PyMem_DEL(s);
00998 }
00999 
01000 #ifndef DYINGSOON
01001 
01003 static int
01004 rpmdbLength(rpmdbObject * s) {
01005     int count = 0;
01006 
01007     {   rpmdbMatchIterator mi;
01008 
01009         /* RPMDBI_PACKAGES */
01010         mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
01011         /* XXX FIXME: unnecessary header mallocs are side effect here */
01012         while (rpmdbNextIterator(mi) != NULL)
01013             count++;
01014         rpmdbFreeIterator(mi);
01015     }
01016 
01017     return count;
01018 }
01019 
01022 static hdrObject *
01023 rpmdbSubscript(rpmdbObject * s, PyObject * key) {
01024     int offset;
01025     hdrObject * h;
01026 
01027     if (!PyInt_Check(key)) {
01028         PyErr_SetString(PyExc_TypeError, "integer expected");
01029         return NULL;
01030     }
01031 
01032     offset = (int) PyInt_AsLong(key);
01033 
01034     h = PyObject_NEW(hdrObject, &hdrType);
01035     h->h = NULL;
01036     h->sigs = NULL;
01037     {   rpmdbMatchIterator mi;
01038         mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, &offset, sizeof(offset));
01039         if ((h->h = rpmdbNextIterator(mi)) != NULL)
01040             h->h = headerLink(h->h);
01041         rpmdbFreeIterator(mi);
01042     }
01043     h->fileList = h->linkList = h->md5list = NULL;
01044     h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
01045     h->modes = h->rdevs = NULL;
01046     if (!h->h) {
01047         Py_DECREF(h);
01048         PyErr_SetString(pyrpmError, "cannot read rpmdb entry");
01049         return NULL;
01050     }
01051 
01052     return h;
01053 }
01054 
01057 static PyMappingMethods rpmdbAsMapping = {
01058         (inquiry) rpmdbLength,          /* mp_length */
01059         (binaryfunc) rpmdbSubscript,    /* mp_subscript */
01060         (objobjargproc)0,               /* mp_ass_subscript */
01061 };
01062 #endif
01063 
01066 static PyTypeObject rpmdbType = {
01067         PyObject_HEAD_INIT(&PyType_Type)
01068         0,                              /* ob_size */
01069         "rpmdb",                        /* tp_name */
01070         sizeof(rpmdbObject),            /* tp_size */
01071         0,                              /* tp_itemsize */
01072         (destructor) rpmdbDealloc,      /* tp_dealloc */
01073         0,                              /* tp_print */
01074         (getattrfunc) rpmdbGetAttr,     /* tp_getattr */
01075         0,                              /* tp_setattr */
01076         0,                              /* tp_compare */
01077         0,                              /* tp_repr */
01078         0,                              /* tp_as_number */
01079         0,                              /* tp_as_sequence */
01080 #ifndef DYINGSOON
01081         &rpmdbAsMapping,                /* tp_as_mapping */
01082 #else
01083         0,
01084 #endif
01085 };
01086 
01191 
01194 struct rpmtransObject_s {
01195     PyObject_HEAD;
01196     rpmdbObject * dbo;
01197     rpmTransactionSet ts;
01198     PyObject * keyList;                 /* keeps reference counts correct */
01199     FD_t scriptFd;
01200 } ;
01201 
01204 static PyObject * rpmtransAdd(rpmtransObject * s, PyObject * args) {
01205     hdrObject * h;
01206     PyObject * key;
01207     char * how = NULL;
01208     int isUpgrade = 0;
01209 
01210     if (!PyArg_ParseTuple(args, "OO|s", &h, &key, &how)) return NULL;
01211     if (h->ob_type != &hdrType) {
01212         PyErr_SetString(PyExc_TypeError, "bad type for header argument");
01213         return NULL;
01214     }
01215 
01216     if (how && strcmp(how, "a") && strcmp(how, "u") && strcmp(how, "i")) {
01217         PyErr_SetString(PyExc_TypeError, "how argument must be \"u\", \"a\", or \"i\"");
01218         return NULL;
01219     } else if (how && !strcmp(how, "u"))
01220         isUpgrade = 1;
01221 
01222     if (how && !strcmp(how, "a"))
01223         rpmtransAvailablePackage(s->ts, h->h, key);
01224     else
01225         rpmtransAddPackage(s->ts, h->h, NULL, key, isUpgrade, NULL);
01226 
01227     /* This should increment the usage count for me */
01228     if (key) {
01229         PyList_Append(s->keyList, key);
01230     }
01231 
01232     Py_INCREF(Py_None);
01233     return Py_None;
01234 }
01235 
01238 static PyObject * rpmtransRemove(rpmtransObject * s, PyObject * args) {
01239     char * name;
01240     int count;
01241     rpmdbMatchIterator mi;
01242     
01243     if (!PyArg_ParseTuple(args, "s", &name))
01244         return NULL;
01245 
01246     /* XXX: Copied hack from ../lib/rpminstall.c, rpmErase() */
01247     mi = rpmdbInitIterator(s->dbo->db, RPMDBI_LABEL, name, 0);
01248     count = rpmdbGetIteratorCount(mi);
01249     if (count <= 0) {
01250         PyErr_SetString(pyrpmError, "package not installed");
01251         return NULL;
01252     } else { /* XXX: Note that we automatically choose to remove all matches */
01253         Header h;
01254         while ((h = rpmdbNextIterator(mi)) != NULL) {
01255             unsigned int recOffset = rpmdbGetIteratorOffset(mi);
01256             if (recOffset) {
01257                 rpmtransRemovePackage(s->ts, recOffset);
01258             }
01259         }
01260     }
01261     rpmdbFreeIterator(mi);
01262 
01263     Py_INCREF(Py_None);
01264     return Py_None;
01265 }
01266 
01269 static PyObject * rpmtransDepCheck(rpmtransObject * s, PyObject * args) {
01270     struct rpmDependencyConflict * conflicts;
01271     int numConflicts;
01272     PyObject * list, * cf;
01273     int i;
01274 
01275     if (!PyArg_ParseTuple(args, "")) return NULL;
01276 
01277     rpmdepCheck(s->ts, &conflicts, &numConflicts);
01278     if (numConflicts) {
01279         list = PyList_New(0);
01280 
01281         for (i = 0; i < numConflicts; i++) {
01282             cf = Py_BuildValue("((sss)(ss)iOi)", conflicts[i].byName,
01283                                conflicts[i].byVersion, conflicts[i].byRelease,
01284 
01285                                conflicts[i].needsName,
01286                                conflicts[i].needsVersion,
01287 
01288                                conflicts[i].needsFlags,
01289                                conflicts[i].suggestedPackage ?
01290                                    conflicts[i].suggestedPackage : Py_None,
01291                                conflicts[i].sense);
01292             PyList_Append(list, (PyObject *) cf);
01293             Py_DECREF(cf);
01294         }
01295 
01296         rpmdepFreeConflicts(conflicts, numConflicts);
01297 
01298         return list;
01299     }
01300 
01301     Py_INCREF(Py_None);
01302     return Py_None;
01303 }
01304 
01307 static PyObject * rpmtransOrder(rpmtransObject * s, PyObject * args) {
01308     if (!PyArg_ParseTuple(args, "")) return NULL;
01309 
01310     rpmdepOrder(s->ts);
01311 
01312     Py_INCREF(Py_None);
01313     return Py_None;
01314 }
01315 
01318 static PyObject * py_rpmtransGetKeys(rpmtransObject * s, PyObject * args) {
01319     const void **data = NULL;
01320     int num, i;
01321     PyObject *tuple;
01322 
01323     rpmtransGetKeys(s->ts, &data, &num);
01324     if (data == NULL) {
01325         Py_INCREF(Py_None);
01326         return Py_None;
01327     }
01328 
01329     tuple = PyTuple_New(num);
01330 
01331     for (i = 0; i < num; i++) {
01332         PyObject *obj = (PyObject *) data[i];
01333         Py_INCREF(obj);
01334         PyTuple_SetItem(tuple, i, obj);
01335     }
01336 
01337     free (data);
01338 
01339     return tuple;
01340 }
01341 
01344 struct tsCallbackType {
01345     PyObject * cb;
01346     PyObject * data;
01347     int pythonError;
01348 };
01349 
01352 static Header transactionSetHeader = NULL;
01353 
01356 static void * tsCallback(const void * hd, const rpmCallbackType what,
01357                          const unsigned long amount, const unsigned long total,
01358                          const void * pkgKey, rpmCallbackData data) {
01359     struct tsCallbackType * cbInfo = data;
01360     PyObject * args, * result;
01361     int fd;
01362     static FD_t fdt;
01363     const Header h = (Header) hd;
01364 
01365     if (cbInfo->pythonError) return NULL;
01366 
01367     if (!pkgKey) pkgKey = Py_None;
01368     transactionSetHeader = h;    
01369 
01370     args = Py_BuildValue("(illOO)", what, amount, total, pkgKey, cbInfo->data);
01371     result = PyEval_CallObject(cbInfo->cb, args);
01372     Py_DECREF(args);
01373 
01374     if (!result) {
01375         cbInfo->pythonError = 1;
01376         return NULL;
01377     }
01378 
01379     if (what == RPMCALLBACK_INST_OPEN_FILE) {
01380         if (!PyArg_Parse(result, "i", &fd)) {
01381             cbInfo->pythonError = 1;
01382             return NULL;
01383         }
01384         fdt = fdDup(fd);
01385         
01386         Py_DECREF(result);
01387         return fdt;
01388     }
01389 
01390     if (what == RPMCALLBACK_INST_CLOSE_FILE) {
01391         Fclose (fdt);
01392     }
01393 
01394     Py_DECREF(result);
01395 
01396     return NULL;
01397 }
01398 
01401 static PyObject * rpmtransRun(rpmtransObject * s, PyObject * args) {
01402     int flags, ignoreSet;
01403     int rc, i;
01404     PyObject * list, * prob;
01405     rpmProblemSet probs;
01406     struct tsCallbackType cbInfo;
01407 
01408     if (!PyArg_ParseTuple(args, "iiOO", &flags, &ignoreSet, &cbInfo.cb,
01409                           &cbInfo.data))
01410         return NULL;
01411 
01412     cbInfo.pythonError = 0;
01413 
01414     rc = rpmRunTransactions(s->ts, tsCallback, &cbInfo, NULL, &probs, flags,
01415                             ignoreSet);
01416 
01417     if (cbInfo.pythonError) {
01418         if (rc > 0)
01419             rpmProblemSetFree(probs);
01420         return NULL;
01421     }
01422 
01423     if (rc < 0) {
01424         list = PyList_New(0);
01425         return list;
01426     } else if (!rc) {
01427         Py_INCREF(Py_None);
01428         return Py_None;
01429     }
01430 
01431     list = PyList_New(0);
01432     for (i = 0; i < probs->numProblems; i++) {
01433         rpmProblem myprob = probs->probs + i;
01434         prob = Py_BuildValue("s(isi)", rpmProblemString(myprob),
01435                              myprob->type,
01436                              myprob->str1,
01437                              myprob->ulong1);
01438         PyList_Append(list, prob);
01439         Py_DECREF(prob);
01440     }
01441 
01442     rpmProblemSetFree(probs);
01443 
01444     return list;
01445 }
01446 
01449 static struct PyMethodDef rpmtransMethods[] = {
01450         {"add",         (PyCFunction) rpmtransAdd,      1 },
01451         {"remove",      (PyCFunction) rpmtransRemove,   1 },
01452         {"depcheck",    (PyCFunction) rpmtransDepCheck, 1 },
01453         {"order",       (PyCFunction) rpmtransOrder,    1 },
01454         {"getKeys",     (PyCFunction) py_rpmtransGetKeys, 1 },
01455         {"run",         (PyCFunction) rpmtransRun, 1 },
01456         {NULL,          NULL}           /* sentinel */
01457 };
01458 
01461 static PyObject * rpmtransGetAttr(rpmtransObject * o, char * name) {
01462     return Py_FindMethod(rpmtransMethods, (PyObject *) o, name);
01463 }
01464 
01467 static void rpmtransDealloc(PyObject * o) {
01468     rpmtransObject * trans = (void *) o;
01469 
01470     rpmtransFree(trans->ts);
01471     if (trans->dbo) {
01472         Py_DECREF(trans->dbo);
01473     }
01474     if (trans->scriptFd) Fclose(trans->scriptFd);
01475     /* this will free the keyList, and decrement the ref count of all
01476        the items on the list as well :-) */
01477     Py_DECREF(trans->keyList);
01478     PyMem_DEL(o);
01479 }
01480 
01483 static int rpmtransSetAttr(rpmtransObject * o, char * name,
01484                            PyObject * val) {
01485     int i;
01486 
01487     if (!strcmp(name, "scriptFd")) {
01488         if (!PyArg_Parse(val, "i", &i)) return 0;
01489         if (i < 0) {
01490             PyErr_SetString(PyExc_TypeError, "bad file descriptor");
01491             return -1;
01492         } else {
01493             o->scriptFd = fdDup(i);
01494             rpmtransSetScriptFd(o->ts, o->scriptFd);
01495         }
01496     } else {
01497         PyErr_SetString(PyExc_AttributeError, name);
01498         return -1;
01499     }
01500 
01501     return 0;
01502 }
01503 
01506 static PyTypeObject rpmtransType = {
01507         PyObject_HEAD_INIT(&PyType_Type)
01508         0,                              /* ob_size */
01509         "rpmtrans",                     /* tp_name */
01510         sizeof(rpmtransObject),         /* tp_size */
01511         0,                              /* tp_itemsize */
01512         (destructor) rpmtransDealloc,   /* tp_dealloc */
01513         0,                              /* tp_print */
01514         (getattrfunc) rpmtransGetAttr,  /* tp_getattr */
01515         (setattrfunc) rpmtransSetAttr,  /* tp_setattr */
01516         0,                              /* tp_compare */
01517         0,                              /* tp_repr */
01518         0,                              /* tp_as_number */
01519         0,                              /* tp_as_sequence */
01520         0,                              /* tp_as_mapping */
01521 };
01522 
01529 
01532 static PyObject * rpmtransCreate(PyObject * self, PyObject * args) {
01533     rpmtransObject * o;
01534     rpmdbObject * db = NULL;
01535     char * rootPath = "/";
01536 
01537     if (!PyArg_ParseTuple(args, "|sO", &rootPath, &db)) return NULL;
01538     if (db && db->ob_type != &rpmdbType) {
01539         PyErr_SetString(PyExc_TypeError, "bad type for database argument");
01540         return NULL;
01541     }
01542 
01543     o = (void *) PyObject_NEW(rpmtransObject, &rpmtransType);
01544 
01545     Py_XINCREF(db);
01546     o->dbo = db;
01547     o->scriptFd = NULL;
01548     o->ts = rpmtransCreateSet(db ? db->db : NULL, rootPath);
01549     o->keyList = PyList_New(0);
01550 
01551     return (void *) o;
01552 }
01553 
01556 static PyObject * doAddMacro(PyObject * self, PyObject * args) {
01557     char * name, * val;
01558 
01559     if (!PyArg_ParseTuple(args, "ss", &name, &val))
01560         return NULL;
01561 
01562     addMacro(NULL, name, NULL, val, RMIL_DEFAULT);
01563 
01564     Py_INCREF(Py_None);
01565     return Py_None;
01566 }
01567 
01570 static PyObject * doDelMacro(PyObject * self, PyObject * args) {
01571     char * name;
01572 
01573     if (!PyArg_ParseTuple(args, "s", &name))
01574         return NULL;
01575 
01576     delMacro(NULL, name);
01577 
01578     Py_INCREF(Py_None);
01579     return Py_None;
01580 }
01581 
01584 static PyObject * archScore(PyObject * self, PyObject * args) {
01585     char * arch;
01586     int score;
01587 
01588     if (!PyArg_ParseTuple(args, "s", &arch))
01589         return NULL;
01590 
01591     score = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
01592 
01593     return Py_BuildValue("i", score);
01594 }
01595 
01598 static int psGetArchScore(Header h) {
01599     void * pkgArch;
01600     int type, count;
01601 
01602     if (!headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count) ||
01603         type == RPM_INT8_TYPE)
01604        return 150;
01605     else
01606         return rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch);
01607 }
01608 
01611 static int pkgCompareVer(void * first, void * second) {
01612     struct packageInfo ** a = first;
01613     struct packageInfo ** b = second;
01614     int ret, score1, score2;
01615 
01616     /* put packages w/o names at the end */
01617     if (!(*a)->name) return 1;
01618     if (!(*b)->name) return -1;
01619 
01620     ret = xstrcasecmp((*a)->name, (*b)->name);
01621     if (ret) return ret;
01622     score1 = psGetArchScore((*a)->h);
01623     if (!score1) return 1;
01624     score2 = psGetArchScore((*b)->h);
01625     if (!score2) return -1;
01626     if (score1 < score2) return -1;
01627     if (score1 > score2) return 1;
01628     return rpmVersionCompare((*b)->h, (*a)->h);
01629 }
01630 
01633 static void pkgSort(struct pkgSet * psp) {
01634     int i;
01635     char *name;
01636 
01637     qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
01638          (void *) pkgCompareVer);
01639 
01640     name = psp->packages[0]->name;
01641     if (!name) {
01642        psp->numPackages = 0;
01643        return;
01644     }
01645     for (i = 1; i < psp->numPackages; i++) {
01646        if (!psp->packages[i]->name) break;
01647        if (!strcmp(psp->packages[i]->name, name))
01648            psp->packages[i]->name = NULL;
01649        else
01650            name = psp->packages[i]->name;
01651     }
01652 
01653     qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
01654          (void *) pkgCompareVer);
01655 
01656     for (i = 0; i < psp->numPackages; i++)
01657        if (!psp->packages[i]->name) break;
01658     psp->numPackages = i;
01659 }
01660 
01663 static PyObject * findUpgradeSet(PyObject * self, PyObject * args) {
01664     PyObject * hdrList, * result;
01665     char * root = "/";
01666     int i;
01667     struct pkgSet list;
01668     hdrObject * hdr;
01669 
01670     if (!PyArg_ParseTuple(args, "O|s", &hdrList, &root)) return NULL;
01671 
01672     if (!PyList_Check(hdrList)) {
01673         PyErr_SetString(PyExc_TypeError, "list of headers expected");
01674         return NULL;
01675     }
01676 
01677     list.numPackages = PyList_Size(hdrList);
01678     list.packages = alloca(sizeof(list.packages) * list.numPackages);
01679     for (i = 0; i < list.numPackages; i++) {
01680         hdr = (hdrObject *) PyList_GetItem(hdrList, i);
01681         if (hdr->ob_type != &hdrType) {
01682             PyErr_SetString(PyExc_TypeError, "list of headers expected");
01683             return NULL;
01684         }
01685         list.packages[i] = alloca(sizeof(struct packageInfo));
01686         list.packages[i]->h = hdr->h;
01687         list.packages[i]->selected = 0;
01688         list.packages[i]->data = hdr;
01689 
01690         headerGetEntry(hdr->h, RPMTAG_NAME, NULL,
01691                       (void **) &list.packages[i]->name, NULL);
01692     }
01693 
01694     pkgSort (&list);
01695 
01696     if (ugFindUpgradePackages(&list, root)) {
01697         PyErr_SetString(pyrpmError, "error during upgrade check");
01698         return NULL;
01699     }
01700 
01701     result = PyList_New(0);
01702     for (i = 0; i < list.numPackages; i++) {
01703         if (list.packages[i]->selected) {
01704             PyList_Append(result, list.packages[i]->data);
01705 /*          Py_DECREF(list.packages[i]->data); */
01706         }
01707     }
01708 
01709     return result;
01710 }
01711 
01714 static PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args) {
01715     hdrObject * h;
01716     Header header;
01717     Header sigs;
01718     FD_t fd;
01719     int rawFd;
01720     int isSource = 0;
01721     rpmRC rc;
01722 
01723     if (!PyArg_ParseTuple(args, "i", &rawFd)) return NULL;
01724     fd = fdDup(rawFd);
01725 
01726     rc = rpmReadPackageInfo(fd, &sigs, &header);
01727     Fclose(fd);
01728 
01729     switch (rc) {
01730     case RPMRC_BADSIZE:
01731     case RPMRC_OK:
01732         h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
01733         h->h = header;
01734         h->sigs = sigs;
01735         h->fileList = h->linkList = h->md5list = NULL;
01736         h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
01737         h->modes = h->rdevs = NULL;
01738         if (headerIsEntry(header, RPMTAG_SOURCEPACKAGE))
01739             isSource = 1;
01740         break;
01741 
01742     case RPMRC_BADMAGIC:
01743         Py_INCREF(Py_None);
01744         h = (hdrObject *) Py_None;
01745         break;
01746 
01747     case RPMRC_FAIL:
01748     case RPMRC_SHORTREAD:
01749     default:
01750         PyErr_SetString(pyrpmError, "error reading package");
01751         return NULL;
01752     }
01753 
01754     return Py_BuildValue("(Ni)", h, isSource);
01755 }
01756 
01759 static PyObject * hdrLoad(PyObject * self, PyObject * args) {
01760     char * obj, * copy=NULL;
01761     Header hdr;
01762     hdrObject * h;
01763     int len;
01764 
01765     if (!PyArg_ParseTuple(args, "s#", &obj, &len)) return NULL;
01766     
01767     copy = malloc(len);
01768     if (copy == NULL) {
01769         PyErr_SetString(pyrpmError, "out of memory");
01770         return NULL;
01771     }
01772 
01773     memcpy (copy, obj, len);
01774 
01775     hdr = headerLoad(copy);
01776     if (!hdr) {
01777         PyErr_SetString(pyrpmError, "bad header");
01778         return NULL;
01779     }
01780     compressFilelist (hdr);
01781     providePackageNVR (hdr);
01782 
01783     h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
01784     h->h = hdr;
01785     h->sigs = NULL;
01786     h->fileList = h->linkList = h->md5list = NULL;
01787     h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
01788     h->modes = h->rdevs = NULL;
01789 
01790     return (PyObject *) h;
01791 }
01792 
01795 static PyObject * rpmInitDB(PyObject * self, PyObject * args) {
01796     char *root;
01797     int forWrite = 0;
01798 
01799     if (!PyArg_ParseTuple(args, "i|s", &forWrite, &root)) return NULL;
01800 
01801     if (rpmdbInit(root, forWrite ? O_RDWR | O_CREAT: O_RDONLY)) {
01802         char * errmsg = "cannot initialize database in %s";
01803         char * errstr = NULL;
01804         int errsize;
01805 
01806         errsize = strlen(errmsg) + strlen(root);
01807         errstr = alloca(errsize);
01808         snprintf(errstr, errsize, errmsg, root);
01809         PyErr_SetString(pyrpmError, errstr);
01810         return NULL;
01811     }
01812 
01813     Py_INCREF(Py_None);
01814     return(Py_None);
01815 }
01816 
01819 static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) {
01820     rpmdbObject * o;
01821     char * root = "";
01822     int forWrite = 0;
01823 
01824     if (!PyArg_ParseTuple(args, "|is", &forWrite, &root)) return NULL;
01825 
01826     o = PyObject_NEW(rpmdbObject, &rpmdbType);
01827     o->db = NULL;
01828     o->offx = 0;
01829     o->noffs = 0;
01830     o->offsets = NULL;
01831 
01832     if (rpmdbOpen(root, &o->db, forWrite ? O_RDWR | O_CREAT: O_RDONLY, 0644)) {
01833         char * errmsg = "cannot open database in %s";
01834         char * errstr = NULL;
01835         int errsize;
01836 
01837         Py_DECREF(o);
01838         /* PyErr_SetString should take varargs... */
01839         errsize = strlen(errmsg) + *root == '\0' ? 15 /* "/var/lib/rpm" */ : strlen(root);
01840         errstr = alloca(errsize);
01841         snprintf(errstr, errsize, errmsg, *root == '\0' ? "/var/lib/rpm" : root);
01842         PyErr_SetString(pyrpmError, errstr);
01843         return NULL;
01844     }
01845 
01846     return o;
01847 }
01848 
01851 static PyObject * rebuildDB (PyObject * self, PyObject * args) {
01852     char * root = "";
01853 
01854     if (!PyArg_ParseTuple(args, "s", &root)) return NULL;
01855 
01856     return Py_BuildValue("i", rpmdbRebuild(root));
01857 }
01858 
01861 static PyObject * rpmReadHeaders (FD_t fd) {
01862     PyObject * list;
01863     Header header;
01864     hdrObject * h;
01865 
01866     if (!fd) {
01867         PyErr_SetFromErrno(pyrpmError);
01868         return NULL;
01869     }
01870 
01871     list = PyList_New(0);
01872     Py_BEGIN_ALLOW_THREADS
01873     header = headerRead(fd, HEADER_MAGIC_YES);
01874 
01875     Py_END_ALLOW_THREADS
01876     while (header) {
01877         compressFilelist (header);
01878         providePackageNVR (header);
01879         h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
01880         h->h = header;
01881         h->sigs = NULL;
01882         h->fileList = h->linkList = h->md5list = NULL;
01883         h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
01884         h->modes = h->rdevs = NULL;
01885         if (PyList_Append(list, (PyObject *) h)) {
01886             Py_DECREF(list);
01887             Py_DECREF(h);
01888             return NULL;
01889         }
01890 
01891         Py_DECREF(h);
01892 
01893         Py_BEGIN_ALLOW_THREADS
01894         header = headerRead(fd, HEADER_MAGIC_YES);
01895         Py_END_ALLOW_THREADS
01896     }
01897 
01898     return list;
01899 }
01900 
01903 static PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args) {
01904     FD_t fd;
01905     int fileno;
01906     PyObject * list;
01907 
01908     if (!PyArg_ParseTuple(args, "i", &fileno)) return NULL;
01909     fd = fdDup(fileno);
01910 
01911     list = rpmReadHeaders (fd);
01912     Fclose(fd);
01913 
01914     return list;
01915 }
01916 
01919 static PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args) {
01920     char * filespec;
01921     FD_t fd;
01922     PyObject * list;
01923 
01924     if (!PyArg_ParseTuple(args, "s", &filespec)) return NULL;
01925     fd = Fopen(filespec, "r.fdio");
01926 
01927     if (!fd) {
01928         PyErr_SetFromErrno(pyrpmError);
01929         return NULL;
01930     }
01931 
01932     list = rpmReadHeaders (fd);
01933     Fclose(fd);
01934 
01935     return list;
01936 }
01937 
01942 static int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag) {
01943     Header newH;
01944     HeaderIterator iter;
01945     int_32 * newMatch, * oldMatch;
01946     hdrObject * ho;
01947     int count = 0;
01948     int type, c, tag;
01949     void * p;
01950 
01951     Py_BEGIN_ALLOW_THREADS
01952     newH = headerRead(fd, HEADER_MAGIC_YES);
01953 
01954     Py_END_ALLOW_THREADS
01955     while (newH) {
01956         if (!headerGetEntry(newH, matchTag, NULL, (void **) &newMatch, NULL)) {
01957             PyErr_SetString(pyrpmError, "match tag missing in new header");
01958             return 1;
01959         }
01960 
01961         ho = (hdrObject *) PyList_GetItem(list, count++);
01962         if (!ho) return 1;
01963 
01964         if (!headerGetEntry(ho->h, matchTag, NULL, (void **) &oldMatch, NULL)) {
01965             PyErr_SetString(pyrpmError, "match tag missing in new header");
01966             return 1;
01967         }
01968 
01969         if (*newMatch != *oldMatch) {
01970             PyErr_SetString(pyrpmError, "match tag mismatch");
01971             return 1;
01972         }
01973 
01974         if (ho->sigs) headerFree(ho->sigs);
01975         if (ho->md5list) free(ho->md5list);
01976         if (ho->fileList) free(ho->fileList);
01977         if (ho->linkList) free(ho->linkList);
01978 
01979         ho->sigs = NULL;
01980         ho->md5list = NULL;
01981         ho->fileList = NULL;
01982         ho->linkList = NULL;
01983 
01984         iter = headerInitIterator(newH);
01985 
01986         while (headerNextIterator(iter, &tag, &type, (void *) &p, &c)) {
01987             /* could be dupes */
01988             headerRemoveEntry(ho->h, tag);
01989             headerAddEntry(ho->h, tag, type, p, c);
01990             headerFreeData(p, type);
01991         }
01992 
01993         headerFreeIterator(iter);
01994 
01995         Py_BEGIN_ALLOW_THREADS
01996         newH = headerRead(fd, HEADER_MAGIC_YES);
01997         Py_END_ALLOW_THREADS
01998     }
01999 
02000     return 0;
02001 }
02002 
02003 static PyObject * rpmMergeHeadersFromFD(PyObject * self, PyObject * args) {
02004     FD_t fd;
02005     int fileno;
02006     PyObject * list;
02007     int rc;
02008     int matchTag;
02009 
02010     if (!PyArg_ParseTuple(args, "Oii", &list, &fileno, &matchTag)) return NULL;
02011 
02012     if (!PyList_Check(list)) {
02013         PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
02014         return NULL;
02015     }
02016 
02017     fd = fdDup(fileno);
02018 
02019     rc = rpmMergeHeaders (list, fd, matchTag);
02020     Fclose(fd);
02021 
02022     if (rc) {
02023         return NULL;
02024     }
02025 
02026     Py_INCREF(Py_None);
02027     return Py_None;
02028 }
02029 
02032 static PyObject * errorCB = NULL, * errorData = NULL;
02033 
02036 static void errorcb (void)
02037 {
02038     PyObject * result, * args = NULL;
02039 
02040     if (errorData)
02041         args = Py_BuildValue("(O)", errorData);
02042 
02043     result = PyEval_CallObject(errorCB, args);
02044     Py_XDECREF(args);
02045 
02046     if (result == NULL) {
02047         PyErr_Print();
02048         PyErr_Clear();
02049     }
02050     Py_DECREF (result);
02051 }
02052 
02055 static PyObject * errorSetCallback (PyObject * self, PyObject * args) {
02056     if (errorCB != NULL) {
02057         Py_DECREF (errorCB);
02058         errorCB = NULL;
02059     }
02060 
02061     if (errorData != NULL) {
02062         Py_DECREF (errorData);
02063         errorData = NULL;
02064     }
02065 
02066     if (!PyArg_ParseTuple(args, "O|O", &errorCB, &errorData)) return NULL;
02067 
02068     /* if we're getting a void*, set the error callback to this. */
02069     /* also, we can possibly decref any python callbacks we had  */
02070     /* and set them to NULL.                                     */
02071     if (PyCObject_Check (errorCB)) {
02072         rpmErrorSetCallback (PyCObject_AsVoidPtr(errorCB));
02073 
02074         Py_XDECREF (errorCB);
02075         Py_XDECREF (errorData);
02076 
02077         errorCB   = NULL;
02078         errorData = NULL;
02079         
02080         Py_INCREF(Py_None);
02081         return Py_None;
02082     }
02083     
02084     if (!PyCallable_Check (errorCB)) {
02085         PyErr_SetString(PyExc_TypeError, "parameter must be callable");
02086         return NULL;
02087     }
02088 
02089     Py_INCREF (errorCB);
02090     Py_XINCREF (errorData);
02091 
02092     return PyCObject_FromVoidPtr(rpmErrorSetCallback (errorcb), NULL);
02093 }
02094 
02097 static PyObject * errorString (PyObject * self, PyObject * args) {
02098     return PyString_FromString(rpmErrorString ());
02099 }
02100 
02103 static PyObject * versionCompare (PyObject * self, PyObject * args) {
02104     hdrObject * h1, * h2;
02105 
02106     if (!PyArg_ParseTuple(args, "O!O!", &hdrType, &h1, &hdrType, &h2)) return NULL;
02107 
02108     return Py_BuildValue("i", rpmVersionCompare(h1->h, h2->h));
02109 }
02110 
02113 static PyObject * labelCompare (PyObject * self, PyObject * args) {
02114     char *v1, *r1, *e1, *v2, *r2, *e2;
02115     int rc;
02116 
02117     if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
02118                           &e1, &v1, &r1,
02119                           &e2, &v2, &r2)) return NULL;
02120 
02121     if (e1 && !e2)
02122         return Py_BuildValue("i", 1);
02123     else if (!e1 && e2)
02124         return Py_BuildValue("i", -1);
02125     else if (e1 && e2) {
02126         int ep1, ep2;
02127         ep1 = atoi (e1);
02128         ep2 = atoi (e2);
02129         if (ep1 < ep2)
02130             return Py_BuildValue("i", -1);
02131         else if (ep1 > ep2)
02132             return Py_BuildValue("i", 1);
02133     }
02134 
02135     rc = rpmvercmp(v1, v2);
02136     if (rc)
02137         return Py_BuildValue("i", rc);
02138 
02139     return Py_BuildValue("i", rpmvercmp(r1, r2));
02140 }
02141 
02144 static PyObject * checkSig (PyObject * self, PyObject * args) {
02145     char * filename;
02146     int flags;
02147     int rc = 255;
02148 
02149     if (PyArg_ParseTuple(args, "si", &filename, &flags)) {
02150         const char *av[2];
02151         av[0] = filename;
02152         av[1] = NULL;
02153         rc = rpmCheckSig(flags, av);
02154     }
02155     return Py_BuildValue("i", rc);
02156 }
02157 
02158 /* hack to get the current header that's in the transaction set */
02161 static PyObject * getTsHeader (PyObject * self, PyObject * args) {
02162     hdrObject * h;
02163     
02164     if (transactionSetHeader) {
02165         h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
02166         h->h = headerLink(transactionSetHeader);
02167         h->sigs = NULL;
02168         h->fileList = h->linkList = h->md5list = NULL;
02169         h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
02170         h->modes = h->rdevs = NULL;
02171         return (PyObject *) h;
02172     }
02173     Py_INCREF(Py_None);
02174     return (PyObject *) Py_None;
02175 }
02176 
02179 typedef struct FDlist_t FDlist;
02180 
02183 struct FDlist_t {
02184     FILE *f;
02185     FD_t fd;
02186     char *note;
02187     FDlist *next;
02188 } ;
02189 
02192 static FDlist *fdhead = NULL;
02193 
02196 static FDlist *fdtail = NULL;
02197 
02200 static int closeCallback(FILE * f) {
02201     FDlist *node, *last;
02202 
02203     printf ("close callback on %p\n", f);
02204     
02205     node = fdhead;
02206     last = NULL;
02207     while (node) {
02208         if (node->f == f)
02209             break;
02210         last = node;
02211         node = node->next;
02212     }
02213     if (node) {
02214         if (last)
02215             last->next = node->next;
02216         else
02217             fdhead = node->next;
02218         printf ("closing %s %p\n", node->note, node->fd);
02219         free (node->note);
02220         node->fd = fdLink(node->fd, "closeCallback");
02221         Fclose (node->fd);
02222         while (node->fd)
02223             node->fd = fdFree(node->fd, "closeCallback");
02224         free (node);
02225     }
02226     return 0; 
02227 }
02228 
02229 #if 0
02230 
02232 static PyObject * doFopen(PyObject * self, PyObject * args) {
02233     char * path, * mode;
02234     FDlist *node;
02235     
02236     if (!PyArg_ParseTuple(args, "ss", &path, &mode))
02237         return NULL;
02238     
02239     node = malloc (sizeof(FDlist));
02240     
02241     node->fd = Fopen(path, mode);
02242     node->fd = fdLink(node->fd, "doFopen");
02243     node->note = strdup (path);
02244 
02245     if (!node->fd) {
02246         PyErr_SetFromErrno(pyrpmError);
02247         free (node);
02248         return NULL;
02249     }
02250     
02251     if (Ferror(node->fd)) {
02252         const char *err = Fstrerror(node->fd);
02253         free(node);
02254         if (err) {
02255             PyErr_SetString(pyrpmError, err);
02256             return NULL;
02257         }
02258     }
02259     node->f = fdGetFp(node->fd);
02260     printf ("opening %s fd = %p f = %p\n", node->note, node->fd, node->f);
02261     if (!node->f) {
02262         PyErr_SetString(pyrpmError, "FD_t has no FILE*");
02263         free(node);
02264         return NULL;
02265     }
02266 
02267     node->next = NULL;
02268     if (!fdhead) {
02269         fdhead = fdtail = node;
02270     } else if (fdtail) {
02271         fdtail->next = node;
02272     } else {
02273         fdhead = node;
02274     }
02275     fdtail = node;
02276     
02277     return PyFile_FromFile (node->f, path, mode, closeCallback);
02278 }
02279 #endif
02280 
02283 static PyMethodDef rpmModuleMethods[] = {
02284     { "TransactionSet", (PyCFunction) rpmtransCreate, METH_VARARGS, NULL },
02285     { "addMacro", (PyCFunction) doAddMacro, METH_VARARGS, NULL },
02286     { "delMacro", (PyCFunction) doDelMacro, METH_VARARGS, NULL },
02287     { "archscore", (PyCFunction) archScore, METH_VARARGS, NULL },
02288     { "findUpgradeSet", (PyCFunction) findUpgradeSet, METH_VARARGS, NULL },
02289     { "headerFromPackage", (PyCFunction) rpmHeaderFromPackage, METH_VARARGS, NULL },
02290     { "headerLoad", (PyCFunction) hdrLoad, METH_VARARGS, NULL },
02291     { "initdb", (PyCFunction) rpmInitDB, METH_VARARGS, NULL },
02292     { "opendb", (PyCFunction) rpmOpenDB, METH_VARARGS, NULL },
02293     { "rebuilddb", (PyCFunction) rebuildDB, METH_VARARGS, NULL },
02294     { "readHeaderListFromFD", (PyCFunction) rpmHeaderFromFD, METH_VARARGS, NULL },
02295     { "readHeaderListFromFile", (PyCFunction) rpmHeaderFromFile, METH_VARARGS, NULL },
02296     { "errorSetCallback", (PyCFunction) errorSetCallback, METH_VARARGS, NULL },
02297     { "errorString", (PyCFunction) errorString, METH_VARARGS, NULL },
02298     { "versionCompare", (PyCFunction) versionCompare, METH_VARARGS, NULL },
02299     { "labelCompare", (PyCFunction) labelCompare, METH_VARARGS, NULL },
02300     { "checksig", (PyCFunction) checkSig, METH_VARARGS, NULL },
02301     { "getTransactionCallbackHeader", (PyCFunction) getTsHeader, METH_VARARGS, NULL },
02302 /*      { "Fopen", (PyCFunction) doFopen, METH_VARARGS, NULL }, */
02303     { NULL }
02304 } ;
02305 
02308 void initrpm(void) {
02309     PyObject * m, * d, *o, * tag = NULL, * dict;
02310     int i;
02311     const struct headerSprintfExtension * extensions = rpmHeaderFormats;
02312     struct headerSprintfExtension * ext;
02313 
02314 /*      _rpmio_debug = -1; */
02315     rpmReadConfigFiles(NULL, NULL);
02316 
02317     m = Py_InitModule("rpm", rpmModuleMethods);
02318     d = PyModule_GetDict(m);
02319 
02320     pyrpmError = PyString_FromString("rpm.error");
02321     PyDict_SetItemString(d, "error", pyrpmError);
02322     Py_DECREF(pyrpmError);
02323 
02324     dict = PyDict_New();
02325 
02326     for (i = 0; i < rpmTagTableSize; i++) {
02327         tag = PyInt_FromLong(rpmTagTable[i].val);
02328         PyDict_SetItemString(d, (char *) rpmTagTable[i].name, tag);
02329         Py_DECREF(tag);
02330         PyDict_SetItem(dict, tag, o=PyString_FromString(rpmTagTable[i].name + 7));
02331         Py_DECREF(o);
02332     }
02333 
02334     while (extensions->name) {
02335         if (extensions->type == HEADER_EXT_TAG) {
02336             (const struct headerSprintfExtension *) ext = extensions;
02337             PyDict_SetItemString(d, extensions->name, o=PyCObject_FromVoidPtr(ext, NULL));
02338             Py_DECREF(o);
02339             PyDict_SetItem(dict, tag, o=PyString_FromString(ext->name + 7));
02340             Py_DECREF(o);    
02341         }
02342         extensions++;
02343     }
02344 
02345     PyDict_SetItemString(d, "tagnames",