# rpmmodule.c

Go to the documentation of this file.

    00001
    00005 #include <errno.h>
    00006 #include <fcntl.h>
    00007 #include <time.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 #include <time.h>
    00015
    00016 #include "Python.h"
    00017 #include "rpmio_internal.h"
    00018 #include "rpmcli.h"     /* XXX for rpmCheckSig */
    00019 #include "misc.h"
    00020 #include "header_internal.h"
    00021 #include "upgrade.h"
    00022
    00023 extern int _rpmio_debug;
    00024
    00025 /*@unused@*/ static inline Header headerAllocated(Header h) {
    00026     h->flags |= HEADERFLAG_ALLOCATED;
    00027     return 0;
    00028 }
    00029
    00030 #ifdef __LCLINT__
    00031 #undef  PyObject_HEAD
    00032 #define PyObject_HEAD   int _PyObjectHead
    00033 #endif
    00034
    00035 extern int mdfile(const char *fn, unsigned char *digest);
    00036
    00037 void initrpm(void);
    00038
    00039 /* from lib/misc.c */
    00040 int rpmvercmp(const char * one, const char * two);
    00041
    00042
    00045 typedef struct rpmdbObject_s rpmdbObject;
    00046
    00049 typedef struct rpmdbMIObject_s rpmdbMIObject;
    00050
    00053 typedef struct rpmtransObject_s rpmtransObject;
    00054
    00057 typedef struct hdrObject_s hdrObject;
    00058
    00061 static PyObject * pyrpmError;
    00062
    00114
    00117 struct hdrObject_s {
    00118     PyObject_HEAD;
    00119     Header h;
    00120     Header sigs;                /* XXX signature tags are in header */
    00121     char ** md5list;
    00122     char ** fileList;
    00123     char ** linkList;
    00124     int_32 * fileSizes;
    00125     int_32 * mtimes;
    00126     int_32 * uids, * gids;      /* XXX these tags are not used anymore */
    00127     unsigned short * rdevs;
    00128     unsigned short * modes;
    00129 } ;
    00130
    00133 static PyObject * hdrKeyList(hdrObject * s, PyObject * args) {
    00134     PyObject * list, *o;
    00135     HeaderIterator iter;
    00136     int tag, type;
    00137
    00138     if (!PyArg_ParseTuple(args, "")) return NULL;
    00139
    00140     list = PyList_New(0);
    00141
    00142     iter = headerInitIterator(s->h);
    00143     while (headerNextIterator(iter, &tag, &type, NULL, NULL)) {
    00144         if (tag == HEADER_I18NTABLE) continue;
    00145
    00146         switch (type) {
    00147           case RPM_BIN_TYPE:
    00148           case RPM_INT32_TYPE:
    00149           case RPM_CHAR_TYPE:
    00150           case RPM_INT8_TYPE:
    00151           case RPM_INT16_TYPE:
    00152           case RPM_STRING_ARRAY_TYPE:
    00153           case RPM_STRING_TYPE:
    00154             PyList_Append(list, o=PyInt_FromLong(tag));
    00155             Py_DECREF(o);
    00156         }
    00157     }
    00158
    00159     headerFreeIterator(iter);
    00160
    00161     return list;
    00162 }
    00163
    00166 static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords) {
    00167     char * buf;
    00168     PyObject * rc;
    00169     int len, legacy = 0;
    00170     Header h;
    00171     static char *kwlist[] = { "legacyHeader", NULL};
    00172
    00173     if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
    00174         return NULL;
    00175
    00176     h = headerLink(s->h);
    00177     /* XXX this legacy switch is a hack, needs to be removed. */
    00178     if (legacy) {
    00179         h = headerCopy(s->h);   /* XXX strip region tags, etc */
    00180         headerFree(s->h);
    00181     }
    00182     len = headerSizeof(h, 0);
    00183     buf = headerUnload(h);
    00184     h = headerFree(h);
    00185
    00186     if (buf == NULL || len == 0) {
    00187         PyErr_SetString(pyrpmError, "can't unload bad header\n");
    00188         return NULL;
    00189     }
    00190
    00191     rc = PyString_FromStringAndSize(buf, len);
    00192     free(buf);
    00193
    00194     return rc;
    00195 }
    00196
    00202 static PyObject * hdrVerifyFile(hdrObject * s, PyObject * args) {
    00203     int fileNumber;
    00204     rpmVerifyAttrs verifyResult = 0;
    00205     PyObject * list, * tuple, * attrName;
    00206     int type, count;
    00207     struct stat sb;
    00208     char buf[2048];
    00209     int i;
    00210     time_t timeInt;
    00211     struct tm * timeStruct;
    00212
    00213     if (!PyInt_Check(args)) {
    00214         PyErr_SetString(PyExc_TypeError, "integer expected");
    00215         return NULL;
    00216     }
    00217
    00218     fileNumber = (int) PyInt_AsLong(args);
    00219
    00220     /* XXX this routine might use callbacks intelligently. */
    00221     if (rpmVerifyFile("", s->h, fileNumber, &verifyResult, RPMVERIFY_NONE)) {
    00222         Py_INCREF(Py_None);
    00223         return Py_None;
    00224     }
    00225
    00226     list = PyList_New(0);
    00227
    00228     if (!verifyResult) return list;
    00229
    00230     /* XXX Legacy tag needs to go away. */
    00231     if (!s->fileList) {
    00232         headerGetEntry(s->h, RPMTAG_OLDFILENAMES, &type, (void **) &s->fileList,
    00233                  &count);
    00234     }
    00235
    00236     lstat(s->fileList[fileNumber], &sb);
    00237
    00238     if (verifyResult & RPMVERIFY_MD5) {
    00239         if (!s->md5list) {
    00240             headerGetEntry(s->h, RPMTAG_FILEMD5S, &type, (void **) &s->md5list,
    00241                      &count);
    00242         }
    00243
    00244         if (mdfile(s->fileList[fileNumber], buf)) {
    00245             strcpy(buf, "(unknown)");
    00246         }
    00247
    00248         tuple = PyTuple_New(3);
    00249         attrName = PyString_FromString("checksum");
    00250         PyTuple_SetItem(tuple, 0, attrName);
    00251         PyTuple_SetItem(tuple, 1, PyString_FromString(s->md5list[fileNumber]));
    00252         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
    00253         PyList_Append(list, tuple);
    00254         Py_DECREF(tuple);
    00255     }
    00256
    00257     if (verifyResult & RPMVERIFY_FILESIZE) {
    00258         if (!s->fileSizes) {
    00259             headerGetEntry(s->h, RPMTAG_FILESIZES, &type, (void **) &s->fileSizes,
    00260                      &count);
    00261
    00262         }
    00263
    00264         tuple = PyTuple_New(3);
    00265         attrName = PyString_FromString("size");
    00266         PyTuple_SetItem(tuple, 0, attrName);
    00267
    00268         sprintf(buf, "%d", 100);
    00269         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
    00270         sprintf(buf, "%ld", sb.st_size);
    00271         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
    00272         PyList_Append(list, tuple);
    00273         Py_DECREF(tuple);
    00274     }
    00275
    00276     if (verifyResult & RPMVERIFY_LINKTO) {
    00277         if (!s->linkList) {
    00278             headerGetEntry(s->h, RPMTAG_FILELINKTOS, &type, (void **) &s->linkList,
    00279                      &count);
    00280         }
    00281
    00282         i = readlink(s->fileList[fileNumber], buf, sizeof(buf));
    00283         if (i <= 0)
    00284             strcpy(buf, "(unknown)");
    00285         else
    00286             buf[i] = '\0';
    00287
    00288         tuple = PyTuple_New(3);
    00289         attrName = PyString_FromString("link");
    00290         PyTuple_SetItem(tuple, 0, attrName);
    00291         PyTuple_SetItem(tuple, 1, PyString_FromString(s->linkList[fileNumber]));
    00292         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
    00293         PyList_Append(list, tuple);
    00294         Py_DECREF(tuple);
    00295     }
    00296
    00297     if (verifyResult & RPMVERIFY_MTIME) {
    00298         if (!s->mtimes) {
    00299             headerGetEntry(s->h, RPMTAG_FILEMTIMES, &type, (void **) &s->mtimes,
    00300                      &count);
    00301         }
    00302
    00303         tuple = PyTuple_New(3);
    00304         attrName = PyString_FromString("time");
    00305         PyTuple_SetItem(tuple, 0, attrName);
    00306
    00307         timeInt = sb.st_mtime;
    00308         timeStruct = localtime(&timeInt);
    00309         strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
    00310         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
    00311
    00312         timeInt = s->mtimes[fileNumber];
    00313         timeStruct = localtime(&timeInt);
    00314         strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
    00315
    00316         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
    00317
    00318         PyList_Append(list, tuple);
    00319         Py_DECREF(tuple);
    00320     }
    00321
    00322     if (verifyResult & RPMVERIFY_RDEV) {
    00323         if (!s->rdevs) {
    00324             headerGetEntry(s->h, RPMTAG_FILERDEVS, &type, (void **) &s->rdevs,
    00325                      &count);
    00326         }
    00327
    00328         tuple = PyTuple_New(3);
    00329         attrName = PyString_FromString("device");
    00330
    00331         PyTuple_SetItem(tuple, 0, attrName);
    00332         sprintf(buf, "0x%-4x", s->rdevs[fileNumber]);
    00333         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
    00334         sprintf(buf, "0x%-4x", (unsigned int) sb.st_rdev);
    00335         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
    00336         PyList_Append(list, tuple);
    00337         Py_DECREF(tuple);
    00338     }
    00339
    00340     /*
    00341      * RPMVERIFY_USER and RPM_VERIFY_GROUP are handled wrong here, but rpmlib.a
    00342      * doesn't do these correctly either. At least this is consistent.
    00343      *
    00344      * XXX Consistent? rpmlib.a verifies user/group quite well, thank you.
    00345      * XXX The code below does nothing useful. FILEUSERNAME needs to be
    00346      * XXX retrieved and looked up.
    00347      */
    00348     if (verifyResult & RPMVERIFY_USER) {
    00349         if (!s->uids) {
    00350             headerGetEntry(s->h, RPMTAG_FILEUIDS, &type, (void **) &s->uids,
    00351                      &count);
    00352         }
    00353
    00354         tuple = PyTuple_New(3);
    00355         attrName = PyString_FromString("uid");
    00356         PyTuple_SetItem(tuple, 0, attrName);
    00357         sprintf(buf, "%d", s->uids[fileNumber]);
    00358         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
    00359         sprintf(buf, "%d", sb.st_uid);
    00360         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
    00361         PyList_Append(list, tuple);
    00362         Py_DECREF(tuple);
    00363     }
    00364
    00365     /*
    00366      * XXX The code below does nothing useful. FILEGROUPNAME needs to be
    00367      * XXX retrieved and looked up.
    00368      */
    00369     if (verifyResult & RPMVERIFY_GROUP) {
    00370         if (!s->gids) {
    00371             headerGetEntry(s->h, RPMTAG_FILEGIDS, &type, (void **) &s->gids,
    00372                      &count);
    00373         }
    00374
    00375         tuple = PyTuple_New(3);
    00376         attrName = PyString_FromString("gid");
    00377         PyTuple_SetItem(tuple, 0, attrName);
    00378         sprintf(buf, "%d", s->gids[fileNumber]);
    00379         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
    00380         sprintf(buf, "%d", sb.st_gid);
    00381         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
    00382         PyList_Append(list, tuple);
    00383         Py_DECREF(tuple);
    00384     }
    00385
    00386     if (verifyResult & RPMVERIFY_MODE) {
    00387         if (!s->modes) {
    00388             headerGetEntry(s->h, RPMTAG_FILEMODES, &type, (void **) &s->modes,
    00389                      &count);
    00390         }
    00391
    00392         tuple = PyTuple_New(3);
    00393         attrName = PyString_FromString("permissions");
    00394         PyTuple_SetItem(tuple, 0, attrName);
    00395         sprintf(buf, "0%-4o", s->modes[fileNumber]);
    00396         PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
    00397         sprintf(buf, "0%-4o", sb.st_mode);
    00398         PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
    00399         PyList_Append(list, tuple);
    00400         Py_DECREF(tuple);
    00401     }
    00402
    00403     return list;
    00404 }
    00405
    00408 static PyObject * hdrExpandFilelist(hdrObject * s, PyObject * args) {
    00409     expandFilelist (s->h);
    00410
    00411     Py_INCREF(Py_None);
    00412     return Py_None;
    00413 }
    00414
    00417 static PyObject * hdrCompressFilelist(hdrObject * s, PyObject * args) {
    00418     compressFilelist (s->h);
    00419
    00420     Py_INCREF(Py_None);
    00421     return Py_None;
    00422 }
    00423
    00424 /* make a header with _all_ the tags we need */
    00427 static void mungeFilelist(Header h)
    00428 {
    00429     const char ** fileNames = NULL;
    00430     int count = 0;
    00431
    00432     if (!headerIsEntry (h, RPMTAG_BASENAMES)
    00433         || !headerIsEntry (h, RPMTAG_DIRNAMES)
    00434         || !headerIsEntry (h, RPMTAG_DIRINDEXES))
    00435         compressFilelist(h);
    00436
    00437     rpmBuildFileList(h, &fileNames, &count);
    00438
    00439     if (fileNames == NULL || count <= 0)
    00440         return;
    00441
    00442     /* XXX Legacy tag needs to go away. */
    00443     headerAddEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
    00444                         fileNames, count);
    00445
    00446     free((void *)fileNames);
    00447 }
    00448
    00451 static PyObject * rhnUnload(hdrObject * s, PyObject * args) {
    00452     int len;
    00453     char * uh;
    00454     PyObject * rc;
    00455     Header h;
    00456
    00457     if (!PyArg_ParseTuple(args, ""))
    00458         return NULL;
    00459
    00460     h = headerLink(s->h);
    00461
    00462     /* Retrofit a RHNPlatform: tag. */
    00463     if (!headerIsEntry(h, RPMTAG_RHNPLATFORM)) {
    00464         const char * arch;
    00465         int_32 at;
    00466         if (headerGetEntry(h, RPMTAG_ARCH, &at, (void **)&arch, NULL))
    00467             headerAddEntry(h, RPMTAG_RHNPLATFORM, at, arch, 1);
    00468     }
    00469
    00470     /* Legacy headers are forced into immutable region. */
    00471     if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
    00472         Header nh = headerReload(h, RPMTAG_HEADERIMMUTABLE);
    00473         /* XXX Another unload/load cycle to "seal" the immutable region. */
    00474         uh = headerUnload(nh);
    00475         headerFree(nh);
    00476         h = headerLoad(uh);
    00477         headerAllocated(h);
    00478     }
    00479
    00480     /* All headers have SHA1 digest, compute and add if necessary. */
    00481     if (!headerIsEntry(h, RPMTAG_SHA1HEADER)) {
    00482         int_32 uht, uhc;
    00483         const char * digest;
    00484         size_t digestlen;
    00485         DIGEST_CTX ctx;
    00486
    00487         headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, (void **)&uh, &uhc);
    00488
    00489         ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
    00490         rpmDigestUpdate(ctx, uh, uhc);
    00491         rpmDigestFinal(ctx, (void **)&digest, &digestlen, 1);
    00492
    00493         headerAddEntry(h, RPMTAG_SHA1RHN, RPM_STRING_TYPE, digest, 1);
    00494
    00495         uh = headerFreeData(uh, uht);
    00496         digest = _free(digest);
    00497     }
    00498
    00499     len = headerSizeof(h, 0);
    00500     uh = headerUnload(h);
    00501     headerFree(h);
    00502
    00503     rc = PyString_FromStringAndSize(uh, len);
    00504     free(uh);
    00505
    00506     return rc;
    00507 }
    00508
    00511 static PyObject * hdrFullFilelist(hdrObject * s, PyObject * args) {
    00512     if (!PyArg_ParseTuple(args, ""))
    00513         return NULL;
    00514
    00515     mungeFilelist (s->h);
    00516
    00517     Py_INCREF(Py_None);
    00518     return Py_None;
    00519 }
    00520
    00523 static PyObject * hdrSprintf(hdrObject * s, PyObject * args) {
    00524     char * fmt;
    00525     char * r;
    00526     errmsg_t err;
    00527     PyObject * result;
    00528
    00529     if (!PyArg_ParseTuple(args, "s", &fmt))
    00530         return NULL;
    00531
    00532     r = headerSprintf(s->h, fmt, rpmTagTable, rpmHeaderFormats, &err);
    00533     if (!r) {
    00534         PyErr_SetString(pyrpmError, err);
    00535         return NULL;
    00536     }
    00537
    00538     result = Py_BuildValue("s", r);
    00539     free(r);
    00540
    00541     return result;
    00542 }
    00543
    00544
    00547 static struct PyMethodDef hdrMethods[] = {
    00548         {"keys",        (PyCFunction) hdrKeyList,       1 },
    00549         {"unload",      (PyCFunction) hdrUnload,        METH_VARARGS|METH_KEYWORDS },
    00550         {"verifyFile",  (PyCFunction) hdrVerifyFile,    1 },
    00551         {"expandFilelist",      (PyCFunction) hdrExpandFilelist,        1 },
    00552         {"compressFilelist",    (PyCFunction) hdrCompressFilelist,      1 },
    00553         {"fullFilelist",        (PyCFunction) hdrFullFilelist,  1 },
    00554         {"rhnUnload",   (PyCFunction) rhnUnload, METH_VARARGS },
    00555         {"sprintf",     (PyCFunction) hdrSprintf, METH_VARARGS },
    00556         {NULL,          NULL}           /* sentinel */
    00557 };
    00558
    00561 static PyObject * hdrGetAttr(hdrObject * s, char * name) {
    00562     return Py_FindMethod(hdrMethods, (PyObject * ) s, name);
    00563 }
    00564
    00567 static void hdrDealloc(hdrObject * s) {
    00568     if (s->h) headerFree(s->h);
    00569     if (s->sigs) headerFree(s->sigs);
    00570     if (s->md5list) free(s->md5list);
    00571     if (s->fileList) free(s->fileList);
    00572     if (s->linkList) free(s->linkList);
    00573     PyMem_DEL(s);
    00574 }
    00575
    00578 static long tagNumFromPyObject (PyObject *item)
    00579 {
    00580     char * str;
    00581     int i;
    00582
    00583     if (PyInt_Check(item)) {
    00584         return PyInt_AsLong(item);
    00585     } else if (PyString_Check(item)) {
    00586         str = PyString_AsString(item);
    00587         for (i = 0; i < rpmTagTableSize; i++)
    00588             if (!xstrcasecmp(rpmTagTable[i].name + 7, str)) break;
    00589         if (i < rpmTagTableSize) return rpmTagTable[i].val;
    00590     }
    00591     return -1;
    00592 }
    00593
    00596 static PyObject * hdrSubscript(hdrObject * s, PyObject * item) {
    00597     int type, count, i, tag = -1;
    00598     void * data;
    00599     PyObject * o, * metao;
    00600     char ** stringArray;
    00601     int forceArray = 0;
    00602     int freeData = 0;
    00603     char * str;
    00604     struct headerSprintfExtension_s * ext = NULL;
    00605     const struct headerSprintfExtension_s * extensions = rpmHeaderFormats;
    00606
    00607     if (PyCObject_Check (item))
    00608         ext = PyCObject_AsVoidPtr(item);
    00609     else
    00610         tag = tagNumFromPyObject (item);
    00611     if (tag == -1 && PyString_Check(item)) {
    00612         /* if we still don't have the tag, go looking for the header
    00613            extensions */
    00614         str = PyString_AsString(item);
    00615         while (extensions->name) {
    00616             if (extensions->type == HEADER_EXT_TAG
    00617                 && !xstrcasecmp(extensions->name + 7, str)) {
    00618                 (const struct headerSprintfExtension *) ext = extensions;
    00619             }
    00620             extensions++;
    00621         }
    00622     }
    00623
    00624     if (ext) {
    00625         ext->u.tagFunction(s->h, &type, (const void **) &data, &count, &freeData);
    00626     } else {
    00627         if (tag == -1) {
    00628             PyErr_SetString(PyExc_KeyError, "unknown header tag");
    00629             return NULL;
    00630         }
    00631
    00632         /* XXX signature tags are appended to header, this API is gonna die */
    00633         if (!rpmPackageGetEntry(NULL, s->sigs, s->h, tag, &type, &data, &count))
    00634         {
    00635             Py_INCREF(Py_None);
    00636             return Py_None;
    00637         }
    00638     }
    00639
    00640     switch (tag) {
    00641       case RPMTAG_OLDFILENAMES:
    00642       case RPMTAG_FILESIZES:
    00643       case RPMTAG_FILESTATES:
    00644       case RPMTAG_FILEMODES:
    00645       case RPMTAG_FILEUIDS:
    00646       case RPMTAG_FILEGIDS:
    00647       case RPMTAG_FILERDEVS:
    00648       case RPMTAG_FILEMTIMES:
    00649       case RPMTAG_FILEMD5S:
    00650       case RPMTAG_FILELINKTOS:
    00651       case RPMTAG_FILEFLAGS:
    00652       case RPMTAG_ROOT:
    00653       case RPMTAG_FILEUSERNAME:
    00654       case RPMTAG_FILEGROUPNAME:
    00655         forceArray = 1;
    00656         break;
    00657       case RPMTAG_SUMMARY:
    00658       case RPMTAG_GROUP:
    00659       case RPMTAG_DESCRIPTION:
    00660         freeData = 1;
    00661         break;
    00662       default:
    00663         break;
    00664     }
    00665
    00666     switch (type) {
    00667       case RPM_BIN_TYPE:
    00668         o = PyString_FromStringAndSize(data, count);
    00669         break;
    00670
    00671       case RPM_INT32_TYPE:
    00672         if (count != 1 || forceArray) {
    00673             metao = PyList_New(0);
    00674             for (i = 0; i < count; i++) {
    00675                 o = PyInt_FromLong(((int *) data)[i]);
    00676                 PyList_Append(metao, o);
    00677                 Py_DECREF(o);
    00678             }
    00679             o = metao;
    00680         } else {
    00681             o = PyInt_FromLong(*((int *) data));
    00682         }
    00683         break;
    00684
    00685       case RPM_CHAR_TYPE:
    00686       case RPM_INT8_TYPE:
    00687         if (count != 1 || forceArray) {
    00688             metao = PyList_New(0);
    00689             for (i = 0; i < count; i++) {
    00690                 o = PyInt_FromLong(((char *) data)[i]);
    00691                 PyList_Append(metao, o);
    00692                 Py_DECREF(o);
    00693             }
    00694             o = metao;
    00695         } else {
    00696             o = PyInt_FromLong(*((char *) data));
    00697         }
    00698         break;
    00699
    00700       case RPM_INT16_TYPE:
    00701         if (count != 1 || forceArray) {
    00702             metao = PyList_New(0);
    00703             for (i = 0; i < count; i++) {
    00704                 o = PyInt_FromLong(((short *) data)[i]);
    00705                 PyList_Append(metao, o);
    00706                 Py_DECREF(o);
    00707             }
    00708             o = metao;
    00709         } else {
    00710             o = PyInt_FromLong(*((short *) data));
    00711         }
    00712         break;
    00713
    00714       case RPM_STRING_ARRAY_TYPE:
    00715         stringArray = data;
    00716
    00717         metao = PyList_New(0);
    00718         for (i = 0; i < count; i++) {
    00719             o = PyString_FromString(stringArray[i]);
    00720             PyList_Append(metao, o);
    00721             Py_DECREF(o);
    00722         }
    00723         free (stringArray);
    00724         o = metao;
    00725         break;
    00726
    00727       case RPM_STRING_TYPE:
    00728         if (count != 1 || forceArray) {
    00729             stringArray = data;
    00730
    00731             metao = PyList_New(0);
    00732             for (i=0; i < count; i++) {
    00733                 o = PyString_FromString(stringArray[i]);
    00734                 PyList_Append(metao, o);
    00735                 Py_DECREF(o);
    00736             }
    00737             o = metao;
    00738         } else {
    00739             o = PyString_FromString(data);
    00740             if (freeData)
    00741                 free (data);
    00742         }
    00743         break;
    00744
    00745       default:
    00746         PyErr_SetString(PyExc_TypeError, "unsupported type in header");
    00747         return NULL;
    00748     }
    00749
    00750     return o;
    00751 }
    00752
    00755 static PyMappingMethods hdrAsMapping = {
    00756         (inquiry) 0,                    /* mp_length */
    00757         (binaryfunc) hdrSubscript,      /* mp_subscript */
    00758         (objobjargproc)0,               /* mp_ass_subscript */
    00759 };
    00760
    00763 static PyTypeObject hdrType = {
    00764         PyObject_HEAD_INIT(NULL)
    00765         0,                              /* ob_size */
    00766         "header",                       /* tp_name */
    00767         sizeof(hdrObject),              /* tp_size */
    00768         0,                              /* tp_itemsize */
    00769         (destructor) hdrDealloc,        /* tp_dealloc */
    00770         0,                              /* tp_print */
    00771         (getattrfunc) hdrGetAttr,       /* tp_getattr */
    00772         0,                              /* tp_setattr */
    00773         0,                              /* tp_compare */
    00774         0,                              /* tp_repr */
    00775         0,                              /* tp_as_number */
    00776         0,                              /* tp_as_sequence */
    00777         &hdrAsMapping,                  /* tp_as_mapping */
    00778 };
    00779
    00792
    00795 struct rpmdbObject_s {
    00796     PyObject_HEAD;
    00797     rpmdb db;
    00798     int offx;
    00799     int noffs;
    00800     int *offsets;
    00801 } ;
    00802
    00805 struct rpmdbMIObject_s {
    00806     PyObject_HEAD;
    00807     rpmdbObject *db;
    00808     rpmdbMatchIterator mi;
    00809 } ;
    00810
    00813 static PyObject *
    00814 rpmdbMINext(rpmdbMIObject * s, PyObject * args) {
    00815     /* XXX assume header? */
    00816     Header h;
    00817     hdrObject * ho;
    00818
    00819
    00820     h = rpmdbNextIterator(s->mi);
    00821     if (!h) {
    00822         Py_INCREF(Py_None);
    00823         return Py_None;
    00824     }
    00825
    00826     ho = PyObject_NEW(hdrObject, &hdrType);
    00827     ho->h = headerLink(h);
    00828     ho->sigs = NULL;
    00829     ho->fileList = ho->linkList = ho->md5list = NULL;
    00830     ho->uids = ho->gids = ho->mtimes = ho->fileSizes = NULL;
    00831     ho->modes = ho->rdevs = NULL;
    00832
    00833     return (PyObject *) ho;
    00834 }
    00835
    00838 static struct PyMethodDef rpmdbMIMethods[] = {
    00839         {"next",            (PyCFunction) rpmdbMINext,  1 },
    00840         {NULL,          NULL}           /* sentinel */
    00841 };
    00842
    00845 static PyObject * rpmdbMIGetAttr (rpmdbObject *s, char *name) {
    00846     return Py_FindMethod (rpmdbMIMethods, (PyObject *) s, name);
    00847 }
    00848
    00851 static void rpmdbMIDealloc(rpmdbMIObject * s) {
    00852     if (s && s->mi) {
    00853         rpmdbFreeIterator(s->mi);
    00854     }
    00855     Py_DECREF (s->db);
    00856     PyMem_DEL(s);
    00857 }
    00858
    00861 static PyTypeObject rpmdbMIType = {
    00862         PyObject_HEAD_INIT(NULL)
    00863         0,                              /* ob_size */
    00864         "rpmdbMatchIterator",           /* tp_name */
    00865         sizeof(rpmdbMIObject),  /* tp_size */
    00866         0,                              /* tp_itemsize */
    00867         (destructor) rpmdbMIDealloc,    /* tp_dealloc */
    00868         0,                              /* tp_print */
    00869         (getattrfunc) rpmdbMIGetAttr,   /* tp_getattr */
    00870         0,                              /* tp_setattr */
    00871         0,                              /* tp_compare */
    00872         0,                              /* tp_repr */
    00873         0,                              /* tp_as_number */
    00874         0,                              /* tp_as_sequence */
    00875         0,                              /* tp_as_mapping */
    00876 };
    00877
    00946
    00949 static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args) {
    00950     int first;
    00951
    00952     if (!PyArg_ParseTuple (args, "")) return NULL;
    00953
    00954     /* Acquire all offsets in one fell swoop. */
    00955     if (s->offsets == NULL || s->noffs <= 0) {
    00956         rpmdbMatchIterator mi;
    00957         Header h;
    00958
    00959         if (s->offsets)
    00960             free(s->offsets);
    00961         s->offsets = NULL;
    00962         s->noffs = 0;
    00963         mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
    00964         while ((h = rpmdbNextIterator(mi)) != NULL) {
    00965             s->noffs++;
    00966             s->offsets = realloc(s->offsets, s->noffs * sizeof(s->offsets[0]));
    00967             s->offsets[s->noffs-1] = rpmdbGetIteratorOffset(mi);
    00968         }
    00969         rpmdbFreeIterator(mi);
    00970     }
    00971
    00972     s->offx = 0;
    00973     if (s->offsets != NULL && s->offx < s->noffs)
    00974         first = s->offsets[s->offx++];
    00975     else
    00976         first = 0;
    00977
    00978     if (!first) {
    00979         PyErr_SetString(pyrpmError, "cannot find first entry in database\n");
    00980         return NULL;
    00981     }
    00982
    00983     return Py_BuildValue("i", first);
    00984 }
    00985
    00988 static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args) {
    00989     int where;
    00990
    00991     if (!PyArg_ParseTuple (args, "i", &where)) return NULL;
    00992
    00993     if (s->offsets == NULL || s->offx >= s->noffs) {
    00994         Py_INCREF(Py_None);
    00995         return Py_None;
    00996     }
    00997
    00998     where = s->offsets[s->offx++];
    00999
    01000     if (!where) {
    01001         Py_INCREF(Py_None);
    01002         return Py_None;
    01003     }
    01004
    01005     return Py_BuildValue("i", where);
    01006 }
    01007
    01010 static PyObject * handleDbResult(rpmdbMatchIterator mi) {
    01011     PyObject * list, *o;
    01012
    01013     list = PyList_New(0);
    01014
    01015     /* XXX FIXME: unnecessary header mallocs are side effect here */
    01016     if (mi != NULL) {
    01017         while (rpmdbNextIterator(mi)) {
    01018             PyList_Append(list, o=PyInt_FromLong(rpmdbGetIteratorOffset(mi)));
    01019             Py_DECREF(o);
    01020         }
    01021         rpmdbFreeIterator(mi);
    01022     }
    01023
    01024     return list;
    01025 }
    01026
    01029 static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args) {
    01030     char * str;
    01031
    01032     if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
    01033
    01034     return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_BASENAMES, str, 0));
    01035 }
    01036
    01039 static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args) {
    01040     char * str;
    01041
    01042     if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
    01043
    01044     return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_NAME, str, 0));
    01045 }
    01046
    01049 static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args) {
    01050     char * str;
    01051
    01052     if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
    01053
    01054     return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_PROVIDENAME, str, 0));
    01055 }
    01056
    01059 static rpmdbMIObject *
    01060 py_rpmdbInitIterator (rpmdbObject * s, PyObject * args) {
    01061     PyObject *index = NULL;
    01062     char *key = NULL;
    01063     int len = 0, tag = -1;
    01064     rpmdbMIObject * mio;
    01065
    01066     if (!PyArg_ParseTuple(args, "|Ozi", &index, &key, &len))
    01067         return NULL;
    01068
    01069     if (index == NULL)
    01070         tag = 0;
    01071     else if ((tag = tagNumFromPyObject (index)) == -1) {
    01072         PyErr_SetString(PyExc_TypeError, "unknown tag type");
    01073         return NULL;
    01074     }
    01075
    01076     mio = (rpmdbMIObject *) PyObject_NEW(rpmdbMIObject, &rpmdbMIType);
    01077     if (mio == NULL) {
    01078         PyErr_SetString(pyrpmError, "out of memory creating rpmdbMIObject");
    01079         return NULL;
    01080     }
    01081
    01082     mio->mi = rpmdbInitIterator(s->db, tag, key, len);
    01083     mio->db = s;
    01084     Py_INCREF (mio->db);
    01085
    01086     return mio;
    01087 }
    01088
    01091 static struct PyMethodDef rpmdbMethods[] = {
    01092         {"firstkey",        (PyCFunction) rpmdbFirst,   1 },
    01093         {"nextkey",         (PyCFunction) rpmdbNext,    1 },
    01094         {"findbyfile",      (PyCFunction) rpmdbByFile, 1 },
    01095         {"findbyname",      (PyCFunction) rpmdbByName, 1 },
    01096         {"findbyprovides",  (PyCFunction) rpmdbByProvides, 1 },
    01097         {"match",           (PyCFunction) py_rpmdbInitIterator, 1 },
    01098         {NULL,          NULL}           /* sentinel */
    01099 };
    01100
    01103 static PyObject * rpmdbGetAttr(rpmdbObject * s, char * name) {
    01104     return Py_FindMethod(rpmdbMethods, (PyObject * ) s, name);
    01105 }
    01106
    01109 static void rpmdbDealloc(rpmdbObject * s) {
    01110     if (s->offsets) {
    01111         free(s->offsets);
    01112     }
    01113     if (s->db) {
    01114         rpmdbClose(s->db);
    01115     }
    01116     PyMem_DEL(s);
    01117 }
    01118
    01119 #ifndef DYINGSOON       /* XXX OK, when? */
    01120
    01122 static int
    01123 rpmdbLength(rpmdbObject * s) {
    01124     int count = 0;
    01125
    01126     {   rpmdbMatchIterator mi;
    01127
    01128         /* RPMDBI_PACKAGES */
    01129         mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
    01130         while (rpmdbNextIterator(mi) != NULL)
    01131             count++;
    01132         rpmdbFreeIterator(mi);
    01133     }
    01134
    01135     return count;
    01136 }
    01137
    01140 static hdrObject *
    01141 rpmdbSubscript(rpmdbObject * s, PyObject * key) {
    01142     int offset;
    01143     hdrObject * h;
    01144
    01145     if (!PyInt_Check(key)) {
    01146         PyErr_SetString(PyExc_TypeError, "integer expected");
    01147         return NULL;
    01148     }
    01149
    01150     offset = (int) PyInt_AsLong(key);
    01151
    01152     h = PyObject_NEW(hdrObject, &hdrType);
    01153     h->h = NULL;
    01154     h->sigs = NULL;
    01155     {   rpmdbMatchIterator mi;
    01156         mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, &offset, sizeof(offset));
    01157         if ((h->h = rpmdbNextIterator(mi)) != NULL)
    01158             h->h = headerLink(h->h);
    01159         rpmdbFreeIterator(mi);
    01160     }
    01161     h->fileList = h->linkList = h->md5list = NULL;
    01162     h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
    01163     h->modes = h->rdevs = NULL;
    01164     if (!h->h) {
    01165         Py_DECREF(h);
    01166         PyErr_SetString(pyrpmError, "cannot read rpmdb entry");
    01167         return NULL;
    01168     }
    01169
    01170     return h;
    01171 }
    01172
    01175 static PyMappingMethods rpmdbAsMapping = {
    01176         (inquiry) rpmdbLength,          /* mp_length */
    01177         (binaryfunc) rpmdbSubscript,    /* mp_subscript */
    01178         (objobjargproc)0,               /* mp_ass_subscript */
    01179 };
    01180 #endif
    01181
    01184 static PyTypeObject rpmdbType = {
    01185         PyObject_HEAD_INIT(NULL)
    01186         0,                              /* ob_size */
    01187         "rpmdb",                        /* tp_name */
    01188         sizeof(rpmdbObject),            /* tp_size */
    01189         0,                              /* tp_itemsize */
    01190         (destructor) rpmdbDealloc,      /* tp_dealloc */
    01191         0,                              /* tp_print */
    01192         (getattrfunc) rpmdbGetAttr,     /* tp_getattr */
    01193         0,                              /* tp_setattr */
    01194         0,                              /* tp_compare */
    01195         0,                              /* tp_repr */
    01196         0,                              /* tp_as_number */
    01197         0,                              /* tp_as_sequence */
    01198 #ifndef DYINGSOON
    01199         &rpmdbAsMapping,                /* tp_as_mapping */
    01200 #else
    01201         0,
    01202 #endif
    01203 };
    01204
    01309
    01312 struct rpmtransObject_s {
    01313     PyObject_HEAD;
    01314     rpmdbObject * dbo;
    01315     rpmTransactionSet ts;
    01316     PyObject * keyList;                 /* keeps reference counts correct */
    01317     FD_t scriptFd;
    01318 } ;
    01319
    01322 static PyObject * rpmtransAdd(rpmtransObject * s, PyObject * args) {
    01323     hdrObject * h;
    01324     PyObject * key;
    01325     char * how = NULL;
    01326     int isUpgrade = 0;
    01327
    01328     if (!PyArg_ParseTuple(args, "OO|s", &h, &key, &how)) return NULL;
    01329     if (h->ob_type != &hdrType) {
    01330         PyErr_SetString(PyExc_TypeError, "bad type for header argument");
    01331         return NULL;
    01332     }
    01333
    01334     if (how && strcmp(how, "a") && strcmp(how, "u") && strcmp(how, "i")) {
    01335         PyErr_SetString(PyExc_TypeError, "how argument must be \"u\", \"a\", or \"i\"");
    01336         return NULL;
    01337     } else if (how && !strcmp(how, "u"))
    01338         isUpgrade = 1;
    01339
    01340     if (how && !strcmp(how, "a"))
    01341         rpmtransAvailablePackage(s->ts, h->h, key);
    01342     else
    01343         rpmtransAddPackage(s->ts, h->h, NULL, key, isUpgrade, NULL);
    01344
    01345     /* This should increment the usage count for me */
    01346     if (key) {
    01347         PyList_Append(s->keyList, key);
    01348     }
    01349
    01350     Py_INCREF(Py_None);
    01351     return Py_None;
    01352 }
    01353
    01356 static PyObject * rpmtransRemove(rpmtransObject * s, PyObject * args) {
    01357     char * name;
    01358     int count;
    01359     rpmdbMatchIterator mi;
    01360
    01361     if (!PyArg_ParseTuple(args, "s", &name))
    01362         return NULL;
    01363
    01364     /* XXX: Copied hack from ../lib/rpminstall.c, rpmErase() */
    01365     mi = rpmdbInitIterator(s->dbo->db, RPMDBI_LABEL, name, 0);
    01366     count = rpmdbGetIteratorCount(mi);
    01367     if (count <= 0) {
    01368         PyErr_SetString(pyrpmError, "package not installed");
    01369         return NULL;
    01370     } else { /* XXX: Note that we automatically choose to remove all matches */
    01371         Header h;
    01372         while ((h = rpmdbNextIterator(mi)) != NULL) {
    01373             unsigned int recOffset = rpmdbGetIteratorOffset(mi);
    01374             if (recOffset) {
    01375                 rpmtransRemovePackage(s->ts, recOffset);
    01376             }
    01377         }
    01378     }
    01379     rpmdbFreeIterator(mi);
    01380
    01381     Py_INCREF(Py_None);
    01382     return Py_None;
    01383 }
    01384
    01387 static PyObject * rpmtransDepCheck(rpmtransObject * s, PyObject * args) {
    01388     rpmDependencyConflict conflicts;
    01389     int numConflicts;
    01390     PyObject * list, * cf;
    01391     int i;
    01392
    01393     if (!PyArg_ParseTuple(args, "")) return NULL;
    01394
    01395     rpmdepCheck(s->ts, &conflicts, &numConflicts);
    01396     if (numConflicts) {
    01397         list = PyList_New(0);
    01398
    01399         /* XXX TODO: rpmlib-4.0.3 can return multiple suggested packages. */
    01400         for (i = 0; i < numConflicts; i++) {
    01401             cf = Py_BuildValue("((sss)(ss)iOi)", conflicts[i].byName,
    01402                                conflicts[i].byVersion, conflicts[i].byRelease,
    01403
    01404                                conflicts[i].needsName,
    01405                                conflicts[i].needsVersion,
    01406
    01407                                conflicts[i].needsFlags,
    01408                                conflicts[i].suggestedPackages ?
    01409                                    conflicts[i].suggestedPackages[0] : Py_None,
    01410                                conflicts[i].sense);
    01411             PyList_Append(list, (PyObject *) cf);
    01412             Py_DECREF(cf);
    01413         }
    01414
    01415         conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
    01416
    01417         return list;
    01418     }
    01419
    01420     Py_INCREF(Py_None);
    01421     return Py_None;
    01422 }
    01423
    01426 static PyObject * rpmtransOrder(rpmtransObject * s, PyObject * args) {
    01427     if (!PyArg_ParseTuple(args, "")) return NULL;
    01428
    01429     rpmdepOrder(s->ts);
    01430
    01431     Py_INCREF(Py_None);
    01432     return Py_None;
    01433 }
    01434
    01437 static PyObject * py_rpmtransGetKeys(rpmtransObject * s, PyObject * args) {
    01438     const void **data = NULL;
    01439     int num, i;
    01440     PyObject *tuple;
    01441
    01442     rpmtransGetKeys(s->ts, &data, &num);
    01443     if (data == NULL) {
    01444         Py_INCREF(Py_None);
    01445         return Py_None;
    01446     }
    01447
    01448     tuple = PyTuple_New(num);
    01449
    01450     for (i = 0; i < num; i++) {
    01451         PyObject *obj = (PyObject *) data[i];
    01452         Py_INCREF(obj);
    01453         PyTuple_SetItem(tuple, i, obj);
    01454     }
    01455
    01456     free (data);
    01457
    01458     return tuple;
    01459 }
    01460
    01463 struct tsCallbackType {
    01464     PyObject * cb;
    01465     PyObject * data;
    01466     int pythonError;
    01467 };
    01468
    01472 static Header transactionSetHeader = NULL;
    01473
    01476 static void * tsCallback(const void * hd, const rpmCallbackType what,
    01477                          const unsigned long amount, const unsigned long total,
    01478                          const void * pkgKey, rpmCallbackData data) {
    01479     struct tsCallbackType * cbInfo = data;
    01480     PyObject * args, * result;
    01481     int fd;
    01482     static FD_t fdt;
    01483     const Header h = (Header) hd;
    01484
    01485     if (cbInfo->pythonError) return NULL;
    01486
    01487     if (!pkgKey) pkgKey = Py_None;
    01488     transactionSetHeader = h;
    01489
    01490     args = Py_BuildValue("(illOO)", what, amount, total, pkgKey, cbInfo->data);
    01491     result = PyEval_CallObject(cbInfo->cb, args);
    01492     Py_DECREF(args);
    01493
    01494     if (!result) {
    01495         cbInfo->pythonError = 1;
    01496         return NULL;
    01497     }
    01498
    01499     if (what == RPMCALLBACK_INST_OPEN_FILE) {
    01500         if (!PyArg_Parse(result, "i", &fd)) {
    01501             cbInfo->pythonError = 1;
    01502             return NULL;
    01503         }
    01504         fdt = fdDup(fd);
    01505
    01506         Py_DECREF(result);
    01507         return fdt;
    01508     }
    01509
    01510     if (what == RPMCALLBACK_INST_CLOSE_FILE) {
    01511         Fclose (fdt);
    01512     }
    01513
    01514     Py_DECREF(result);
    01515
    01516     return NULL;
    01517 }
    01518
    01521 static PyObject * rpmtransRun(rpmtransObject * s, PyObject * args) {
    01522     int flags, ignoreSet;
    01523     int rc, i;
    01524     PyObject * list, * prob;
    01525     rpmProblemSet probs;
    01526     struct tsCallbackType cbInfo;
    01527
    01528     if (!PyArg_ParseTuple(args, "iiOO", &flags, &ignoreSet, &cbInfo.cb,
    01529                           &cbInfo.data))
    01530         return NULL;
    01531
    01532     cbInfo.pythonError = 0;
    01533
    01534     rc = rpmRunTransactions(s->ts, tsCallback, &cbInfo, NULL, &probs, flags,
    01535                             ignoreSet);
    01536
    01537     if (cbInfo.pythonError) {
    01538         if (rc > 0)
    01539             rpmProblemSetFree(probs);
    01540         return NULL;
    01541     }
    01542
    01543     if (rc < 0) {
    01544         list = PyList_New(0);
    01545         return list;
    01546     } else if (!rc) {
    01547         Py_INCREF(Py_None);
    01548         return Py_None;
    01549     }
    01550
    01551     list = PyList_New(0);
    01552     for (i = 0; i < probs->numProblems; i++) {
    01553         rpmProblem myprob = probs->probs + i;
    01554         prob = Py_BuildValue("s(isi)", rpmProblemString(myprob),
    01555                              myprob->type,
    01556                              myprob->str1,
    01557                              myprob->ulong1);
    01558         PyList_Append(list, prob);
    01559         Py_DECREF(prob);
    01560     }
    01561
    01562     rpmProblemSetFree(probs);
    01563
    01564     return list;
    01565 }
    01566
    01569 static struct PyMethodDef rpmtransMethods[] = {
    01570         {"add",         (PyCFunction) rpmtransAdd,      1 },
    01571         {"remove",      (PyCFunction) rpmtransRemove,   1 },
    01572         {"depcheck",    (PyCFunction) rpmtransDepCheck, 1 },
    01573         {"order",       (PyCFunction) rpmtransOrder,    1 },
    01574         {"getKeys",     (PyCFunction) py_rpmtransGetKeys, 1 },
    01575         {"run",         (PyCFunction) rpmtransRun, 1 },
    01576         {NULL,          NULL}           /* sentinel */
    01577 };
    01578
    01581 static PyObject * rpmtransGetAttr(rpmtransObject * o, char * name) {
    01582     return Py_FindMethod(rpmtransMethods, (PyObject *) o, name);
    01583 }
    01584
    01587 static void rpmtransDealloc(PyObject * o) {
    01588     rpmtransObject * trans = (void *) o;
    01589
    01590     rpmtransFree(trans->ts);
    01591     if (trans->dbo) {
    01592         Py_DECREF(trans->dbo);
    01593     }
    01594     if (trans->scriptFd) Fclose(trans->scriptFd);
    01595     /* this will free the keyList, and decrement the ref count of all
    01596        the items on the list as well :-) */
    01597     Py_DECREF(trans->keyList);
    01598     PyMem_DEL(o);
    01599 }
    01600
    01603 static int rpmtransSetAttr(rpmtransObject * o, char * name,
    01604                            PyObject * val) {
    01605     int i;
    01606
    01607     if (!strcmp(name, "scriptFd")) {
    01608         if (!PyArg_Parse(val, "i", &i)) return 0;
    01609         if (i < 0) {
    01610             PyErr_SetString(PyExc_TypeError, "bad file descriptor");
    01611             return -1;
    01612         } else {
    01613             o->scriptFd = fdDup(i);
    01614             rpmtransSetScriptFd(o->ts, o->scriptFd);
    01615         }
    01616     } else {
    01617         PyErr_SetString(PyExc_AttributeError, name);
    01618         return -1;
    01619     }
    01620
    01621     return 0;
    01622 }
    01623
    01626 static PyTypeObject rpmtransType = {
    01627         PyObject_HEAD_INIT(NULL)
    01628         0,                              /* ob_size */
    01629         "rpmtrans",                     /* tp_name */
    01630         sizeof(rpmtransObject),         /* tp_size */
    01631         0,                              /* tp_itemsize */
    01632         (destructor) rpmtransDealloc,   /* tp_dealloc */
    01633         0,                              /* tp_print */
    01634         (getattrfunc) rpmtransGetAttr,  /* tp_getattr */
    01635         (setattrfunc) rpmtransSetAttr,  /* tp_setattr */
    01636         0,                              /* tp_compare */
    01637         0,                              /* tp_repr */
    01638         0,                              /* tp_as_number */
    01639         0,                              /* tp_as_sequence */
    01640         0,                              /* tp_as_mapping */
    01641 };
    01642
    01649
    01652 static PyObject * rpmtransCreate(PyObject * self, PyObject * args) {
    01653     rpmtransObject * o;
    01654     rpmdbObject * db = NULL;
    01655     char * rootPath = "/";
    01656
    01657     if (!PyArg_ParseTuple(args, "|sO", &rootPath, &db)) return NULL;
    01658     if (db && db->ob_type != &rpmdbType) {
    01659         PyErr_SetString(PyExc_TypeError, "bad type for database argument");
    01660         return NULL;
    01661     }
    01662
    01663     o = (void *) PyObject_NEW(rpmtransObject, &rpmtransType);
    01664
    01665     Py_XINCREF(db);
    01666     o->dbo = db;
    01667     o->scriptFd = NULL;
    01668     o->ts = rpmtransCreateSet(db ? db->db : NULL, rootPath);
    01669     o->keyList = PyList_New(0);
    01670
    01671     return (void *) o;
    01672 }
    01673
    01676 static PyObject * doAddMacro(PyObject * self, PyObject * args) {
    01677     char * name, * val;
    01678
    01679     if (!PyArg_ParseTuple(args, "ss", &name, &val))
    01680         return NULL;
    01681
    01682     addMacro(NULL, name, NULL, val, RMIL_DEFAULT);
    01683
    01684     Py_INCREF(Py_None);
    01685     return Py_None;
    01686 }
    01687
    01690 static PyObject * doDelMacro(PyObject * self, PyObject * args) {
    01691     char * name;
    01692
    01693     if (!PyArg_ParseTuple(args, "s", &name))
    01694         return NULL;
    01695
    01696     delMacro(NULL, name);
    01697
    01698     Py_INCREF(Py_None);
    01699     return Py_None;
    01700 }
    01701
    01704 static PyObject * archScore(PyObject * self, PyObject * args) {
    01705     char * arch;
    01706     int score;
    01707
    01708     if (!PyArg_ParseTuple(args, "s", &arch))
    01709         return NULL;
    01710
    01711     score = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
    01712
    01713     return Py_BuildValue("i", score);
    01714 }
    01715
    01718 static int psGetArchScore(Header h) {
    01719     void * pkgArch;
    01720     int type, count;
    01721
    01722     if (!headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count) ||
    01723         type == RPM_INT8_TYPE)
    01724        return 150;
    01725     else
    01726         return rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch);
    01727 }
    01728
    01731 static int pkgCompareVer(void * first, void * second) {
    01732     struct packageInfo ** a = first;
    01733     struct packageInfo ** b = second;
    01734     int ret, score1, score2;
    01735
    01736     /* put packages w/o names at the end */
    01737     if (!(*a)->name) return 1;
    01738     if (!(*b)->name) return -1;
    01739
    01740     ret = xstrcasecmp((*a)->name, (*b)->name);
    01741     if (ret) return ret;
    01742     score1 = psGetArchScore((*a)->h);
    01743     if (!score1) return 1;
    01744     score2 = psGetArchScore((*b)->h);
    01745     if (!score2) return -1;
    01746     if (score1 < score2) return -1;
    01747     if (score1 > score2) return 1;
    01748     return rpmVersionCompare((*b)->h, (*a)->h);
    01749 }
    01750
    01753 static void pkgSort(struct pkgSet * psp) {
    01754     int i;
    01755     char *name;
    01756
    01757     if (psp->numPackages <= 0)
    01758         return;
    01759
    01760     qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
    01761          (void *) pkgCompareVer);
    01762
    01763     name = psp->packages[0]->name;
    01764     if (!name) {
    01765        psp->numPackages = 0;
    01766        return;
    01767     }
    01768     for (i = 1; i < psp->numPackages; i++) {
    01769        if (!psp->packages[i]->name) break;
    01770        if (!strcmp(psp->packages[i]->name, name))
    01771            psp->packages[i]->name = NULL;
    01772        else
    01773            name = psp->packages[i]->name;
    01774     }
    01775
    01776     qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
    01777          (void *) pkgCompareVer);
    01778
    01779     for (i = 0; i < psp->numPackages; i++)
    01780        if (!psp->packages[i]->name) break;
    01781     psp->numPackages = i;
    01782 }
    01783
    01786 static PyObject * findUpgradeSet(PyObject * self, PyObject * args) {
    01787     PyObject * hdrList, * result;
    01788     char * root = "/";
    01789     int i;
    01790     struct pkgSet list;
    01791     hdrObject * hdr;
    01792
    01793     if (!PyArg_ParseTuple(args, "O|s", &hdrList, &root)) return NULL;
    01794
    01795     if (!PyList_Check(hdrList)) {
    01796         PyErr_SetString(PyExc_TypeError, "list of headers expected");
    01797         return NULL;
    01798     }
    01799
    01800     list.numPackages = PyList_Size(hdrList);
    01801     list.packages = alloca(sizeof(list.packages) * list.numPackages);
    01802     for (i = 0; i < list.numPackages; i++) {
    01803         hdr = (hdrObject *) PyList_GetItem(hdrList, i);
    01804         if (hdr->ob_type != &hdrType) {
    01805             PyErr_SetString(PyExc_TypeError, "list of headers expected");
    01806             return NULL;
    01807         }
    01808         list.packages[i] = alloca(sizeof(struct packageInfo));
    01809         list.packages[i]->h = hdr->h;
    01810         list.packages[i]->selected = 0;
    01811         list.packages[i]->data = hdr;
    01812
    01813         headerGetEntry(hdr->h, RPMTAG_NAME, NULL,
    01814                       (void **) &list.packages[i]->name, NULL);
    01815     }
    01816
    01817     pkgSort (&list);
    01818
    01819     if (ugFindUpgradePackages(&list, root)) {
    01820         PyErr_SetString(pyrpmError, "error during upgrade check");
    01821         return NULL;
    01822     }
    01823
    01824     result = PyList_New(0);
    01825     for (i = 0; i < list.numPackages; i++) {
    01826         if (list.packages[i]->selected) {
    01827             PyList_Append(result, list.packages[i]->data);
    01828 /*          Py_DECREF(list.packages[i]->data); */
    01829         }
    01830     }
    01831
    01832     return result;
    01833 }
    01834
    01837 static PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args) {
    01838     hdrObject * h;
    01839     Header header;
    01840     Header sigs;
    01841     FD_t fd;
    01842     int rawFd;
    01843     int isSource = 0;
    01844     rpmRC rc;
    01845
    01846     if (!PyArg_ParseTuple(args, "i", &rawFd)) return NULL;
    01847     fd = fdDup(rawFd);
    01848
    01849     rc = rpmReadPackageInfo(fd, &sigs, &header);
    01850     Fclose(fd);
    01851
    01852     switch (rc) {
    01853     case RPMRC_BADSIZE:
    01854     case RPMRC_OK:
    01855         h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
    01856         h->h = header;
    01857         h->sigs = sigs;
    01858         h->fileList = h->linkList = h->md5list = NULL;
    01859         h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
    01860         h->modes = h->rdevs = NULL;
    01861         if (headerIsEntry(header, RPMTAG_SOURCEPACKAGE))
    01862             isSource = 1;
    01863         break;
    01864
    01865     case RPMRC_BADMAGIC:
    01866         Py_INCREF(Py_None);
    01867         h = (hdrObject *) Py_None;
    01868         break;
    01869
    01870     case RPMRC_FAIL:
    01871     case RPMRC_SHORTREAD:
    01872     default:
    01873         PyErr_SetString(pyrpmError, "error reading package");
    01874         return NULL;
    01875     }
    01876
    01877     return Py_BuildValue("(Ni)", h, isSource);
    01878 }
    01879
    01882 static PyObject * hdrLoad(PyObject * self, PyObject * args) {
    01883     char * obj, * copy=NULL;
    01884     Header hdr;
    01885     hdrObject * h;
    01886     int len;
    01887
    01888     if (!PyArg_ParseTuple(args, "s#", &obj, &len)) return NULL;
    01889
    01890     /* malloc is needed to avoid surprises from data swab in headerLoad(). */
    01891     copy = malloc(len);
    01892     if (copy == NULL) {
    01893         PyErr_SetString(pyrpmError, "out of memory");
    01894         return NULL;
    01895     }
    01896     memcpy (copy, obj, len);
    01897
    01898     hdr = headerLoad(copy);
    01899     if (!hdr) {
    01900         PyErr_SetString(pyrpmError, "bad header");
    01901         return NULL;
    01902     }
    01903     headerAllocated(hdr);
    01904     compressFilelist (hdr);
    01905     providePackageNVR (hdr);
    01906
    01907     h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
    01908     h->h = hdr;
    01909     h->sigs = NULL;
    01910     h->fileList = h->linkList = h->md5list = NULL;
    01911     h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
    01912     h->modes = h->rdevs = NULL;
    01913
    01914     return (PyObject *) h;
    01915 }
    01916
    01919 static PyObject * rhnLoad(PyObject * self, PyObject * args) {
    01920     char * obj, * copy=NULL;
    01921     Header hdr;
    01922     hdrObject * h;
    01923     int len;
    01924
    01925     if (!PyArg_ParseTuple(args, "s#", &obj, &len)) return NULL;
    01926
    01927     /* malloc is needed to avoid surprises from data swab in headerLoad(). */
    01928     copy = malloc(len);
    01929     if (copy == NULL) {
    01930         PyErr_SetString(pyrpmError, "out of memory");
    01931         return NULL;
    01932     }
    01933     memcpy (copy, obj, len);
    01934
    01935     hdr = headerLoad(copy);
    01936     if (!hdr) {
    01937         PyErr_SetString(pyrpmError, "bad header");
    01938         return NULL;
    01939     }
    01940     headerAllocated(hdr);
    01941
    01942     /* XXX avoid the false OK's from rpmverifyDigest() with missing tags. */
    01943     if (!headerIsEntry(hdr, RPMTAG_HEADERIMMUTABLE)) {
    01944         PyErr_SetString(pyrpmError, "bad header, not immutable");
    01945         headerFree(hdr);
    01946         return NULL;
    01947     }
    01948
    01949     /* XXX avoid the false OK's from rpmverifyDigest() with missing tags. */
    01950     if (!headerIsEntry(hdr, RPMTAG_SHA1HEADER)
    01951     &&  !headerIsEntry(hdr, RPMTAG_SHA1RHN)) {
    01952         PyErr_SetString(pyrpmError, "bad header, no digest");
    01953         headerFree(hdr);
    01954         return NULL;
    01955     }
    01956
    01957     if (rpmVerifyDigest(hdr)) {
    01958         PyErr_SetString(pyrpmError, "bad header, digest check failed");
    01959         headerFree(hdr);
    01960         return NULL;
    01961     }
    01962
    01963     /* Retrofit a RHNPlatform: tag. */
    01964     if (!headerIsEntry(hdr, RPMTAG_RHNPLATFORM)) {
    01965         const char * arch;
    01966         int_32 at;
    01967         if (headerGetEntry(hdr, RPMTAG_ARCH, &at, (void **)&arch, NULL))
    01968             headerAddEntry(hdr, RPMTAG_RHNPLATFORM, at, arch, 1);
    01969     }
    01970
    01971     h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
    01972     h->h = hdr;
    01973     h->sigs = NULL;
    01974     h->fileList = h->linkList = h->md5list = NULL;
    01975     h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
    01976     h->modes = h->rdevs = NULL;
    01977
    01978     return (PyObject *) h;
    01979 }
    01980
    01983 static PyObject * rpmInitDB(PyObject * self, PyObject * args) {
    01984     char *root;
    01985     int forWrite = 0;
    01986
    01987     if (!PyArg_ParseTuple(args, "i|s", &forWrite, &root)) return NULL;
    01988
    01989     if (rpmdbInit(root, forWrite ? O_RDWR | O_CREAT: O_RDONLY)) {
    01990         char * errmsg = "cannot initialize database in %s";
    01991         char * errstr = NULL;
    01992         int errsize;
    01993
    01994         errsize = strlen(errmsg) + strlen(root);
    01995         errstr = alloca(errsize);
    01996         snprintf(errstr, errsize, errmsg, root);
    01997         PyErr_SetString(pyrpmError, errstr);
    01998         return NULL;
    01999     }
    02000
    02001     Py_INCREF(Py_None);
    02002     return(Py_None);
    02003 }
    02004
    02007 static rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) {
    02008     rpmdbObject * o;
    02009     char * root = "";
    02010     int forWrite = 0;
    02011
    02012     if (!PyArg_ParseTuple(args, "|is", &forWrite, &root)) return NULL;
    02013
    02014     o = PyObject_NEW(rpmdbObject, &rpmdbType);
    02015     o->db = NULL;
    02016     o->offx = 0;
    02017     o->noffs = 0;
    02018     o->offsets = NULL;
    02019
    02020     if (rpmdbOpen(root, &o->db, forWrite ? O_RDWR | O_CREAT: O_RDONLY, 0644)) {
    02021         char * errmsg = "cannot open database in %s";
    02022         char * errstr = NULL;
    02023         int errsize;
    02024
    02025         Py_DECREF(o);
    02026         /* PyErr_SetString should take varargs... */
    02027         errsize = strlen(errmsg) + *root == '\0' ? 15 /* "/var/lib/rpm" */ : strlen(root);
    02028         errstr = alloca(errsize);
    02029         snprintf(errstr, errsize, errmsg, *root == '\0' ? "/var/lib/rpm" : root);
    02030         PyErr_SetString(pyrpmError, errstr);
    02031         return NULL;
    02032     }
    02033
    02034     return o;
    02035 }
    02036
    02039 static PyObject * rebuildDB (PyObject * self, PyObject * args) {
    02040     char * root = "";
    02041
    02042     if (!PyArg_ParseTuple(args, "s", &root)) return NULL;
    02043
    02044     return Py_BuildValue("i", rpmdbRebuild(root));
    02045 }
    02046
    02049 static PyObject * rpmReadHeaders (FD_t fd) {
    02050     PyObject * list;
    02051     Header header;
    02052     hdrObject * h;
    02053
    02054     if (!fd) {
    02055         PyErr_SetFromErrno(pyrpmError);
    02056         return NULL;
    02057     }
    02058
    02059     list = PyList_New(0);
    02060     Py_BEGIN_ALLOW_THREADS
    02061     header = headerRead(fd, HEADER_MAGIC_YES);
    02062
    02063     Py_END_ALLOW_THREADS
    02064     while (header) {
    02065         compressFilelist (header);
    02066         providePackageNVR (header);
    02067         h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
    02068         h->h = header;
    02069         h->sigs = NULL;
    02070         h->fileList = h->linkList = h->md5list = NULL;
    02071         h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
    02072         h->modes = h->rdevs = NULL;
    02073         if (PyList_Append(list, (PyObject *) h)) {
    02074             Py_DECREF(list);
    02075             Py_DECREF(h);
    02076             return NULL;
    02077         }
    02078
    02079         Py_DECREF(h);
    02080
    02081         Py_BEGIN_ALLOW_THREADS
    02082         header = headerRead(fd, HEADER_MAGIC_YES);
    02083         Py_END_ALLOW_THREADS
    02084     }
    02085
    02086     return list;
    02087 }
    02088
    02091 static PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args) {
    02092     FD_t fd;
    02093     int fileno;
    02094     PyObject * list;
    02095
    02096     if (!PyArg_ParseTuple(args, "i", &fileno)) return NULL;
    02097     fd = fdDup(fileno);
    02098
    02099     list = rpmReadHeaders (fd);
    02100     Fclose(fd);
    02101
    02102     return list;
    02103 }
    02104
    02107 static PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args) {
    02108     char * filespec;
    02109     FD_t fd;
    02110     PyObject * list;
    02111
    02112     if (!PyArg_ParseTuple(args, "s", &filespec)) return NULL;
    02113     fd = Fopen(filespec, "r.fdio");
    02114
    02115     if (!fd) {
    02116         PyErr_SetFromErrno(pyrpmError);
    02117         return NULL;
    02118     }
    02119
    02120     list = rpmReadHeaders (fd);
    02121     Fclose(fd);
    02122
    02123     return list;
    02124 }
    02125
    02130 static int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag) {
    02131     Header newH;
    02132     HeaderIterator iter;
    02133     int_32 * newMatch, * oldMatch;
    02134     hdrObject * ho;
    02135     int count = 0;
    02136     int type, c, tag;
    02137     void * p;
    02138
    02139     Py_BEGIN_ALLOW_THREADS
    02140     newH = headerRead(fd, HEADER_MAGIC_YES);
    02141
    02142     Py_END_ALLOW_THREADS
    02143     while (newH) {
    02144         if (!headerGetEntry(newH, matchTag, NULL, (void **) &newMatch, NULL)) {
    02145             PyErr_SetString(pyrpmError, "match tag missing in new header");
    02146             return 1;
    02147         }
    02148
    02149         ho = (hdrObject *) PyList_GetItem(list, count++);
    02150         if (!ho) return 1;
    02151
    02152         if (!headerGetEntry(ho->h, matchTag, NULL, (void **) &oldMatch, NULL)) {
    02153             PyErr_SetString(pyrpmError, "match tag missing in new header");
    02154             return 1;
    02155         }
    02156
    02157         if (*newMatch != *oldMatch) {
    02158             PyErr_SetString(pyrpmError, "match tag mismatch");
    02159             return 1;
    02160         }
    02161
    02162         if (ho->sigs) headerFree(ho->sigs);
    02163         if (ho->md5list) free(ho->md5list);
    02164         if (ho->fileList) free(ho->fileList);
    02165         if (ho->linkList) free(ho->linkList);
    02166
    02167         ho->sigs = NULL;
    02168         ho->md5list = NULL;
    02169         ho->fileList = NULL;
    02170         ho->linkList = NULL;
    02171
    02172         iter = headerInitIterator(newH);
    02173
    02174         while (headerNextIterator(iter, &tag, &type, (void *) &p, &c)) {
    02175             /* could be dupes */
    02176             headerRemoveEntry(ho->h, tag);
    02177             headerAddEntry(ho->h, tag, type, p, c);
    02178             headerFreeData(p, type);
    02179         }
    02180
    02181         headerFreeIterator(iter);
    02182
    02183         Py_BEGIN_ALLOW_THREADS
    02184         newH = headerRead(fd, HEADER_MAGIC_YES);
    02185         Py_END_ALLOW_THREADS
    02186     }
    02187
    02188     return 0;
    02189 }
    02190
    02191 static PyObject * rpmMergeHeadersFromFD(PyObject * self, PyObject * args) {
    02192     FD_t fd;
    02193     int fileno;
    02194     PyObject * list;
    02195     int rc;
    02196     int matchTag;
    02197
    02198     if (!PyArg_ParseTuple(args, "Oii", &list, &fileno, &matchTag)) return NULL;
    02199
    02200     if (!PyList_Check(list)) {
    02201         PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
    02202         return NULL;
    02203     }
    02204
    02205     fd = fdDup(fileno);
    02206
    02207     rc = rpmMergeHeaders (list, fd, matchTag);
    02208     Fclose(fd);
    02209
    02210     if (rc) {
    02211         return NULL;
    02212     }
    02213
    02214     Py_INCREF(Py_None);
    02215     return Py_None;
    02216 }
    02217
    02218
    02221 static PyObject * errorCB = NULL, * errorData = NULL;
    02222
    02225 static void errorcb (void)
    02226 {
    02227     PyObject * result, * args = NULL;
    02228
    02229     if (errorData)
    02230         args = Py_BuildValue("(O)", errorData);
    02231
    02232     result = PyEval_CallObject(errorCB, args);
    02233     Py_XDECREF(args);
    02234
    02235     if (result == NULL) {
    02236         PyErr_Print();
    02237         PyErr_Clear();
    02238     }
    02239     Py_DECREF (result);
    02240 }
    02241
    02244 static PyObject * errorSetCallback (PyObject * self, PyObject * args) {
    02245     PyObject *newCB = NULL, *newData = NULL;
    02246
    02247     if (!PyArg_ParseTuple(args, "O|O", &newCB, &newData)) return NULL;
    02248
    02249     /* if we're getting a void*, set the error callback to this. */
    02250     /* also, we can possibly decref any python callbacks we had  */
    02251     /* and set them to NULL.                                     */
    02252     if (PyCObject_Check (newCB)) {
    02253         rpmErrorSetCallback (PyCObject_AsVoidPtr(newCB));
    02254
    02255         Py_XDECREF (errorCB);
    02256         Py_XDECREF (errorData);
    02257
    02258         errorCB   = NULL;
    02259         errorData = NULL;
    02260
    02261         Py_INCREF(Py_None);
    02262         return Py_None;
    02263     }
    02264
    02265     if (!PyCallable_Check (newCB)) {
    02266         PyErr_SetString(PyExc_TypeError, "parameter must be callable");
    02267         return NULL;
    02268     }
    02269
    02270     Py_XDECREF(errorCB);
    02271     Py_XDECREF(errorData);
    02272
    02273     errorCB = newCB;
    02274     errorData = newData;
    02275
    02276     Py_INCREF (errorCB);
    02277     Py_XINCREF (errorData);
    02278
    02279     return PyCObject_FromVoidPtr(rpmErrorSetCallback (errorcb), NULL);
    02280 }
    02281
    02284 static PyObject * errorString (PyObject * self, PyObject * args) {
    02285     return PyString_FromString(rpmErrorString ());
    02286 }
    02287
    02290 static PyObject * versionCompare (PyObject * self, PyObject * args) {
    02291     hdrObject * h1, * h2;
    02292
    02293     if (!PyArg_ParseTuple(args, "O!O!", &hdrType, &h1, &hdrType, &h2)) return NULL;
    02294
    02295     return Py_BuildValue("i", rpmVersionCompare(h1->h, h2->h));
    02296 }
    02297
    02300 static PyObject * labelCompare (PyObject * self, PyObject * args) {
    02301     char *v1, *r1, *e1, *v2, *r2, *e2;
    02302     int rc;
    02303
    02304     if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
    02305                           &e1, &v1, &r1,
    02306                           &e2, &v2, &r2)) return NULL;
    02307
    02308     if (e1 && !e2)
    02309         return Py_BuildValue("i", 1);
    02310     else if (!e1 && e2)
    02311         return Py_BuildValue("i", -1);
    02312     else if (e1 && e2) {
    02313         int ep1, ep2;
    02314         ep1 = atoi (e1);
    02315         ep2 = atoi (e2);
    02316         if (ep1 < ep2)
    02317             return Py_BuildValue("i", -1);
    02318         else if (ep1 > ep2)
    02319             return Py_BuildValue("i", 1);
    02320     }
    02321
    02322     rc = rpmvercmp(v1, v2);
    02323     if (rc)
    02324         return Py_BuildValue("i", rc);
    02325
    02326     return Py_BuildValue("i", rpmvercmp(r1, r2));
    02327 }
    02328
    02331 static PyObject * checkSig (PyObject * self, PyObject * args) {
    02332     char * filename;
    02333     int flags;
    02334     int rc = 255;
    02335
    02336     if (PyArg_ParseTuple(args, "si", &filename, &flags)) {
    02337         const char *av[2];
    02338         av[0] = filename;
    02339         av[1] = NULL;
    02340         rc = rpmCheckSig(flags, av);
    02341     }
    02342     return Py_BuildValue("i", rc);
    02343 }
    02344
    02345 /* hack to get the current header that's in the transaction set */
    02348 static PyObject * getTsHeader (PyObject * self, PyObject * args) {
    02349     hdrObject * h;
    02350
    02351     if (!PyArg_ParseTuple(args, ""))
    02352         return NULL;
    02353
    02354     if (transactionSetHeader) {
    02355         h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
    02356         h->h = headerLink(transactionSetHeader);
    02357         h->sigs = NULL;
    02358         h->fileList = h->linkList = h->md5list = NULL;
    02359         h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
    02360         h->modes = h->rdevs = NULL;
    02361         return (PyObject *) h;
    02362     }
    02363     Py_INCREF(Py_None);
    02364     return (PyObject *) Py_None;
    02365 }
    02366
    02367 static PyObject * setVerbosity (PyObject * self, PyObject * args) {
    02368     int level;
    02369
    02370     if (!PyArg_ParseTuple(args, "i", &level))
    02371         return NULL;
    02372
    02373     rpmSetVerbosity(level);
    02374
    02375     Py_INCREF(Py_None);
    02376     return (PyObject *) Py_None;
    02377 }
    02378
    02381 typedef struct FDlist_t FDlist;
    02382
    02385 struct FDlist_t {
    02386     FILE *f;
    02387     FD_t fd;
    02388     char *note;
    02389     FDlist *next;
    02390 } ;
    02391
    02394 static FDlist *fdhead = NULL;
    02395
    02398 static FDlist *fdtail = NULL;
    02399
    02402 static int closeCallback(FILE * f) {
    02403     FDlist *node, *last;
    02404
    02405     printf ("close callback on %p\n", f);
    02406
    02407     node = fdhead;
    02408     last = NULL;
    02409     while (node) {
    02410         if (node->f == f)
    02411             break;
    02412         last = node;
    02413         node = node->next;
    02414     }
    02415     if (node) {
    02416         if (last)
    02417             last->next = node->next;
    02418         else
    02419             fdhead = node->next;
    02420         printf ("closing %s %p\n", node->note, node->fd);
    02421         free (node->note);
    02422         node->fd = fdLink(node->fd, "closeCallback");
    02423         Fclose (node->fd);
    02424         while (node->fd)
    02425             node->fd = fdFree(node->fd, "closeCallback");
    02426         free (node);
    02427     }
    02428     return 0;
    02429 }
    02430
    02433 static PyObject * doFopen(PyObject * self, PyObject * args) {
    02434     char * path, * mode;
    02435     FDlist *node;
    02436
    02437     if (!PyArg_ParseTuple(args, "ss", &path, &mode))
    02438         return NULL;
    02439
    02440     node = malloc (sizeof(FDlist));
    02441
    02442     node->fd = Fopen(path, mode);
    02443     node->fd = fdLink(node->fd, "doFopen");
    02444     node->note = strdup (path);
    02445
    02446     if (!node->fd) {
    02447         PyErr_SetFromErrno(pyrpmError);
    02448         free (node);
    02449         return NULL;
    02450     }
    02451
    02452     if (Ferror(node->fd)) {
    02453         const char *err = Fstrerror(node->fd);
    02454         free(node);
    02455         if (err) {
    02456             PyErr_SetString(pyrpmError, err);
    02457             return NULL;
    02458         }
    02459     }
    02460     node->f = fdGetFp(node->fd);
    02461     printf ("opening %s fd = %p f = %p\n", node->note, node->fd, node->f);
    02462     if (!node->f) {
    02463         PyErr_SetString(pyrpmError, "FD_t has no FILE*");
    02464         free(node);
    02465         return NULL;
    02466     }
    02467
    02468     node->next = NULL;
    02469     if (!fdhead) {
    02470         fdhead = fdtail = node;
    02471     } else if (fdtail) {
    02472         fdtail->next = node;
    02473     } else {
    02474         fdhead = node;
    02475     }
    02476     fdtail = node;
    02477
    02478     return PyFile_FromFile (node->f, path, mode, closeCallback);
    02479 }
    02480
    02483 static PyMethodDef rpmModuleMethods[] = {
    02484     { "TransactionSet", (PyCFunction) rpmtransCreate, METH_VARARGS, NULL },
    02485     { "addMacro", (PyCFunction) doAddMacro, METH_VARARGS, NULL },
    02486     { "delMacro", (PyCFunction) doDelMacro, METH_VARARGS, NULL },
    02487     { "archscore", (PyCFunction) archScore, METH_VARARGS, NULL },
    02488     { "findUpgradeSet", (PyCFunction) findUpgradeSet, METH_VARARGS, NULL },
    02489     { "headerFromPackage", (PyCFunction) rpmHeaderFromPackage, METH_VARARGS, NULL },
    02490     { "headerLoad", (PyCFunction) hdrLoad, METH_VARARGS, NULL },
    02491     { "rhnLoad", (PyCFunction) rhnLoad, METH_VARARGS, NULL },
    02492     { "initdb", (PyCFunction) rpmInitDB, METH_VARARGS, NULL },
    02493     { "opendb", (PyCFunction) rpmOpenDB, METH_VARARGS, NULL },
    02494     { "rebuilddb", (PyCFunction) rebuildDB, METH_VARARGS, NULL },
    02495     { "mergeHeaderListFromFD", (PyCFunction) rpmMergeHeadersFromFD, METH_VARARGS, NULL },
    02496     { "readHeaderListFromFD", (PyCFunction) rpmHeaderFromFD, METH_VARARGS, NULL },
    02497     { "readHeaderListFromFile", (PyCFunction) rpmHeaderFromFile, METH_VARARGS, NULL },
    02498     { "errorSetCallback", (PyCFunction) errorSetCallback, METH_VARARGS, NULL },
    02499     { "errorString", (PyCFunction) errorString, METH_VARARGS, NULL },
    02500     { "versionCompare", (PyCFunction) versionCompare, METH_VARARGS, NULL },
    02501     { "labelCompare", (PyCFunction) labelCompare, METH_VARARGS, NULL },
    02502     { "checksig", (PyCFunction) checkSig, METH_VARARGS, NULL },
    02503     { "getTransactionCallbackHeader", (PyCFunction) getTsHeader, METH_VARARGS, NULL },
    02504 /*      { "Fopen", (PyCFunction) doFopen, METH_VARARGS, NULL }, */
    02505     { "setVerbosity", (PyCFunction) setVerbosity, METH_VARARGS, NULL },
    02506     { NULL }
    02507 } ;
    02508
    02511 void initrpm(void) {
    02512     PyObject * m, * d, *o, * tag = NULL, * dict;
    02513     int i;
    02514     const struct headerSprintfExtension_s * extensions = rpmHeaderFormats;
    02515     struct headerSprintfExtension_s * ext;
    02516
    02517     m = Py_InitModule("rpm", rpmModuleMethods);
    02518
    02519     hdrType.ob_type = &PyType_Type;
    02520     rpmdbMIType.ob_type = &PyType_Type;
    02521     rpmdbType.ob_type = &PyType_Type;
    02522     rpmtransType.ob_type = &PyType_Type;
    02523
    02524     if(!m)
    02525         return;
    02526
    02527 /*      _rpmio_debug = -1; */
    02528     rpmReadConfigFiles(NULL, NULL);
    02529
    02530     d = PyModule_GetDict(m);
    02531
    02532     pyrpmError = PyString_FromString("rpm.error");
    02533     PyDict_SetItemString(d, "error", pyrpmError);
    02534     Py_DECREF(pyrpmError);
    02535
    02536     dict = PyDict_New();
    02537
    02538     for (i = 0; i < rpmTagTableSize; i++) {
    02539         tag = PyInt_FromLong(rpmTagTable[i].val);
    02540         PyDict_SetItemString(d, (char *) rpmTagTable[i].name, tag);
    02541         Py_DECREF(tag);
    02542         PyDict_SetItem(dict, tag, o=PyString_FromString(rpmTagTable[i].name + 7));
    02543         Py_DECREF(o);
    02544     }
    02545
    02546     while (extensions->name) {
    02547         if (extensions->type == HEADER_EXT_TAG) {
    02548             (const struct headerSprintfExtension *) ext = extensions;
    02549             PyDict_SetItemString(d, extensions->name, o=PyCObject_FromVoidPtr(ext, NULL));
    02550             Py_DECREF(o);
    02551             PyDict_SetItem(dict, tag, o=PyString_FromString(ext->name + 7));
    02552             Py_DECREF(o);
    02553         }
    02554         extensions++;
    02555     }
    02556
    02557     PyDict_SetItemString(d, "tagnames", dict);
    02558     Py_DECREF(dict);
    02559
    02560
    02561 #define REGISTER_ENUM(val) \
    02562     PyDict_SetItemString(d, #val, o=PyInt_FromLong( val )); \
    02563     Py_DECREF(o);
    02564
    02565     REGISTER_ENUM(RPMFILE_STATE_NORMAL);
    02566     REGISTER_ENUM(RPMFILE_STATE_REPLACED);
    02567     REGISTER_ENUM(RPMFILE_STATE_NOTINSTALLED);
    02568     REGISTER_ENUM(RPMFILE_STATE_NETSHARED);
    02569
    02570     REGISTER_ENUM(RPMFILE_CONFIG);
    02571     REGISTER_ENUM(RPMFILE_DOC);
    02572     REGISTER_ENUM(RPMFILE_MISSINGOK);
    02573     REGISTER_ENUM(RPMFILE_NOREPLACE);
    02574     REGISTER_ENUM(RPMFILE_GHOST);
    02575     REGISTER_ENUM(RPMFILE_LICENSE);
    02576     REGISTER_ENUM(RPMFILE_README);
    02577
    02578     REGISTER_ENUM(RPMDEP_SENSE_REQUIRES);
    02579     REGISTER_ENUM(RPMDEP_SENSE_CONFLICTS);
    02580
    02581     REGISTER_ENUM(RPMSENSE_SERIAL);
    02582     REGISTER_ENUM(RPMSENSE_LESS);
    02583     REGISTER_ENUM(RPMSENSE_GREATER);
    02584     REGISTER_ENUM(RPMSENSE_EQUAL);
    02585     REGISTER_ENUM(RPMSENSE_PREREQ);
    02586     REGISTER_ENUM(RPMSENSE_INTERP);
    02587     REGISTER_ENUM(RPMSENSE_SCRIPT_PRE);
    02588     REGISTER_ENUM(RPMSENSE_SCRIPT_POST);
    02589     REGISTER_ENUM(RPMSENSE_SCRIPT_PREUN);
    02590     REGISTER_ENUM(RPMSENSE_SCRIPT_POSTUN);
    02591     REGISTER_ENUM(RPMSENSE_SCRIPT_VERIFY);
    02592     REGISTER_ENUM(RPMSENSE_FIND_REQUIRES);
    02593     REGISTER_ENUM(RPMSENSE_FIND_PROVIDES);
    02594     REGISTER_ENUM(RPMSENSE_TRIGGERIN);
    02595     REGISTER_ENUM(RPMSENSE_TRIGGERUN);
    02596     REGISTER_ENUM(RPMSENSE_TRIGGERPOSTUN);
    02597     REGISTER_ENUM(RPMSENSE_MULTILIB);
    02598     REGISTER_ENUM(RPMSENSE_SCRIPT_PREP);
    02599     REGISTER_ENUM(RPMSENSE_SCRIPT_BUILD);
    02600     REGISTER_ENUM(RPMSENSE_SCRIPT_INSTALL);
    02601     REGISTER_ENUM(RPMSENSE_SCRIPT_CLEAN);
    02602     REGISTER_ENUM(RPMSENSE_RPMLIB);
    02603     REGISTER_ENUM(RPMSENSE_TRIGGERPREIN);
    02604
    02605     REGISTER_ENUM(RPMTRANS_FLAG_TEST);
    02606     REGISTER_ENUM(RPMTRANS_FLAG_BUILD_PROBS);
    02607     REGISTER_ENUM(RPMTRANS_FLAG_NOSCRIPTS);
    02608     REGISTER_ENUM(RPMTRANS_FLAG_JUSTDB);
    02609     REGISTER_ENUM(RPMTRANS_FLAG_NOTRIGGERS);
    02610     REGISTER_ENUM(RPMTRANS_FLAG_NODOCS);
    02611     REGISTER_ENUM(RPMTRANS_FLAG_ALLFILES);
    02612     REGISTER_ENUM(RPMTRANS_FLAG_KEEPOBSOLETE);
    02613     REGISTER_ENUM(RPMTRANS_FLAG_MULTILIB);
    02614
    02615     REGISTER_ENUM(RPMPROB_FILTER_IGNOREOS);
    02616     REGISTER_ENUM(RPMPROB_FILTER_IGNOREARCH);
    02617     REGISTER_ENUM(RPMPROB_FILTER_REPLACEPKG);
    02618     REGISTER_ENUM(RPMPROB_FILTER_FORCERELOCATE);
    02619     REGISTER_ENUM(RPMPROB_FILTER_REPLACENEWFILES);
    02620     REGISTER_ENUM(RPMPROB_FILTER_REPLACEOLDFILES);
    02621     REGISTER_ENUM(RPMPROB_FILTER_OLDPACKAGE);
    02622     REGISTER_ENUM(RPMPROB_FILTER_DISKSPACE);
    02623     REGISTER_ENUM(RPMPROB_FILTER_DISKNODES);
    02624
    02625     REGISTER_ENUM(RPMCALLBACK_INST_PROGRESS);
    02626     REGISTER_ENUM(RPMCALLBACK_INST_START);
    02627     REGISTER_ENUM(RPMCALLBACK_INST_OPEN_FILE);
    02628     REGISTER_ENUM(RPMCALLBACK_INST_CLOSE_FILE);
    02629     REGISTER_ENUM(RPMCALLBACK_TRANS_PROGRESS);
    02630     REGISTER_ENUM(RPMCALLBACK_TRANS_START);
    02631     REGISTER_ENUM(RPMCALLBACK_TRANS_STOP);
    02632     REGISTER_ENUM(RPMCALLBACK_UNINST_PROGRESS);
    02633     REGISTER_ENUM(RPMCALLBACK_UNINST_START);
    02634     REGISTER_ENUM(RPMCALLBACK_UNINST_STOP);
    02635
    02636     REGISTER_ENUM(RPMPROB_BADARCH);
    02637     REGISTER_ENUM(RPMPROB_BADOS);
    02638     REGISTER_ENUM(RPMPROB_PKG_INSTALLED);
    02639     REGISTER_ENUM(RPMPROB_BADRELOCATE);
    02640     REGISTER_ENUM(RPMPROB_REQUIRES);
    02641     REGISTER_ENUM(RPMPROB_CONFLICT);
    02642     REGISTER_ENUM(RPMPROB_NEW_FILE_CONFLICT);
    02643     REGISTER_ENUM(RPMPROB_FILE_CONFLICT);
    02644     REGISTER_ENUM(RPMPROB_OLDPACKAGE);
    02645     REGISTER_ENUM(RPMPROB_DISKSPACE);
    02646     REGISTER_ENUM(RPMPROB_DISKNODES);
    02647     REGISTER_ENUM(RPMPROB_BADPRETRANS);
    02648
    02649     REGISTER_ENUM(CHECKSIG_PGP);
    02650     REGISTER_ENUM(CHECKSIG_GPG);
    02651     REGISTER_ENUM(CHECKSIG_MD5);
    02652
    02653     REGISTER_ENUM(RPMLOG_EMERG);
    02654     REGISTER_ENUM(RPMLOG_ALERT);
    02655     REGISTER_ENUM(RPMLOG_CRIT);
    02656     REGISTER_ENUM(RPMLOG_ERR);
    02657     REGISTER_ENUM(RPMLOG_WARNING);
    02658     REGISTER_ENUM(RPMLOG_NOTICE);
    02659     REGISTER_ENUM(RPMLOG_INFO);
    02660     REGISTER_ENUM(RPMLOG_DEBUG);
    02661
    02662 }
    02663