#include "rpmsystem-py.h" #include #include #include "header-py.h" #include "rpmfiles-py.h" #include "rpmfd-py.h" #include "rpmarchive-py.h" #include "rpmstrpool-py.h" /* A single file from rpmfiles set, can't be independently instanciated */ struct rpmfileObject_s { PyObject_HEAD PyObject *md_dict; rpmfiles files; /* reference to rpmfiles */ int ix; /* index to rpmfiles */ }; static void rpmfile_dealloc(rpmfileObject * s) { s->files = rpmfilesFree(s->files); Py_TYPE(s)->tp_free((PyObject *)s); } static char rpmfile_doc[] = "Gives access to the meta data of a single file.\n\n" "Instances of this class are only available through an rpm.files object."; static PyObject *rpmfile_fx(rpmfileObject *s) { return Py_BuildValue("i", s->ix); } static PyObject *rpmfile_dx(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesDI(s->files, s->ix)); } static PyObject *rpmfile_name(rpmfileObject *s) { char * fn = rpmfilesFN(s->files, s->ix); PyObject *o = utf8FromString(fn); free(fn); return o; } static PyObject *rpmfile_basename(rpmfileObject *s) { return utf8FromString(rpmfilesBN(s->files, s->ix)); } static PyObject *rpmfile_dirname(rpmfileObject *s) { return utf8FromString(rpmfilesDN(s->files, rpmfilesDI(s->files, s->ix))); } static PyObject *rpmfile_orig_name(rpmfileObject *s) { char * fn = rpmfilesOFN(s->files, s->ix); PyObject *o = utf8FromString(fn); free(fn); return o; } static PyObject *rpmfile_orig_basename(rpmfileObject *s) { return utf8FromString(rpmfilesOBN(s->files, s->ix)); } static PyObject *rpmfile_orig_dirname(rpmfileObject *s) { return utf8FromString(rpmfilesODN(s->files, rpmfilesODI(s->files, s->ix))); } static PyObject *rpmfile_mode(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesFMode(s->files, s->ix)); } static PyObject *rpmfile_size(rpmfileObject *s) { return Py_BuildValue("L", rpmfilesFSize(s->files, s->ix)); } static PyObject *rpmfile_mtime(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesFMtime(s->files, s->ix)); } static PyObject *rpmfile_rdev(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesFRdev(s->files, s->ix)); } static PyObject *rpmfile_inode(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesFInode(s->files, s->ix)); } static PyObject *rpmfile_nlink(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesFNlink(s->files, s->ix)); } static PyObject *rpmfile_linkto(rpmfileObject *s) { return utf8FromString(rpmfilesFLink(s->files, s->ix)); } static PyObject *rpmfile_user(rpmfileObject *s) { return utf8FromString(rpmfilesFUser(s->files, s->ix)); } static PyObject *rpmfile_group(rpmfileObject *s) { return utf8FromString(rpmfilesFGroup(s->files, s->ix)); } static PyObject *rpmfile_fflags(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesFFlags(s->files, s->ix)); } static PyObject *rpmfile_vflags(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesVFlags(s->files, s->ix)); } static PyObject *rpmfile_color(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesFColor(s->files, s->ix)); } static PyObject *rpmfile_state(rpmfileObject *s) { return Py_BuildValue("i", rpmfilesFState(s->files, s->ix)); } static PyObject *rpmfile_digest(rpmfileObject *s) { size_t diglen = 0; const unsigned char *digest = rpmfilesFDigest(s->files, s->ix, NULL, &diglen); if (digest) { char * hex = rpmhex(digest, diglen); PyObject *o = utf8FromString(hex); free(hex); return o; } Py_RETURN_NONE; } static PyObject *bytebuf(const unsigned char *buf, size_t len) { if (buf) { PyObject *o = PyBytes_FromStringAndSize((const char *)buf, len); return o; } Py_RETURN_NONE; } static PyObject *rpmfile_imasig(rpmfileObject *s) { size_t len = 0; const unsigned char *sig = rpmfilesFSignature(s->files, s->ix, &len); return bytebuf(sig, len); } static PyObject *rpmfile_veritysig(rpmfileObject *s) { size_t len = 0; const unsigned char *sig = rpmfilesVSignature(s->files, s->ix, &len, NULL); return bytebuf(sig, len); } static PyObject *rpmfile_class(rpmfileObject *s) { return utf8FromString(rpmfilesFClass(s->files, s->ix)); } static PyObject *rpmfile_caps(rpmfileObject *s) { return utf8FromString(rpmfilesFCaps(s->files, s->ix)); } static PyObject *rpmfile_langs(rpmfileObject *s) { return utf8FromString(rpmfilesFLangs(s->files, s->ix)); } static PyObject *rpmfile_links(rpmfileObject *s) { PyObject *result = NULL; const int * links = NULL; uint32_t nlinks = rpmfilesFLinks(s->files, s->ix, &links); if (nlinks == 0) Py_RETURN_NONE; else if (nlinks == 1) links = &s->ix; /* file itself */ result = PyTuple_New(nlinks); if (result) { for (uint32_t i = 0; i < nlinks; i++) { int lix = links[i]; PyObject * o; if (lix == s->ix) { /* file itself, return a reference instead of new object */ Py_INCREF(s); o = (PyObject *) s; } else { o = rpmfile_Wrap(s->files, lix); } PyTuple_SET_ITEM(result, i, o); } } return result; } /* * Exported as "matches" instead of a rich comparison operator or such * as this cannot be used for comparing file *object* equality, * rpmfilesCompare() determines whether the file *contents* match. */ static PyObject *rpmfile_matches(rpmfileObject *s, PyObject *o) { PyObject *result = NULL; if (rpmfileObject_Check(o)) { rpmfileObject *of = (rpmfileObject *)o; int rc = rpmfilesCompare(s->files, s->ix, of->files, of->ix); result = PyBool_FromLong(rc == 0); } else { PyErr_SetObject(PyExc_TypeError, o); } return result; } static PyObject *rpmfile_verify(rpmfileObject *s, PyObject *args, PyObject *kwds) { static char *kwlist[] = { "omitMask", NULL }; rpmVerifyAttrs omitMask = 0; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwlist, &omitMask)) return NULL; return Py_BuildValue("i", rpmfilesVerify(s->files, s->ix, omitMask)); } static PyGetSetDef rpmfile_getseters[] = { { "fx", (getter) rpmfile_fx, NULL, "index in header and rpm.files object" }, { "dx", (getter) rpmfile_dx, NULL, "index of dirname entry" }, { "name", (getter) rpmfile_name, NULL, "file name (path)" }, { "basename", (getter) rpmfile_basename, NULL, NULL }, { "dirname", (getter) rpmfile_dirname, NULL, NULL }, { "orig_name", (getter) rpmfile_orig_name, NULL, "original file name (may differ due to relocation)" }, { "orig_basename", (getter) rpmfile_orig_basename, NULL, "original base name (may differ due to relocation)" }, { "orig_dirname", (getter) rpmfile_orig_dirname, NULL, "original dir name (may differ due to relocation)" }, { "mode", (getter) rpmfile_mode, NULL, "mode flags / unix permissions" }, { "mtime", (getter) rpmfile_mtime, NULL, "modification time (in unix time)" }, { "size", (getter) rpmfile_size, NULL, "file size" }, { "rdev", (getter) rpmfile_rdev, NULL, "device number - for device files only" }, { "inode", (getter) rpmfile_inode, NULL, "inode number - contains fake, data used to identify hard liked files" }, { "fflags", (getter) rpmfile_fflags, NULL, "file flags - see RPMFILE_* constants" }, { "vflags", (getter) rpmfile_vflags, NULL, "verification flags - see RPMVERIFY_* (in rpmfiles.h)" }, { "linkto", (getter) rpmfile_linkto, NULL, "link target - symlinks only" }, { "color", (getter) rpmfile_color, NULL, "file color - 2 for 64 bit binaries, 1 for 32 bit binaries, 0 else" }, { "nlink", (getter) rpmfile_nlink, NULL, "number of hardlinks pointing to the same content as this file" }, { "links", (getter) rpmfile_links, NULL, "list of file indexes that are hardlinked with this file" }, { "user", (getter) rpmfile_user, NULL, "user name owning this file" }, { "group", (getter) rpmfile_group, NULL, "group name owning this file" }, { "digest", (getter) rpmfile_digest, NULL, "check sum of file content" }, { "class", (getter) rpmfile_class, NULL, "classfication of file content based on libmagic/file(1)" }, { "state", (getter) rpmfile_state, NULL, "file state - see RPMFILE_STATE_* constants" }, { "langs", (getter) rpmfile_langs, NULL, "language the file provides (typically for doc files)" }, { "caps", (getter) rpmfile_caps, NULL, "file capabilities" }, { "imasig", (getter) rpmfile_imasig, NULL, "IMA signature" }, { "veritysig", (getter) rpmfile_veritysig, NULL, "Verity signature" }, { NULL, NULL, NULL, NULL } }; static struct PyMethodDef rpmfile_methods[] = { { "matches", (PyCFunction) rpmfile_matches, METH_O, NULL }, { "verify", (PyCFunction) rpmfile_verify, METH_VARARGS|METH_KEYWORDS, NULL }, { NULL, NULL, 0, NULL } }; PyTypeObject rpmfile_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "rpm.file", /* tp_name */ sizeof(rpmfileObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor) rpmfile_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ (reprfunc)rpmfile_name, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ rpmfile_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ rpmfile_methods, /* tp_methods */ 0, /* tp_members */ rpmfile_getseters, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ 0, /* tp_is_gc */ }; PyObject * rpmfile_Wrap(rpmfiles files, int ix) { rpmfileObject *s = PyObject_New(rpmfileObject, &rpmfile_Type); if (s == NULL) return NULL; s->files = rpmfilesLink(files); s->ix = ix; return (PyObject *) s; } /* The actual rpmfiles info set */ struct rpmfilesObject_s { PyObject_HEAD PyObject *md_dict; /*!< to look like PyModuleObject */ rpmfiles files; }; static void rpmfiles_dealloc(rpmfilesObject * s) { s->files = rpmfilesFree(s->files); Py_TYPE(s)->tp_free((PyObject *)s); } static PyObject * rpmfiles_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds) { PyObject * to = NULL; Header h = NULL; rpmfiles files = NULL; rpmTagVal tagN = RPMTAG_BASENAMES; int flags = 0; rpmstrPool pool = NULL; char * kwlist[] = {"header", "tag", "flags", "pool", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|OiO&:rpmfiles_new", kwlist, hdrFromPyObject, &h, &to, &flags, poolFromPyObject, &pool)) return NULL; files = rpmfilesNew(pool, h, tagN, flags); if (files == NULL) { PyErr_SetString(PyExc_ValueError, "invalid file data in header"); return NULL; } return rpmfiles_Wrap(subtype, files); } static Py_ssize_t rpmfiles_length(rpmfilesObject *s) { return rpmfilesFC(s->files); } static PyObject * rpmfiles_getitem(rpmfilesObject *s, Py_ssize_t ix) { if (ix >= 0 && ix < rpmfilesFC(s->files)) return rpmfile_Wrap(s->files, ix); PyErr_SetObject(PyExc_IndexError, Py_BuildValue("i", ix)); return NULL; } static int rpmfiles_contains(rpmfilesObject *s, PyObject *value) { const char *fn = NULL; if (!PyArg_Parse(value, "s", &fn)) return -1; return (rpmfilesFindFN(s->files, fn) >= 0) ? 1 : 0; } static PySequenceMethods rpmfiles_as_sequence = { (lenfunc)rpmfiles_length, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ (ssizeargfunc) rpmfiles_getitem, /* sq_item */ 0, /* sq_slice */ 0, /* sq_ass_item */ 0, /* sq_ass_slice */ (objobjproc)rpmfiles_contains, /* sq_contains */ 0, /* sq_inplace_concat */ 0, /* sq_inplace_repeat */ }; static PyObject * rpmfiles_find(rpmfileObject *s, PyObject *args, PyObject *kwds) { const char *fn = NULL; int fx, orig = 0; char * kwlist[] = {"filename", "orig", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &fn, &orig)) return NULL; if (orig) fx = rpmfilesFindOFN(s->files, fn); else fx = rpmfilesFindFN(s->files, fn); if (fx >= 0) return rpmfile_Wrap(s->files, fx); Py_RETURN_NONE; } static PyObject *rpmfiles_archive(rpmfilesObject *s, PyObject *args, PyObject *kwds) { char * kwlist[] = {"fd", "write", NULL}; rpmfdObject *fdo = NULL; FD_t fd = NULL; rpmfi archive = NULL; int writer = 0; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|i", kwlist, rpmfdFromPyObject, &fdo, &writer)) { return NULL; } fd = rpmfdGetFd(fdo); if (writer) { archive = rpmfiNewArchiveWriter(fd, s->files); } else { archive = rpmfiNewArchiveReader(fd, s->files, RPMFI_ITER_READ_ARCHIVE); } return rpmarchive_Wrap(&rpmarchive_Type, s->files, archive); } static PyObject *rpmfiles_subscript(rpmfilesObject *s, PyObject *item) { PyObject *str = NULL; /* treat numbers as sequence accesses */ if (PyLong_Check(item)) { return rpmfiles_getitem(s, PyLong_AsSsize_t(item)); } /* handle slices by returning tuples of rpm.file items */ if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength, i, cur; PyObject * result; if (PySlice_GetIndicesEx(item, rpmfiles_length(s), &start, &stop, &step, &slicelength) < 0) { return NULL; } result = PyTuple_New(slicelength); if (result) { for (cur = start, i = 0; i < slicelength; cur += step, i++) { PyTuple_SET_ITEM(result, i, rpmfiles_getitem(s, cur)); } } return result; } /* ... and strings as mapping access */ if (utf8FromPyObject(item, &str)) { int fx = rpmfilesFindFN(s->files, PyBytes_AsString(str)); Py_DECREF(str); if (fx >= 0) { return rpmfile_Wrap(s->files, fx); } else { PyErr_SetObject(PyExc_KeyError, item); } } else { PyErr_SetObject(PyExc_TypeError, item); } return NULL; } static PyMappingMethods rpmfiles_as_mapping = { (lenfunc) rpmfiles_length, /* mp_length */ (binaryfunc) rpmfiles_subscript, /* mp_subscript */ 0, /* mp_ass_subscript */ }; static struct PyMethodDef rpmfiles_methods[] = { { "archive", (PyCFunction) rpmfiles_archive, METH_VARARGS|METH_KEYWORDS, "files.archive(fd, write=False) -- Return a rpm.archive object\n\n" "Args:\n" " fd : File to read from or write to.\n" " write : True to get an archive writer, False for an archive reader"}, { "find", (PyCFunction) rpmfiles_find, METH_VARARGS|METH_KEYWORDS, "files.find(filename, orig=False) -- Return index of given file name.\n\n" " Return -1 if file is not found.\n" " Leading \".\" in filename is ignored."}, { NULL, NULL, 0, NULL } }; static char rpmfiles_doc[] = "rpm.files(hdr, tag=RPMTAG_BASENAMES, flags=None, pool=None)\n\n" "Stores the meta data of a package's files.\n\n" "Args:\n" "\thdr: The header object to get the data from.\n" "\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" "\tpool : rpm.strpool object to store the strings in.\n\t\tLeave empty to use global pool.\n" "\ttag : Obsolete. Leave alone!\n\n" "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."; PyTypeObject rpmfiles_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "rpm.files", /* tp_name */ sizeof(rpmfilesObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor) rpmfiles_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ &rpmfiles_as_sequence, /* tp_as_sequence */ &rpmfiles_as_mapping, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ PyObject_GenericSetAttr, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ rpmfiles_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ rpmfiles_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ (newfunc) rpmfiles_new, /* tp_new */ 0, /* tp_free */ 0, /* tp_is_gc */ }; PyObject * rpmfiles_Wrap(PyTypeObject *subtype, rpmfiles files) { rpmfilesObject *s = (rpmfilesObject *)subtype->tp_alloc(subtype, 0); if (s == NULL) return NULL; s->files = files; return (PyObject *) s; }