2 #include "rpmsystem-py.h"
3 #include <rpm/rpmstring.h>
4 #include "header-py.h" /* XXX for utf8FromPyObject() only */
13 FD_t rpmfdGetFd(rpmfdObject *fdo)
18 int rpmfdFromPyObject(PyObject *obj, rpmfdObject **fdop)
20 rpmfdObject *fdo = NULL;
22 if (rpmfdObject_Check(obj)) {
24 fdo = (rpmfdObject *) obj;
26 fdo = (rpmfdObject *) PyObject_CallFunctionObjArgs((PyObject *)&rpmfd_Type,
29 if (fdo == NULL) return 0;
31 if (Ferror(fdo->fd)) {
32 PyErr_SetString(PyExc_IOError, Fstrerror(fdo->fd));
40 static PyObject *err_closed(void)
42 PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
46 static FD_t openPath(const char *path, const char *mode, const char *flags)
49 char *m = rstrscat(NULL, mode, ".", flags, NULL);
50 Py_BEGIN_ALLOW_THREADS
57 static int rpmfd_init(rpmfdObject *s, PyObject *args, PyObject *kwds)
59 char *kwlist[] = { "obj", "mode", "flags", NULL };
60 const char *mode = "r";
61 const char *flags = "ufdio";
66 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ss", kwlist,
70 if (PyBytes_Check(fo)) {
71 fd = openPath(PyBytes_AsString(fo), mode, flags);
72 } else if (PyUnicode_Check(fo)) {
75 #if PY_MAJOR_VERSION >= 3
76 rc = PyUnicode_FSConverter(fo, &enc);
78 rc = utf8FromPyObject(fo, &enc);
81 fd = openPath(PyBytes_AsString(enc), mode, flags);
84 } else if ((fdno = PyObject_AsFileDescriptor(fo)) >= 0) {
87 PyErr_SetString(PyExc_TypeError, "path or file object expected");
91 /* TODO: remember our filename, mode & flags */
92 Fclose(s->fd); /* in case __init__ was called again */
95 PyErr_SetString(PyExc_IOError, Fstrerror(fd));
98 return (fd == NULL) ? -1 : 0;
101 static PyObject *do_close(rpmfdObject *s)
103 /* mimic python fileobject: close on closed file is not an error */
105 Py_BEGIN_ALLOW_THREADS
113 static PyObject *rpmfd_close(rpmfdObject *s)
118 static void rpmfd_dealloc(rpmfdObject *s)
120 PyObject *res = do_close(s);
122 Py_TYPE(s)->tp_free((PyObject *)s);
125 static PyObject *rpmfd_fileno(rpmfdObject *s)
128 if (s->fd == NULL) return err_closed();
130 Py_BEGIN_ALLOW_THREADS
135 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
138 return Py_BuildValue("i", fno);
141 static PyObject *rpmfd_flush(rpmfdObject *s)
145 if (s->fd == NULL) return err_closed();
147 Py_BEGIN_ALLOW_THREADS
151 if (rc || Ferror(s->fd)) {
152 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
158 static PyObject *rpmfd_isatty(rpmfdObject *s)
161 if (s->fd == NULL) return err_closed();
163 Py_BEGIN_ALLOW_THREADS
164 fileno = Fileno(s->fd);
168 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
171 return PyBool_FromLong(isatty(fileno));
174 static PyObject *rpmfd_seek(rpmfdObject *s, PyObject *args, PyObject *kwds)
176 char *kwlist[] = { "offset", "whence", NULL };
178 int whence = SEEK_SET;
181 if (!PyArg_ParseTupleAndKeywords(args, kwds, "L|i", kwlist,
185 if (s->fd == NULL) return err_closed();
187 Py_BEGIN_ALLOW_THREADS
188 rc = Fseek(s->fd, offset, whence);
190 if (rc < 0 || Ferror(s->fd)) {
191 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
197 static PyObject *rpmfd_tell(rpmfdObject *s)
200 Py_BEGIN_ALLOW_THREADS
201 offset = Ftell(s->fd);
203 return Py_BuildValue("L", offset);
207 static PyObject *rpmfd_read(rpmfdObject *s, PyObject *args, PyObject *kwds)
209 char *kwlist[] = { "size", NULL };
211 ssize_t chunksize = sizeof(buf);
214 PyObject *res = NULL;
216 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|l", kwlist, &left))
219 if (s->fd == NULL) return err_closed();
221 /* ConcatAndDel() doesn't work on NULL string, meh */
222 res = PyBytes_FromStringAndSize(NULL, 0);
224 if (left >= 0 && left < chunksize)
227 Py_BEGIN_ALLOW_THREADS
228 nb = Fread(buf, 1, chunksize, s->fd);
232 PyObject *tmp = PyBytes_FromStringAndSize(buf, nb);
233 PyString_ConcatAndDel(&res, tmp);
239 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
247 static PyObject *rpmfd_write(rpmfdObject *s, PyObject *args, PyObject *kwds)
250 const char *buf = NULL;
252 char *kwlist[] = { "buffer", NULL };
255 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist, &buf, &size)) {
259 if (s->fd == NULL) return err_closed();
261 Py_BEGIN_ALLOW_THREADS
262 rc = Fwrite(buf, 1, size, s->fd);
266 PyErr_SetString(PyExc_IOError, Fstrerror(s->fd));
269 return Py_BuildValue("n", rc);
272 static char rpmfd_doc[] = "";
274 static struct PyMethodDef rpmfd_methods[] = {
275 { "close", (PyCFunction) rpmfd_close, METH_NOARGS,
277 { "fileno", (PyCFunction) rpmfd_fileno, METH_NOARGS,
279 { "flush", (PyCFunction) rpmfd_flush, METH_NOARGS,
281 { "isatty", (PyCFunction) rpmfd_isatty, METH_NOARGS,
283 { "read", (PyCFunction) rpmfd_read, METH_VARARGS|METH_KEYWORDS,
285 { "seek", (PyCFunction) rpmfd_seek, METH_VARARGS|METH_KEYWORDS,
287 { "tell", (PyCFunction) rpmfd_tell, METH_NOARGS,
289 { "write", (PyCFunction) rpmfd_write, METH_VARARGS|METH_KEYWORDS,
294 static PyObject *rpmfd_get_closed(rpmfdObject *s)
296 return PyBool_FromLong((s->fd == NULL));
299 static PyObject *rpmfd_get_name(rpmfdObject *s)
301 /* XXX: rpm returns non-paths with [mumble], python files use <mumble> */
302 return Py_BuildValue("s", Fdescr(s->fd));
305 static PyGetSetDef rpmfd_getseters[] = {
306 { "closed", (getter)rpmfd_get_closed, NULL, NULL },
307 { "name", (getter)rpmfd_get_name, NULL, NULL },
311 PyTypeObject rpmfd_Type = {
312 PyVarObject_HEAD_INIT(&PyType_Type, 0)
313 "rpm.fd", /* tp_name */
314 sizeof(rpmfdObject), /* tp_size */
317 (destructor) rpmfd_dealloc, /* tp_dealloc */
319 (getattrfunc)0, /* tp_getattr */
320 (setattrfunc)0, /* tp_setattr */
322 (reprfunc)0, /* tp_repr */
323 0, /* tp_as_number */
324 0, /* tp_as_sequence */
325 0, /* tp_as_mapping */
326 (hashfunc)0, /* tp_hash */
327 (ternaryfunc)0, /* tp_call */
328 (reprfunc)0, /* tp_str */
329 PyObject_GenericGetAttr, /* tp_getattro */
330 PyObject_GenericSetAttr, /* tp_setattro */
331 0, /* tp_as_buffer */
332 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
333 rpmfd_doc, /* tp_doc */
336 0, /* tp_richcompare */
337 0, /* tp_weaklistoffset */
340 rpmfd_methods, /* tp_methods */
342 rpmfd_getseters, /* tp_getset */
345 0, /* tp_descr_get */
346 0, /* tp_descr_set */
347 0, /* tp_dictoffset */
348 (initproc)rpmfd_init, /* tp_init */
349 (allocfunc)0, /* tp_alloc */
350 PyType_GenericNew, /* tp_new */
351 (freefunc)0, /* tp_free */