1 #include "rpmsystem-py.h"
3 #include <rpm/rpmtypes.h>
4 #include <rpm/rpmpgp.h>
8 #include "rpmfiles-py.h"
10 #include "rpmarchive-py.h"
11 #include "rpmstrpool-py.h"
13 /* A single file from rpmfiles set, can't be independently instanciated */
14 struct rpmfileObject_s {
17 rpmfiles files; /* reference to rpmfiles */
18 int ix; /* index to rpmfiles */
21 static void rpmfile_dealloc(rpmfileObject * s)
23 s->files = rpmfilesFree(s->files);
24 Py_TYPE(s)->tp_free((PyObject *)s);
27 static char rpmfile_doc[] =
28 "Gives access to the meta data of a single file.\n\n"
29 "Instances of this class are only available through an rpm.files object.";
31 static PyObject *rpmfile_fx(rpmfileObject *s)
33 return Py_BuildValue("i", s->ix);
36 static PyObject *rpmfile_dx(rpmfileObject *s)
38 return Py_BuildValue("i", rpmfilesDI(s->files, s->ix));
41 static PyObject *rpmfile_name(rpmfileObject *s)
43 char * fn = rpmfilesFN(s->files, s->ix);
44 PyObject *o = utf8FromString(fn);
49 static PyObject *rpmfile_basename(rpmfileObject *s)
51 return utf8FromString(rpmfilesBN(s->files, s->ix));
54 static PyObject *rpmfile_dirname(rpmfileObject *s)
56 return utf8FromString(rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix)));
59 static PyObject *rpmfile_orig_name(rpmfileObject *s)
61 char * fn = rpmfilesOFN(s->files, s->ix);
62 PyObject *o = utf8FromString(fn);
67 static PyObject *rpmfile_orig_basename(rpmfileObject *s)
69 return utf8FromString(rpmfilesOBN(s->files, s->ix));
72 static PyObject *rpmfile_orig_dirname(rpmfileObject *s)
74 return utf8FromString(rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix)));
76 static PyObject *rpmfile_mode(rpmfileObject *s)
78 return Py_BuildValue("i", rpmfilesFMode(s->files, s->ix));
81 static PyObject *rpmfile_size(rpmfileObject *s)
83 return Py_BuildValue("L", rpmfilesFSize(s->files, s->ix));
86 static PyObject *rpmfile_mtime(rpmfileObject *s)
88 return Py_BuildValue("i", rpmfilesFMtime(s->files, s->ix));
91 static PyObject *rpmfile_rdev(rpmfileObject *s)
93 return Py_BuildValue("i", rpmfilesFRdev(s->files, s->ix));
96 static PyObject *rpmfile_inode(rpmfileObject *s)
98 return Py_BuildValue("i", rpmfilesFInode(s->files, s->ix));
101 static PyObject *rpmfile_nlink(rpmfileObject *s)
103 return Py_BuildValue("i", rpmfilesFNlink(s->files, s->ix));
106 static PyObject *rpmfile_linkto(rpmfileObject *s)
108 return utf8FromString(rpmfilesFLink(s->files, s->ix));
111 static PyObject *rpmfile_user(rpmfileObject *s)
113 return utf8FromString(rpmfilesFUser(s->files, s->ix));
116 static PyObject *rpmfile_group(rpmfileObject *s)
118 return utf8FromString(rpmfilesFGroup(s->files, s->ix));
121 static PyObject *rpmfile_fflags(rpmfileObject *s)
123 return Py_BuildValue("i", rpmfilesFFlags(s->files, s->ix));
126 static PyObject *rpmfile_vflags(rpmfileObject *s)
128 return Py_BuildValue("i", rpmfilesVFlags(s->files, s->ix));
131 static PyObject *rpmfile_color(rpmfileObject *s)
133 return Py_BuildValue("i", rpmfilesFColor(s->files, s->ix));
136 static PyObject *rpmfile_state(rpmfileObject *s)
138 return Py_BuildValue("i", rpmfilesFState(s->files, s->ix));
141 static PyObject *rpmfile_digest(rpmfileObject *s)
144 const unsigned char *digest = rpmfilesFDigest(s->files, s->ix,
147 char * hex = pgpHexStr(digest, diglen);
148 PyObject *o = utf8FromString(hex);
155 static PyObject *rpmfile_class(rpmfileObject *s)
157 return utf8FromString(rpmfilesFClass(s->files, s->ix));
160 static PyObject *rpmfile_caps(rpmfileObject *s)
162 return utf8FromString(rpmfilesFCaps(s->files, s->ix));
165 static PyObject *rpmfile_langs(rpmfileObject *s)
167 return utf8FromString(rpmfilesFLangs(s->files, s->ix));
170 static PyObject *rpmfile_links(rpmfileObject *s)
172 PyObject *result = NULL;
173 const int * links = NULL;
174 uint32_t nlinks = rpmfilesFLinks(s->files, s->ix, &links);
178 else if (nlinks == 1)
179 links = &s->ix; /* file itself */
181 result = PyTuple_New(nlinks);
183 for (uint32_t i = 0; i < nlinks; i++) {
188 /* file itself, return a reference instead of new object */
192 o = rpmfile_Wrap(s->files, lix);
195 PyTuple_SET_ITEM(result, i, o);
202 * Exported as "matches" instead of a rich comparison operator or such
203 * as this cannot be used for comparing file *object* equality,
204 * rpmfilesCompare() determines whether the file *contents* match.
206 static PyObject *rpmfile_matches(rpmfileObject *s, PyObject *o)
208 PyObject *result = NULL;
209 if (rpmfileObject_Check(o)) {
210 rpmfileObject *of = (rpmfileObject *)o;
211 int rc = rpmfilesCompare(s->files, s->ix, of->files, of->ix);
212 result = PyBool_FromLong(rc == 0);
214 PyErr_SetObject(PyExc_TypeError, o);
219 static PyObject *rpmfile_verify(rpmfileObject *s, PyObject *args, PyObject *kwds)
221 static char *kwlist[] = { "omitMask", NULL };
222 rpmVerifyAttrs omitMask = 0;
224 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &omitMask))
227 return Py_BuildValue("i", rpmfilesVerify(s->files, s->ix, omitMask));
230 static PyGetSetDef rpmfile_getseters[] = {
231 { "fx", (getter) rpmfile_fx, NULL,
232 "index in header and rpm.files object" },
233 { "dx", (getter) rpmfile_dx, NULL,
234 "index of dirname entry" },
235 { "name", (getter) rpmfile_name, NULL,
236 "file name (path)" },
237 { "basename", (getter) rpmfile_basename, NULL, NULL },
238 { "dirname", (getter) rpmfile_dirname, NULL, NULL },
239 { "orig_name", (getter) rpmfile_orig_name, NULL,
240 "original file name (may differ due to relocation)" },
241 { "orig_basename", (getter) rpmfile_orig_basename, NULL,
242 "original base name (may differ due to relocation)" },
243 { "orig_dirname", (getter) rpmfile_orig_dirname, NULL,
244 "original dir name (may differ due to relocation)" },
245 { "mode", (getter) rpmfile_mode, NULL,
246 "mode flags / unix permissions" },
247 { "mtime", (getter) rpmfile_mtime, NULL,
248 "modification time (in unix time)" },
249 { "size", (getter) rpmfile_size, NULL,
251 { "rdev", (getter) rpmfile_rdev, NULL,
252 "device number - for device files only" },
253 { "inode", (getter) rpmfile_inode, NULL,
254 "inode number - contains fake, data used to identify hard liked files" },
255 { "fflags", (getter) rpmfile_fflags, NULL,
256 "file flags - see RPMFILE_* constants" },
257 { "vflags", (getter) rpmfile_vflags, NULL,
258 "verification flags - see RPMVERIFY_* (in rpmvf.h)" },
259 { "linkto", (getter) rpmfile_linkto, NULL,
260 "link target - symlinks only" },
261 { "color", (getter) rpmfile_color, NULL,
262 "file color - 2 for 64 bit binaries, 1 for 32 bit binaries, 0 else" },
263 { "nlink", (getter) rpmfile_nlink, NULL,
264 "number of hardlinks pointing to the same content as this file" },
265 { "links", (getter) rpmfile_links, NULL,
266 "list of file indexes that are hardlinked with this file" },
267 { "user", (getter) rpmfile_user, NULL,
268 "user name owning this file" },
269 { "group", (getter) rpmfile_group, NULL,
270 "group name owning this file" },
271 { "digest", (getter) rpmfile_digest, NULL,
272 "check sum of file content" },
273 { "class", (getter) rpmfile_class, NULL,
274 "classfication of file content based on libmagic/file(1)" },
275 { "state", (getter) rpmfile_state, NULL,
276 "file state - see RPMFILE_STATE_* constants" },
277 { "langs", (getter) rpmfile_langs, NULL,
278 "language the file provides (typically for doc files)" },
279 { "caps", (getter) rpmfile_caps, NULL,
280 "file capabilities" },
281 { NULL, NULL, NULL, NULL }
284 static struct PyMethodDef rpmfile_methods[] = {
285 { "matches", (PyCFunction) rpmfile_matches, METH_O,
287 { "verify", (PyCFunction) rpmfile_verify, METH_VARARGS|METH_KEYWORDS,
289 { NULL, NULL, 0, NULL }
292 PyTypeObject rpmfile_Type = {
293 PyVarObject_HEAD_INIT(&PyType_Type, 0)
294 "rpm.file", /* tp_name */
295 sizeof(rpmfileObject), /* tp_basicsize */
298 (destructor) rpmfile_dealloc, /* tp_dealloc */
304 0, /* tp_as_number */
305 0, /* tp_as_sequence */
306 0, /* tp_as_mapping */
309 (reprfunc)rpmfile_name, /* tp_str */
310 PyObject_GenericGetAttr, /* tp_getattro */
311 PyObject_GenericSetAttr, /* tp_setattro */
312 0, /* tp_as_buffer */
313 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
314 rpmfile_doc, /* tp_doc */
317 0, /* tp_richcompare */
318 0, /* tp_weaklistoffset */
321 rpmfile_methods, /* tp_methods */
323 rpmfile_getseters, /* tp_getset */
326 0, /* tp_descr_get */
327 0, /* tp_descr_set */
328 0, /* tp_dictoffset */
336 PyObject * rpmfile_Wrap(rpmfiles files, int ix)
338 rpmfileObject *s = PyObject_New(rpmfileObject, &rpmfile_Type);
339 if (s == NULL) return NULL;
341 s->files = rpmfilesLink(files);
343 return (PyObject *) s;
346 /* The actual rpmfiles info set */
347 struct rpmfilesObject_s {
349 PyObject *md_dict; /*!< to look like PyModuleObject */
353 static void rpmfiles_dealloc(rpmfilesObject * s)
355 s->files = rpmfilesFree(s->files);
356 Py_TYPE(s)->tp_free((PyObject *)s);
359 static PyObject * rpmfiles_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
361 PyObject * to = NULL;
363 rpmfiles files = NULL;
364 rpmTagVal tagN = RPMTAG_BASENAMES;
366 rpmstrPool pool = NULL;
367 char * kwlist[] = {"header", "tag", "flags", "pool", NULL};
369 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|OiO&:rpmfiles_new", kwlist,
370 hdrFromPyObject, &h, &to, &flags,
371 poolFromPyObject, &pool))
374 files = rpmfilesNew(pool, h, tagN, flags);
377 PyErr_SetString(PyExc_ValueError, "invalid file data in header");
381 return rpmfiles_Wrap(subtype, files);
384 static Py_ssize_t rpmfiles_length(rpmfilesObject *s)
386 return rpmfilesFC(s->files);
389 static PyObject * rpmfiles_getitem(rpmfilesObject *s, Py_ssize_t ix)
391 if (ix >= 0 && ix < rpmfilesFC(s->files))
392 return rpmfile_Wrap(s->files, ix);
394 PyErr_SetObject(PyExc_IndexError, Py_BuildValue("i", ix));
398 static int rpmfiles_contains(rpmfilesObject *s, PyObject *value)
400 const char *fn = NULL;
402 if (!PyArg_Parse(value, "s", &fn))
405 return (rpmfilesFindFN(s->files, fn) >= 0) ? 1 : 0;
408 static PySequenceMethods rpmfiles_as_sequence = {
409 (lenfunc)rpmfiles_length, /* sq_length */
412 (ssizeargfunc) rpmfiles_getitem, /* sq_item */
415 0, /* sq_ass_slice */
416 (objobjproc)rpmfiles_contains, /* sq_contains */
417 0, /* sq_inplace_concat */
418 0, /* sq_inplace_repeat */
421 static PyObject * rpmfiles_find(rpmfileObject *s,
422 PyObject *args, PyObject *kwds)
424 const char *fn = NULL;
426 char * kwlist[] = {"filename", "orig", NULL};
428 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &fn, &orig))
432 fx = rpmfilesFindOFN(s->files, fn);
434 fx = rpmfilesFindFN(s->files, fn);
437 return rpmfile_Wrap(s->files, fx);
442 static PyObject *rpmfiles_archive(rpmfilesObject *s,
443 PyObject *args, PyObject *kwds)
445 char * kwlist[] = {"fd", "write", NULL};
446 rpmfdObject *fdo = NULL;
448 rpmfi archive = NULL;
451 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist,
452 rpmfdFromPyObject, &fdo, &writer)) {
456 fd = rpmfdGetFd(fdo);
458 archive = rpmfiNewArchiveWriter(fd, s->files);
460 archive = rpmfiNewArchiveReader(fd, s->files, RPMFI_ITER_READ_ARCHIVE);
463 return rpmarchive_Wrap(&rpmarchive_Type, s->files, archive);
466 static PyObject *rpmfiles_subscript(rpmfilesObject *s, PyObject *item)
468 PyObject *str = NULL;
470 /* treat numbers as sequence accesses */
471 if (PyInt_Check(item)) {
472 return rpmfiles_getitem(s, PyInt_AsSsize_t(item));
473 } else if (PyLong_Check(item)) {
474 return rpmfiles_getitem(s, PyLong_AsSsize_t(item));
477 /* handle slices by returning tuples of rpm.file items */
478 if (PySlice_Check(item)) {
479 Py_ssize_t start, stop, step, slicelength, i, cur;
482 if (PySlice_GetIndicesEx(
483 #if PY_MAJOR_VERSION < 3
486 item, rpmfiles_length(s),
487 &start, &stop, &step, &slicelength) < 0) {
491 result = PyTuple_New(slicelength);
493 for (cur = start, i = 0; i < slicelength; cur += step, i++) {
494 PyTuple_SET_ITEM(result, i, rpmfiles_getitem(s, cur));
500 /* ... and strings as mapping access */
501 if (utf8FromPyObject(item, &str)) {
502 int fx = rpmfilesFindFN(s->files, PyBytes_AsString(str));
506 return rpmfile_Wrap(s->files, fx);
508 PyErr_SetObject(PyExc_KeyError, item);
511 PyErr_SetObject(PyExc_TypeError, item);
517 static PyMappingMethods rpmfiles_as_mapping = {
518 (lenfunc) rpmfiles_length, /* mp_length */
519 (binaryfunc) rpmfiles_subscript, /* mp_subscript */
520 0, /* mp_ass_subscript */
523 static struct PyMethodDef rpmfiles_methods[] = {
524 { "archive", (PyCFunction) rpmfiles_archive, METH_VARARGS|METH_KEYWORDS,
525 "files.archive(fd, write=False) -- Return a rpm.archive object\n\n"
527 " fd : File to read from or write to.\n"
528 " write : True to get an archive writer, False for an archive reader"},
529 { "find", (PyCFunction) rpmfiles_find, METH_VARARGS|METH_KEYWORDS,
530 "files.find(filename, orig=False) -- Return index of given file name.\n\n"
531 " Return -1 if file is not found.\n"
532 " Leading \".\" in filename is ignored."},
533 { NULL, NULL, 0, NULL }
536 static char rpmfiles_doc[] =
537 "rpm.files(hdr, tag=RPMTAG_BASENAMES, flags=None, pool=None)\n\n"
538 "Stores the meta data of a package's files.\n\n"
540 "\thdr: The header object to get the data from.\n"
541 "\tflags : Controls which data to store and whether to create\n\t\tcopies or use the data from the header.\n\t\tBy default all data is copied.\n\t\tSee RPMFI_* constants in rpmfiles.h.\n"
542 "\tpool : rpm.strpool object to store the strings in.\n\t\tLeave empty to use global pool.\n"
543 "\ttag : Obsolete. Leave alone!\n\n"
544 "rpm.files is basically a sequence of rpm.file objects.\nNote that this is a read only data structure. To write file data you\nhave to write it directly into aheader object.";
546 PyTypeObject rpmfiles_Type = {
547 PyVarObject_HEAD_INIT(&PyType_Type, 0)
548 "rpm.files", /* tp_name */
549 sizeof(rpmfilesObject), /* tp_basicsize */
552 (destructor) rpmfiles_dealloc, /* tp_dealloc */
558 0, /* tp_as_number */
559 &rpmfiles_as_sequence, /* tp_as_sequence */
560 &rpmfiles_as_mapping, /* tp_as_mapping */
564 PyObject_GenericGetAttr, /* tp_getattro */
565 PyObject_GenericSetAttr, /* tp_setattro */
566 0, /* tp_as_buffer */
567 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
568 rpmfiles_doc, /* tp_doc */
571 0, /* tp_richcompare */
572 0, /* tp_weaklistoffset */
575 rpmfiles_methods, /* tp_methods */
580 0, /* tp_descr_get */
581 0, /* tp_descr_set */
582 0, /* tp_dictoffset */
585 (newfunc) rpmfiles_new, /* tp_new */
590 PyObject * rpmfiles_Wrap(PyTypeObject *subtype, rpmfiles files)
592 rpmfilesObject *s = (rpmfilesObject *)subtype->tp_alloc(subtype, 0);
593 if (s == NULL) return NULL;
596 return (PyObject *) s;