Call (sub)type tp_free from destructors
[platform/upstream/rpm.git] / python / header-py.c
1 #include "rpmsystem-py.h"
2
3 #include <rpm/rpmlib.h>         /* rpmvercmp */
4 #include <rpm/rpmtag.h>
5 #include <rpm/rpmstring.h>
6 #include <rpm/rpmts.h>  /* XXX rpmtsCreate/rpmtsFree */
7
8 #include "header-py.h"
9 #include "rpmds-py.h"
10 #include "rpmfd-py.h"
11 #include "rpmfi-py.h"
12 #include "rpmtd-py.h"
13
14 #include "debug.h"
15
16 /** \ingroup python
17  * \class Rpm
18  * \brief START HERE / RPM base module for the Python API
19  *
20  * The rpm base module provides the main starting point for
21  * accessing RPM from Python. For most usage, call
22  * the TransactionSet method to get a transaction set (rpmts).
23  *
24  * For example:
25  * \code
26  *      import rpm
27  *
28  *      ts = rpm.TransactionSet()
29  * \endcode
30  *
31  * The transaction set will open the RPM database as needed, so
32  * in most cases, you do not need to explicitly open the
33  * database. The transaction set is the workhorse of RPM.
34  *
35  * You can open another RPM database, such as one that holds
36  * all packages for a given Linux distribution, to provide
37  * packages used to solve dependencies. To do this, use
38  * the following code:
39  *
40  * \code
41  * rpm.addMacro('_dbpath', '/path/to/alternate/database')
42  * solvets = rpm.TransactionSet()
43  * solvets.openDB()
44  * rpm.delMacro('_dbpath')
45  *
46  * # Open default database
47  * ts = rpm.TransactionSet()
48  * \endcode
49  *
50  * This code gives you access to two RPM databases through
51  * two transaction sets (rpmts): ts is a transaction set
52  * associated with the default RPM database and solvets
53  * is a transaction set tied to an alternate database, which
54  * is very useful for resolving dependencies.
55  *
56  * The rpm methods used here are:
57  *
58  * - addMacro(macro, value)
59  * @param macro   Name of macro to add
60  * @param value   Value for the macro
61  *
62  * - delMacro(macro)
63  * @param macro   Name of macro to delete
64  *
65  */
66
67 /** \ingroup python
68  * \class Rpmhdr
69  * \brief A python header object represents an RPM package header.
70  *
71  * All RPM packages have headers that provide metadata for the package.
72  * Header objects can be returned by database queries or loaded from a
73  * binary package on disk.
74  *
75  * The ts.hdrFromFdno() function returns the package header from a
76  * package on disk, verifying package signatures and digests of the
77  * package while reading.
78  *
79  * Note: The older method rpm.headerFromPackage() which has been replaced
80  * by ts.hdrFromFdno() used to return a (hdr, isSource) tuple.
81  *
82  * If you need to distinguish source/binary headers, do:
83  * \code
84  *      import os, rpm
85  *
86  *      ts = rpm.TransactionSet()
87  *      fdno = os.open("/tmp/foo-1.0-1.i386.rpm", os.O_RDONLY)
88  *      hdr = ts.hdrFromFdno(fdno)
89  *      os.close(fdno)
90  *      if hdr[rpm.RPMTAG_SOURCEPACKAGE]:
91  *         print "header is from a source package"
92  *      else:
93  *         print "header is from a binary package"
94  * \endcode
95  *
96  * The Python interface to the header data is quite elegant.  It
97  * presents the data in a dictionary form.  We'll take the header we
98  * just loaded and access the data within it:
99  * \code
100  *      print hdr[rpm.RPMTAG_NAME]
101  *      print hdr[rpm.RPMTAG_VERSION]
102  *      print hdr[rpm.RPMTAG_RELEASE]
103  * \endcode
104  * in the case of our "foo-1.0-1.i386.rpm" package, this code would
105  * output:
106 \verbatim
107         foo
108         1.0
109         1
110 \endverbatim
111  *
112  * You make also access the header data by string name:
113  * \code
114  *      print hdr['name']
115  *      print hdr['version']
116  *      print hdr['release']
117  * \endcode
118  *
119  * This method of access is a teensy bit slower because the name must be
120  * translated into the tag number dynamically. You also must make sure
121  * the strings in header lookups don't get translated, or the lookups
122  * will fail.
123  */
124
125 /** \ingroup python
126  * \name Class: rpm.hdr
127  */
128
129 struct hdrObject_s {
130     PyObject_HEAD
131     Header h;
132 } ;
133
134 static PyObject * hdrKeyList(hdrObject * s)
135 {
136     PyObject * list, *o;
137     HeaderIterator hi;
138     rpmtd td = rpmtdNew();
139
140     list = PyList_New(0);
141
142     hi = headerInitIterator(s->h);
143     while (headerNext(hi, td)) {
144         rpmTag tag = rpmtdTag(td);
145         if (tag == HEADER_I18NTABLE) continue;
146
147         switch (rpmtdType(td)) {
148         case RPM_BIN_TYPE:
149         case RPM_INT32_TYPE:
150         case RPM_CHAR_TYPE:
151         case RPM_INT8_TYPE:
152         case RPM_INT16_TYPE:
153         case RPM_STRING_ARRAY_TYPE:
154         case RPM_STRING_TYPE:
155             PyList_Append(list, o=PyInt_FromLong(tag));
156             Py_DECREF(o);
157             break;
158         case RPM_I18NSTRING_TYPE: /* hum.. ?`*/
159         case RPM_NULL_TYPE:
160         default:
161             break;
162         }
163         rpmtdFreeData(td);
164     }
165     headerFreeIterator(hi);
166     rpmtdFree(td);
167
168     return list;
169 }
170
171 static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords)
172 {
173     char * buf;
174     PyObject * rc;
175     int len, legacy = 0;
176     Header h;
177     static char *kwlist[] = { "legacyHeader", NULL};
178
179     if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
180         return NULL;
181
182     h = headerLink(s->h);
183     /* XXX this legacy switch is a hack, needs to be removed. */
184     if (legacy) {
185         h = headerCopy(s->h);   /* XXX strip region tags, etc */
186         headerFree(s->h);
187     }
188     len = headerSizeof(h, 0);
189     buf = headerUnload(h);
190     h = headerFree(h);
191
192     if (buf == NULL || len == 0) {
193         PyErr_SetString(pyrpmError, "can't unload bad header\n");
194         return NULL;
195     }
196
197     rc = PyString_FromStringAndSize(buf, len);
198     buf = _free(buf);
199
200     return rc;
201 }
202
203 static PyObject * hdrExpandFilelist(hdrObject * s)
204 {
205     DEPRECATED_METHOD;
206     headerConvert(s->h, HEADERCONV_EXPANDFILELIST);
207
208     Py_RETURN_NONE;
209 }
210
211 static PyObject * hdrCompressFilelist(hdrObject * s)
212 {
213     DEPRECATED_METHOD;
214     headerConvert(s->h, HEADERCONV_COMPRESSFILELIST);
215
216     Py_RETURN_NONE;
217 }
218
219 /* make a header with _all_ the tags we need */
220 static PyObject * hdrFullFilelist(hdrObject * s)
221 {
222     rpmtd fileNames = rpmtdNew();
223     Header h = s->h;
224
225     DEPRECATED_METHOD;
226     if (!headerIsEntry (h, RPMTAG_BASENAMES)
227         || !headerIsEntry (h, RPMTAG_DIRNAMES)
228         || !headerIsEntry (h, RPMTAG_DIRINDEXES))
229         headerConvert(h, HEADERCONV_COMPRESSFILELIST);
230
231     if (headerGet(h, RPMTAG_FILENAMES, fileNames, HEADERGET_EXT)) {
232         rpmtdSetTag(fileNames, RPMTAG_OLDFILENAMES);
233         headerPut(h, fileNames, HEADERPUT_DEFAULT);
234         rpmtdFreeData(fileNames);
235     }
236     rpmtdFree(fileNames);
237
238     Py_RETURN_NONE;
239 }
240
241 static PyObject * hdrFormat(hdrObject * s, PyObject * args, PyObject * kwds)
242 {
243     char * fmt;
244     char * r;
245     errmsg_t err;
246     PyObject * result;
247     char * kwlist[] = {"format", NULL};
248
249     if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &fmt))
250         return NULL;
251
252     r = headerFormat(s->h, fmt, &err);
253     if (!r) {
254         PyErr_SetString(pyrpmError, err);
255         return NULL;
256     }
257
258     result = Py_BuildValue("s", r);
259     r = _free(r);
260
261     return result;
262 }
263
264 static PyObject * hdrSprintf(hdrObject * s, PyObject * args, PyObject * kwds)
265 {
266     DEPRECATED_METHOD;
267     return hdrFormat(s, args, kwds);
268 }
269
270 static PyObject *hdrIsSource(hdrObject *s)
271 {
272     return PyBool_FromLong(headerIsSource(s->h));
273 }
274
275 static PyObject *hdrHasKey(hdrObject *s, PyObject *pytag)
276 {
277     rpmTag tag;
278     if (!tagNumFromPyObject(pytag, &tag)) return NULL;
279
280     return PyBool_FromLong(headerIsEntry(s->h, tag));
281 }
282
283 static PyObject *hdrConvert(hdrObject *self, PyObject *args, PyObject *kwds)
284 {
285     char *kwlist[] = {"op", NULL};
286     headerConvOps op = -1;
287
288     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &op)) {
289         return NULL;
290     }
291     return PyBool_FromLong(headerConvert(self->h, op));
292 }
293
294 static PyObject * hdrWrite(hdrObject *s, PyObject *args, PyObject *kwds)
295 {
296     char *kwlist[] = { "file", "magic", NULL };
297     int magic = 1;
298     FD_t fd = NULL;
299     int rc;
300
301     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist,
302                                      rpmFdFromPyObject, &fd, &magic))
303         return NULL;
304
305     Py_BEGIN_ALLOW_THREADS;
306     rc = headerWrite(fd, s->h, magic ? HEADER_MAGIC_YES : HEADER_MAGIC_NO);
307     Py_END_ALLOW_THREADS;
308
309     if (rc) PyErr_SetFromErrno(PyExc_IOError);
310     Fclose(fd); /* avoid messing up errno wrt above */
311     if (rc) return NULL;
312
313     Py_RETURN_NONE;
314 }
315
316 static PyObject * hdr_fiFromHeader(PyObject * s, PyObject * args, PyObject * kwds)
317 {
318     DEPRECATED_METHOD;
319     return PyObject_Call((PyObject *) &rpmfi_Type,
320                          Py_BuildValue("(O)", s), kwds);
321 }
322
323 static int hdr_compare(hdrObject * a, hdrObject * b)
324 {
325     return rpmVersionCompare(a->h, b->h);
326 }
327
328 static long hdr_hash(PyObject * h)
329 {
330     return (long) h;
331 }
332
333 static struct PyMethodDef hdr_methods[] = {
334     {"keys",            (PyCFunction) hdrKeyList,       METH_NOARGS,
335         NULL },
336     {"unload",          (PyCFunction) hdrUnload,        METH_VARARGS|METH_KEYWORDS,
337         NULL },
338     {"expandFilelist",  (PyCFunction) hdrExpandFilelist,METH_NOARGS,
339         NULL },
340     {"compressFilelist",(PyCFunction) hdrCompressFilelist,METH_NOARGS,
341         NULL },
342     {"fullFilelist",    (PyCFunction) hdrFullFilelist,  METH_NOARGS,
343         NULL },
344     {"convert",         (PyCFunction) hdrConvert,       METH_VARARGS|METH_KEYWORDS,
345         NULL },
346     {"format",          (PyCFunction) hdrFormat,        METH_VARARGS|METH_KEYWORDS,
347         NULL },
348     {"has_key",         (PyCFunction) hdrHasKey,        METH_O,
349         NULL },
350     {"sprintf",         (PyCFunction) hdrSprintf,       METH_VARARGS|METH_KEYWORDS,
351         NULL },
352     {"isSource",        (PyCFunction)hdrIsSource,       METH_NOARGS, 
353         NULL },
354     {"write",           (PyCFunction)hdrWrite,          METH_VARARGS|METH_KEYWORDS,
355         NULL },
356     {"dsOfHeader",      (PyCFunction)hdr_dsOfHeader,    METH_NOARGS,
357         NULL},
358     {"dsFromHeader",    (PyCFunction)hdr_dsFromHeader,  METH_VARARGS|METH_KEYWORDS,
359         NULL},
360     {"fiFromHeader",    (PyCFunction)hdr_fiFromHeader,  METH_VARARGS|METH_KEYWORDS,
361         NULL},
362
363     {NULL,              NULL}           /* sentinel */
364 };
365
366 /* TODO: permit keyring check + retrofits on copy/load */
367 static PyObject *hdr_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
368 {
369     PyObject *obj = NULL;
370     Header h = NULL;
371     FD_t fd = NULL;
372     char *kwlist[] = { "obj", NULL };
373
374     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &obj)) {
375         return NULL;
376     }
377
378     if (obj == NULL) {
379         h = headerNew();
380     } else if (hdrObject_Check(obj)) {
381         h = headerCopy(hdrGetHeader((hdrObject*) obj));
382     } else if (PyString_Check(obj)) {
383         h = headerCopyLoad(PyString_AsString(obj));
384     } else if (rpmFdFromPyObject(obj, &fd)) {
385         Py_BEGIN_ALLOW_THREADS;
386         h = headerRead(fd, HEADER_MAGIC_YES);
387         Fclose(fd);
388         Py_END_ALLOW_THREADS;
389     } else {
390         PyErr_SetString(PyExc_TypeError, "header, blob or file expected");
391         return NULL;
392     }
393
394     if (h == NULL) {
395         PyErr_SetString(pyrpmError, "bad header");
396         return NULL;
397     }
398     
399     return hdr_Wrap(subtype, h);
400 }
401
402 static void hdr_dealloc(hdrObject * s)
403 {
404     if (s->h) headerFree(s->h);
405     s->ob_type->tp_free((PyObject *)s);
406 }
407
408 int tagNumFromPyObject (PyObject *item, rpmTag *tagp)
409 {
410     rpmTag tag = RPMTAG_NOT_FOUND;
411
412     if (PyInt_Check(item)) {
413         /* XXX we should probably validate tag numbers too */
414         tag = PyInt_AsLong(item);
415     } else if (PyString_Check(item)) {
416         tag = rpmTagGetValue(PyString_AsString(item));
417     } else {
418         PyErr_SetString(PyExc_TypeError, "expected a string or integer");
419         return 0;
420     }
421     if (tag == RPMTAG_NOT_FOUND) {
422         PyErr_SetString(PyExc_ValueError, "unknown header tag");
423         return 0;
424     }
425
426     *tagp = tag;
427     return 1;
428 }
429
430 static PyObject * hdr_subscript(hdrObject * s, PyObject * item)
431 {
432     rpmTag tag = RPMTAG_NOT_FOUND;
433     struct rpmtd_s td;
434     PyObject *res = NULL;
435
436     if (!tagNumFromPyObject(item, &tag)) return NULL;
437     
438     /* rpmtd_AsPyObj() knows how to handle empty containers and all */
439     (void) headerGet(s->h, tag, &td, HEADERGET_EXT);
440     res = rpmtd_AsPyobj(&td);
441     rpmtdFreeData(&td);
442
443     return res;
444 }
445
446 static PyObject * hdr_getattro(PyObject * o, PyObject * n)
447 {
448     PyObject * res;
449     res = PyObject_GenericGetAttr(o, n);
450     if (res == NULL)
451         res = hdr_subscript((hdrObject *)o, n);
452     return res;
453 }
454
455 static int hdr_setattro(PyObject * o, PyObject * n, PyObject * v)
456 {
457     return PyObject_GenericSetAttr(o, n, v);
458 }
459
460 static PyMappingMethods hdr_as_mapping = {
461         (lenfunc) 0,                    /* mp_length */
462         (binaryfunc) hdr_subscript,     /* mp_subscript */
463         (objobjargproc)0,               /* mp_ass_subscript */
464 };
465
466 static char hdr_doc[] =
467 "";
468
469 PyTypeObject hdr_Type = {
470         PyObject_HEAD_INIT(&PyType_Type)
471         0,                              /* ob_size */
472         "rpm.hdr",                      /* tp_name */
473         sizeof(hdrObject),              /* tp_size */
474         0,                              /* tp_itemsize */
475         (destructor) hdr_dealloc,       /* tp_dealloc */
476         0,                              /* tp_print */
477         (getattrfunc) 0,                /* tp_getattr */
478         0,                              /* tp_setattr */
479         (cmpfunc) hdr_compare,          /* tp_compare */
480         0,                              /* tp_repr */
481         0,                              /* tp_as_number */
482         0,                              /* tp_as_sequence */
483         &hdr_as_mapping,                /* tp_as_mapping */
484         hdr_hash,                       /* tp_hash */
485         0,                              /* tp_call */
486         0,                              /* tp_str */
487         (getattrofunc) hdr_getattro,    /* tp_getattro */
488         (setattrofunc) hdr_setattro,    /* tp_setattro */
489         0,                              /* tp_as_buffer */
490         Py_TPFLAGS_DEFAULT,             /* tp_flags */
491         hdr_doc,                        /* tp_doc */
492         0,                              /* tp_traverse */
493         0,                              /* tp_clear */
494         0,                              /* tp_richcompare */
495         0,                              /* tp_weaklistoffset */
496         0,                              /* tp_iter */
497         0,                              /* tp_iternext */
498         hdr_methods,                    /* tp_methods */
499         0,                              /* tp_members */
500         0,                              /* tp_getset */
501         0,                              /* tp_base */
502         0,                              /* tp_dict */
503         0,                              /* tp_descr_get */
504         0,                              /* tp_descr_set */
505         0,                              /* tp_dictoffset */
506         0,                              /* tp_init */
507         0,                              /* tp_alloc */
508         hdr_new,                        /* tp_new */
509         0,                              /* tp_free */
510         0,                              /* tp_is_gc */
511 };
512
513 PyObject * hdr_Wrap(PyTypeObject *subtype, Header h)
514 {
515     hdrObject * hdr = (hdrObject *)subtype->tp_alloc(subtype, 0);
516     if (hdr == NULL) return PyErr_NoMemory();
517
518     hdr->h = headerLink(h);
519     return (PyObject *) hdr;
520 }
521
522 Header hdrGetHeader(hdrObject * s)
523 {
524     return s->h;
525 }
526
527 PyObject * hdrLoad(PyObject * s, PyObject * args, PyObject * kwds)
528 {
529     DEPRECATED_METHOD;
530     return PyObject_Call((PyObject *) &hdr_Type, args, kwds);
531 }
532
533 PyObject * rpmReadHeaders (FD_t fd)
534 {
535     PyObject * list;
536     Header h;
537     PyObject * hdr;
538
539     if (!fd) {
540         PyErr_SetFromErrno(pyrpmError);
541         return NULL;
542     }
543
544     list = PyList_New(0);
545     Py_BEGIN_ALLOW_THREADS
546     h = headerRead(fd, HEADER_MAGIC_YES);
547     Py_END_ALLOW_THREADS
548
549     while (h) {
550         headerConvert(h, HEADERCONV_RETROFIT_V3);
551         hdr = hdr_Wrap(&hdr_Type, h);
552         if (PyList_Append(list, (PyObject *) hdr)) {
553             Py_DECREF(list);
554             Py_DECREF(hdr);
555             return NULL;
556         }
557         Py_DECREF(hdr);
558
559         h = headerFree(h);      /* XXX ref held by hdr */
560
561         Py_BEGIN_ALLOW_THREADS
562         h = headerRead(fd, HEADER_MAGIC_YES);
563         Py_END_ALLOW_THREADS
564     }
565
566     return list;
567 }
568
569 PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args, PyObject * kwds)
570 {
571     FD_t fd;
572     PyObject * list;
573     char * kwlist[] = {"fd", NULL};
574
575     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist,
576                                      rpmFdFromPyObject, &fd))
577         return NULL;
578
579     list = rpmReadHeaders (fd);
580     Fclose(fd);
581
582     return list;
583 }
584
585 PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args, PyObject *kwds)
586 {
587     char * filespec;
588     FD_t fd;
589     PyObject * list;
590     char * kwlist[] = {"file", NULL};
591
592     if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &filespec))
593         return NULL;
594
595     fd = Fopen(filespec, "r.fdio");
596
597     if (!fd) {
598         PyErr_SetFromErrno(pyrpmError);
599         return NULL;
600     }
601
602     list = rpmReadHeaders (fd);
603     Fclose(fd);
604
605     return list;
606 }
607
608 /**
609  * This assumes the order of list matches the order of the new headers, and
610  * throws an exception if that isn't true.
611  */
612 int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag)
613 {
614     Header h;
615     HeaderIterator hi;
616     rpmTag newMatch, oldMatch;
617     hdrObject * hdr;
618     rpm_count_t count = 0;
619     int rc = 1; /* assume failure */
620     rpmtd td = rpmtdNew();
621
622     Py_BEGIN_ALLOW_THREADS
623     h = headerRead(fd, HEADER_MAGIC_YES);
624     Py_END_ALLOW_THREADS
625
626     while (h) {
627         if (!headerGet(h, matchTag, td, HEADERGET_MINMEM)) {
628             PyErr_SetString(pyrpmError, "match tag missing in new header");
629             goto exit;
630         }
631         newMatch = rpmtdTag(td);
632         rpmtdFreeData(td);
633
634         hdr = (hdrObject *) PyList_GetItem(list, count++);
635         if (!hdr) goto exit;
636
637         if (!headerGet(hdr->h, matchTag, td, HEADERGET_MINMEM)) {
638             PyErr_SetString(pyrpmError, "match tag missing in new header");
639             goto exit;
640         }
641         oldMatch = rpmtdTag(td);
642         rpmtdFreeData(td);
643
644         if (newMatch != oldMatch) {
645             PyErr_SetString(pyrpmError, "match tag mismatch");
646             goto exit;
647         }
648
649         for (hi = headerInitIterator(h); headerNext(hi, td); rpmtdFreeData(td))
650         {
651             /* could be dupes */
652             headerDel(hdr->h, rpmtdTag(td));
653             headerPut(hdr->h, td, HEADERPUT_DEFAULT);
654         }
655
656         headerFreeIterator(hi);
657         h = headerFree(h);
658
659         Py_BEGIN_ALLOW_THREADS
660         h = headerRead(fd, HEADER_MAGIC_YES);
661         Py_END_ALLOW_THREADS
662     }
663     rc = 0;
664
665 exit:
666     rpmtdFree(td);
667     return rc;
668 }
669
670 PyObject *
671 rpmMergeHeadersFromFD(PyObject * self, PyObject * args, PyObject * kwds)
672 {
673     FD_t fd;
674     int fileno;
675     PyObject * list;
676     int rc;
677     int matchTag;
678     char * kwlist[] = {"list", "fd", "matchTag", NULL};
679
680     if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oii", kwlist, &list,
681             &fileno, &matchTag))
682         return NULL;
683
684     if (!PyList_Check(list)) {
685         PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
686         return NULL;
687     }
688
689     fd = fdDup(fileno);
690
691     rc = rpmMergeHeaders (list, fd, matchTag);
692     Fclose(fd);
693
694     if (rc) {
695         return NULL;
696     }
697
698     Py_RETURN_NONE;
699 }
700
701 PyObject *
702 rpmSingleHeaderFromFD(PyObject * self, PyObject * args, PyObject * kwds)
703 {
704     FD_t fd;
705     int fileno;
706     off_t offset;
707     PyObject * tuple;
708     Header h;
709     char * kwlist[] = {"fd", NULL};
710
711     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &fileno))
712         return NULL;
713
714     offset = lseek(fileno, 0, SEEK_CUR);
715
716     fd = fdDup(fileno);
717
718     if (!fd) {
719         PyErr_SetFromErrno(pyrpmError);
720         return NULL;
721     }
722
723     Py_BEGIN_ALLOW_THREADS
724     h = headerRead(fd, HEADER_MAGIC_YES);
725     Py_END_ALLOW_THREADS
726
727     Fclose(fd);
728
729     tuple = PyTuple_New(2);
730
731     if (h && tuple) {
732         PyTuple_SET_ITEM(tuple, 0, hdr_Wrap(&hdr_Type, h));
733         PyTuple_SET_ITEM(tuple, 1, PyLong_FromLong(offset));
734         h = headerFree(h);
735     } else {
736         Py_INCREF(Py_None);
737         Py_INCREF(Py_None);
738         PyTuple_SET_ITEM(tuple, 0, Py_None);
739         PyTuple_SET_ITEM(tuple, 1, Py_None);
740     }
741
742     return tuple;
743 }
744
745 PyObject * versionCompare (PyObject * self, PyObject * args, PyObject * kwds)
746 {
747     hdrObject * h1, * h2;
748     char * kwlist[] = {"version0", "version1", NULL};
749
750     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!", kwlist, &hdr_Type,
751             &h1, &hdr_Type, &h2))
752         return NULL;
753
754     return Py_BuildValue("i", hdr_compare(h1, h2));
755 }
756
757 static int compare_values(const char *str1, const char *str2)
758 {
759     if (!str1 && !str2)
760         return 0;
761     else if (str1 && !str2)
762         return 1;
763     else if (!str1 && str2)
764         return -1;
765     return rpmvercmp(str1, str2);
766 }
767
768 PyObject * labelCompare (PyObject * self, PyObject * args)
769 {
770     char *v1, *r1, *v2, *r2;
771     const char *e1, *e2;
772     int rc;
773
774     if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
775                         &e1, &v1, &r1, &e2, &v2, &r2))
776         return NULL;
777
778     if (e1 == NULL)     e1 = "0";
779     if (e2 == NULL)     e2 = "0";
780
781     rc = compare_values(e1, e2);
782     if (!rc) {
783         rc = compare_values(v1, v2);
784         if (!rc)
785             rc = compare_values(r1, r2);
786     }
787     return Py_BuildValue("i", rc);
788 }
789