2 #include "rpmsystem-py.h"
3 #include <rpm/rpmstring.h>
4 #include "header-py.h" /* XXX for utf8FromPyObject() only */
15 FD_t rpmfdGetFd(rpmfdObject *fdo)
20 int rpmfdFromPyObject(PyObject *obj, rpmfdObject **fdop)
22 rpmfdObject *fdo = NULL;
24 if (rpmfdObject_Check(obj)) {
26 fdo = (rpmfdObject *) obj;
28 fdo = (rpmfdObject *) PyObject_CallFunctionObjArgs((PyObject *)&rpmfd_Type,
31 if (fdo == NULL) return 0;
33 if (Ferror(fdo->fd)) {
34 PyErr_SetString(PyExc_IOError, Fstrerror(fdo->fd));
42 static PyObject *err_closed(void)
44 PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
48 static FD_t openPath(const char *path, const char *mode)
51 Py_BEGIN_ALLOW_THREADS
52 fd = Fopen(path, mode);
57 static FD_t openFd(FD_t ofd, const char *mode)
60 Py_BEGIN_ALLOW_THREADS
61 fd = Fdopen(ofd, mode);
66 static int rpmfd_init(rpmfdObject *s, PyObject *args, PyObject *kwds)
68 char *kwlist[] = { "obj", "mode", "flags", NULL };
69 const char *mode = "r";
70 const char *flags = "ufdio";
71 char *rpmio_mode = NULL;
76 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ss", kwlist,
80 rpmio_mode = rstrscat(NULL, mode, ".", flags, NULL);
82 if (PyBytes_Check(fo)) {
83 fd = openPath(PyBytes_AsString(fo), rpmio_mode);
84 } else if (PyUnicode_Check(fo)) {
87 #if PY_MAJOR_VERSION >= 3
88 rc = PyUnicode_FSConverter(fo, &enc);
90 rc = utf8FromPyObject(fo, &enc);
93 fd = openPath(PyBytes_AsString(enc), rpmio_mode);
96 } else if (rpmfdObject_Check(fo)) {
97 rpmfdObject *fdo = (rpmfdObject *)fo;
98 fd = openFd(fdDup(Fileno(fdo->fd)), rpmio_mode);
99 } else if ((fdno = PyObject_AsFileDescriptor(fo)) >= 0) {
100 fd = openFd(fdDup(fdno), rpmio_mode);
102 PyErr_SetString(PyExc_TypeError, "path or file object expected");
106 Fclose(s->fd); /* in case __init__ was called again */
110 s->mode = rstrdup(mode);
111 s->flags = rstrdup(flags);
113 PyErr_SetString(PyExc_IOError, Fstrerror(fd));
117 return (fd == NULL) ? -1 : 0;
120 static PyObject *rpmfd_open(PyObject *cls, PyObject *args, PyObject *kwds)
122 return PyObject_Call(cls, args, kwds);
125 static PyObject *do_close(rpmfdObject *s)
127 /* mimic python fileobject: close on closed file is not an error */
129 Py_BEGIN_ALLOW_THREADS
137 static PyObject *rpmfd_close(rpmfdObject *s)
142 static void rpmfd_dealloc(rpmfdObject *s)
144 PyObject *res = do_close(s);
148 Py_TYPE(s)->tp_free((PyObject *)s);
151 static PyObject *rpmfd_fileno(rpmfdObject *s)
154 if (s->fd == NULL) return err_closed();
156 Py_BEGIN_ALLOW_THREADS
161 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
164 return Py_BuildValue("i", fno);
167 static PyObject *rpmfd_flush(rpmfdObject *s)
171 if (s->fd == NULL) return err_closed();
173 Py_BEGIN_ALLOW_THREADS
177 if (rc || Ferror(s->fd)) {
178 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
184 static PyObject *rpmfd_isatty(rpmfdObject *s)
187 if (s->fd == NULL) return err_closed();
189 Py_BEGIN_ALLOW_THREADS
190 fileno = Fileno(s->fd);
194 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
197 return PyBool_FromLong(isatty(fileno));
200 static PyObject *rpmfd_seek(rpmfdObject *s, PyObject *args, PyObject *kwds)
202 char *kwlist[] = { "offset", "whence", NULL };
204 int whence = SEEK_SET;
207 if (!PyArg_ParseTupleAndKeywords(args, kwds, "L|i", kwlist,
211 if (s->fd == NULL) return err_closed();
213 Py_BEGIN_ALLOW_THREADS
214 rc = Fseek(s->fd, offset, whence);
216 if (rc < 0 || Ferror(s->fd)) {
217 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
223 static PyObject *rpmfd_tell(rpmfdObject *s)
226 Py_BEGIN_ALLOW_THREADS
227 offset = Ftell(s->fd);
229 return Py_BuildValue("L", offset);
233 static PyObject *rpmfd_read(rpmfdObject *s, PyObject *args, PyObject *kwds)
235 char *kwlist[] = { "size", NULL };
237 ssize_t chunksize = sizeof(buf);
240 PyObject *res = NULL;
242 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|l", kwlist, &left))
245 if (s->fd == NULL) return err_closed();
247 /* ConcatAndDel() doesn't work on NULL string, meh */
248 res = PyBytes_FromStringAndSize(NULL, 0);
250 if (left >= 0 && left < chunksize)
253 Py_BEGIN_ALLOW_THREADS
254 nb = Fread(buf, 1, chunksize, s->fd);
258 PyObject *tmp = PyBytes_FromStringAndSize(buf, nb);
259 PyBytes_ConcatAndDel(&res, tmp);
265 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
273 static PyObject *rpmfd_write(rpmfdObject *s, PyObject *args, PyObject *kwds)
276 const char *buf = NULL;
278 char *kwlist[] = { "buffer", NULL };
281 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &buf, &size)) {
285 if (s->fd == NULL) return err_closed();
287 Py_BEGIN_ALLOW_THREADS
288 rc = Fwrite(buf, 1, size, s->fd);
292 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
295 return Py_BuildValue("n", rc);
298 static char rpmfd_doc[] = "";
300 static struct PyMethodDef rpmfd_methods[] = {
301 { "open", (PyCFunction) rpmfd_open, METH_VARARGS|METH_KEYWORDS|METH_CLASS,
303 { "close", (PyCFunction) rpmfd_close, METH_NOARGS,
305 { "fileno", (PyCFunction) rpmfd_fileno, METH_NOARGS,
307 { "flush", (PyCFunction) rpmfd_flush, METH_NOARGS,
309 { "isatty", (PyCFunction) rpmfd_isatty, METH_NOARGS,
311 { "read", (PyCFunction) rpmfd_read, METH_VARARGS|METH_KEYWORDS,
313 { "seek", (PyCFunction) rpmfd_seek, METH_VARARGS|METH_KEYWORDS,
315 { "tell", (PyCFunction) rpmfd_tell, METH_NOARGS,
317 { "write", (PyCFunction) rpmfd_write, METH_VARARGS|METH_KEYWORDS,
322 static PyObject *rpmfd_get_closed(rpmfdObject *s)
324 return PyBool_FromLong((s->fd == NULL));
327 static PyObject *rpmfd_get_name(rpmfdObject *s)
329 /* XXX: rpm returns non-paths with [mumble], python files use <mumble> */
330 return Py_BuildValue("s", Fdescr(s->fd));
333 static PyObject *rpmfd_get_mode(rpmfdObject *s)
335 return Py_BuildValue("s", s->mode);
338 static PyObject *rpmfd_get_flags(rpmfdObject *s)
340 return Py_BuildValue("s", s->flags);
343 static PyGetSetDef rpmfd_getseters[] = {
344 { "closed", (getter)rpmfd_get_closed, NULL, NULL },
345 { "name", (getter)rpmfd_get_name, NULL, NULL },
346 { "mode", (getter)rpmfd_get_mode, NULL, NULL },
347 { "flags", (getter)rpmfd_get_flags, NULL, NULL },
351 PyTypeObject rpmfd_Type = {
352 PyVarObject_HEAD_INIT(&PyType_Type, 0)
353 "rpm.fd", /* tp_name */
354 sizeof(rpmfdObject), /* tp_size */
357 (destructor) rpmfd_dealloc, /* tp_dealloc */
359 (getattrfunc)0, /* tp_getattr */
360 (setattrfunc)0, /* tp_setattr */
362 (reprfunc)0, /* tp_repr */
363 0, /* tp_as_number */
364 0, /* tp_as_sequence */
365 0, /* tp_as_mapping */
366 (hashfunc)0, /* tp_hash */
367 (ternaryfunc)0, /* tp_call */
368 (reprfunc)0, /* tp_str */
369 PyObject_GenericGetAttr, /* tp_getattro */
370 PyObject_GenericSetAttr, /* tp_setattro */
371 0, /* tp_as_buffer */
372 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
373 rpmfd_doc, /* tp_doc */
376 0, /* tp_richcompare */
377 0, /* tp_weaklistoffset */
380 rpmfd_methods, /* tp_methods */
382 rpmfd_getseters, /* tp_getset */
385 0, /* tp_descr_get */
386 0, /* tp_descr_set */
387 0, /* tp_dictoffset */
388 (initproc)rpmfd_init, /* tp_init */
389 (allocfunc)0, /* tp_alloc */
390 PyType_GenericNew, /* tp_new */
391 (freefunc)0, /* tp_free */