summaryrefslogtreecommitdiff
path: root/python/rpmfd-py.c
diff options
context:
space:
mode:
Diffstat (limited to 'python/rpmfd-py.c')
-rw-r--r--python/rpmfd-py.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/python/rpmfd-py.c b/python/rpmfd-py.c
new file mode 100644
index 0000000..f3536ea
--- /dev/null
+++ b/python/rpmfd-py.c
@@ -0,0 +1,354 @@
+
+#include "rpmsystem-py.h"
+#include <rpm/rpmstring.h>
+#include "header-py.h" /* XXX for utf8FromPyObject() only */
+#include "rpmfd-py.h"
+
+struct rpmfdObject_s {
+ PyObject_HEAD
+ PyObject *md_dict;
+ FD_t fd;
+};
+
+FD_t rpmfdGetFd(rpmfdObject *fdo)
+{
+ return fdo->fd;
+}
+
+int rpmfdFromPyObject(PyObject *obj, rpmfdObject **fdop)
+{
+ rpmfdObject *fdo = NULL;
+
+ if (rpmfdObject_Check(obj)) {
+ Py_INCREF(obj);
+ fdo = (rpmfdObject *) obj;
+ } else {
+ fdo = (rpmfdObject *) PyObject_Call((PyObject *)&rpmfd_Type,
+ Py_BuildValue("(O)", obj), NULL);
+ }
+ if (fdo == NULL) return 0;
+
+ if (Ferror(fdo->fd)) {
+ Py_DECREF(fdo);
+ PyErr_SetString(PyExc_IOError, Fstrerror(fdo->fd));
+ return 0;
+ }
+ *fdop = fdo;
+ return 1;
+}
+
+static PyObject *err_closed(void)
+{
+ PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
+ return NULL;
+}
+
+static FD_t openPath(const char *path, const char *mode, const char *flags)
+{
+ FD_t fd;
+ char *m = rstrscat(NULL, mode, ".", flags, NULL);
+ Py_BEGIN_ALLOW_THREADS
+ fd = Fopen(path, m);
+ Py_END_ALLOW_THREADS;
+ free(m);
+ return fd;
+}
+
+static PyObject *rpmfd_new(PyTypeObject *subtype,
+ PyObject *args, PyObject *kwds)
+{
+ char *kwlist[] = { "obj", "mode", "flags", NULL };
+ char *mode = "r";
+ char *flags = "ufdio";
+ PyObject *fo = NULL;
+ rpmfdObject *s = NULL;
+ FD_t fd = NULL;
+ int fdno;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ss", kwlist,
+ &fo, &mode, &flags))
+ return NULL;
+
+ if (PyBytes_Check(fo)) {
+ fd = openPath(PyBytes_AsString(fo), mode, flags);
+ } else if (PyUnicode_Check(fo)) {
+ PyObject *enc = NULL;
+ int rc;
+#if PY_MAJOR_VERSION >= 3
+ rc = PyUnicode_FSConverter(fo, &enc);
+#else
+ rc = utf8FromPyObject(fo, &enc);
+#endif
+ if (rc == 0)
+ return NULL;
+
+ fd = openPath(PyBytes_AsString(enc), mode, flags);
+ Py_DECREF(enc);
+
+ } else if ((fdno = PyObject_AsFileDescriptor(fo)) >= 0) {
+ fd = fdDup(fdno);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "path or file object expected");
+ return NULL;
+ }
+
+ if (Ferror(fd)) {
+ PyErr_SetString(PyExc_IOError, Fstrerror(fd));
+ return NULL;
+ }
+
+ if ((s = (rpmfdObject *)subtype->tp_alloc(subtype, 0)) == NULL) {
+ Fclose(fd);
+ return NULL;
+ }
+ /* TODO: remember our filename, mode & flags */
+ s->fd = fd;
+ return (PyObject*) s;
+}
+
+static PyObject *do_close(rpmfdObject *s)
+{
+ /* mimic python fileobject: close on closed file is not an error */
+ if (s->fd) {
+ Py_BEGIN_ALLOW_THREADS
+ Fclose(s->fd);
+ Py_END_ALLOW_THREADS
+ s->fd = NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *rpmfd_close(rpmfdObject *s)
+{
+ return do_close(s);
+}
+
+static void rpmfd_dealloc(rpmfdObject *s)
+{
+ PyObject *res = do_close(s);
+ Py_XDECREF(res);
+ Py_TYPE(s)->tp_free((PyObject *)s);
+}
+
+static PyObject *rpmfd_fileno(rpmfdObject *s)
+{
+ int fno;
+ if (s->fd == NULL) return err_closed();
+
+ Py_BEGIN_ALLOW_THREADS
+ fno = Fileno(s->fd);
+ Py_END_ALLOW_THREADS
+
+ if (Ferror(s->fd)) {
+ PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
+ return NULL;
+ }
+ return Py_BuildValue("i", fno);
+}
+
+static PyObject *rpmfd_flush(rpmfdObject *s)
+{
+ int rc;
+
+ if (s->fd == NULL) return err_closed();
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = Fflush(s->fd);
+ Py_END_ALLOW_THREADS
+
+ if (rc || Ferror(s->fd)) {
+ PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *rpmfd_isatty(rpmfdObject *s)
+{
+ int fileno;
+ if (s->fd == NULL) return err_closed();
+
+ Py_BEGIN_ALLOW_THREADS
+ fileno = Fileno(s->fd);
+ Py_END_ALLOW_THREADS
+
+ if (Ferror(s->fd)) {
+ PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
+ return NULL;
+ }
+ return PyBool_FromLong(isatty(fileno));
+}
+
+static PyObject *rpmfd_seek(rpmfdObject *s, PyObject *args, PyObject *kwds)
+{
+ char *kwlist[] = { "offset", "whence", NULL };
+ off_t offset;
+ int whence = SEEK_SET;
+ int rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "L|i", kwlist,
+ &offset, &whence))
+ return NULL;
+
+ if (s->fd == NULL) return err_closed();
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = Fseek(s->fd, offset, whence);
+ Py_END_ALLOW_THREADS
+ if (rc < 0 || Ferror(s->fd)) {
+ PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *rpmfd_tell(rpmfdObject *s)
+{
+ off_t offset;
+ Py_BEGIN_ALLOW_THREADS
+ offset = Ftell(s->fd);
+ Py_END_ALLOW_THREADS
+ return Py_BuildValue("L", offset);
+
+}
+
+static PyObject *rpmfd_read(rpmfdObject *s, PyObject *args, PyObject *kwds)
+{
+ char *kwlist[] = { "size", NULL };
+ char buf[BUFSIZ];
+ ssize_t chunksize = sizeof(buf);
+ ssize_t left = -1;
+ ssize_t nb = 0;
+ PyObject *res = NULL;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|l", kwlist, &left))
+ return NULL;
+
+ if (s->fd == NULL) return err_closed();
+
+ /* ConcatAndDel() doesn't work on NULL string, meh */
+ res = PyBytes_FromStringAndSize(NULL, 0);
+ do {
+ if (left >= 0 && left < chunksize)
+ chunksize = left;
+
+ Py_BEGIN_ALLOW_THREADS
+ nb = Fread(buf, 1, chunksize, s->fd);
+ Py_END_ALLOW_THREADS
+
+ if (nb > 0) {
+ PyObject *tmp = PyBytes_FromStringAndSize(buf, nb);
+ PyString_ConcatAndDel(&res, tmp);
+ left -= nb;
+ }
+ } while (nb > 0);
+
+ if (Ferror(s->fd)) {
+ PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
+ Py_XDECREF(res);
+ return NULL;
+ } else {
+ return res;
+ }
+}
+
+static PyObject *rpmfd_write(rpmfdObject *s, PyObject *args, PyObject *kwds)
+{
+
+ const char *buf = NULL;
+ ssize_t size = 0;
+ char *kwlist[] = { "buffer", NULL };
+ ssize_t rc = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &buf, &size)) {
+ return NULL;
+ }
+
+ if (s->fd == NULL) return err_closed();
+
+ Py_BEGIN_ALLOW_THREADS
+ rc = Fwrite(buf, 1, size, s->fd);
+ Py_END_ALLOW_THREADS
+
+ if (Ferror(s->fd)) {
+ PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
+ return NULL;
+ }
+ return Py_BuildValue("n", rc);
+}
+
+static char rpmfd_doc[] = "";
+
+static struct PyMethodDef rpmfd_methods[] = {
+ { "close", (PyCFunction) rpmfd_close, METH_NOARGS,
+ NULL },
+ { "fileno", (PyCFunction) rpmfd_fileno, METH_NOARGS,
+ NULL },
+ { "flush", (PyCFunction) rpmfd_flush, METH_NOARGS,
+ NULL },
+ { "isatty", (PyCFunction) rpmfd_isatty, METH_NOARGS,
+ NULL },
+ { "read", (PyCFunction) rpmfd_read, METH_VARARGS|METH_KEYWORDS,
+ NULL },
+ { "seek", (PyCFunction) rpmfd_seek, METH_VARARGS|METH_KEYWORDS,
+ NULL },
+ { "tell", (PyCFunction) rpmfd_tell, METH_NOARGS,
+ NULL },
+ { "write", (PyCFunction) rpmfd_write, METH_VARARGS|METH_KEYWORDS,
+ NULL },
+ { NULL, NULL }
+};
+
+static PyObject *rpmfd_get_closed(rpmfdObject *s)
+{
+ return PyBool_FromLong((s->fd == NULL));
+}
+
+static PyGetSetDef rpmfd_getseters[] = {
+ { "closed", (getter)rpmfd_get_closed, NULL, NULL },
+ { NULL },
+};
+
+PyTypeObject rpmfd_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "rpm.fd", /* tp_name */
+ sizeof(rpmfdObject), /* tp_size */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor) rpmfd_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ (getattrfunc)0, /* tp_getattr */
+ (setattrfunc)0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ (hashfunc)0, /* tp_hash */
+ (ternaryfunc)0, /* tp_call */
+ (reprfunc)0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ PyObject_GenericSetAttr, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
+ rpmfd_doc, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ rpmfd_methods, /* tp_methods */
+ 0, /* tp_members */
+ rpmfd_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)0, /* tp_init */
+ (allocfunc)0, /* tp_alloc */
+ (newfunc) rpmfd_new, /* tp_new */
+ (freefunc)0, /* tp_free */
+ 0, /* tp_is_gc */
+};