git » libjio » commit 9607741

bindings/python: Add readv()/writev() support

author Alberto Bertogli
2009-07-13 05:43:46 UTC
committer Alberto Bertogli
2009-07-13 05:43:46 UTC
parent 3d0488b17d699e3d83e440e9f0801418350139ce

bindings/python: Add readv()/writev() support

Signed-off-by: Alberto Bertogli <albertito@blitiri.com.ar>

bindings/python/libjio.c +157 -0

diff --git a/bindings/python/libjio.c b/bindings/python/libjio.c
index 10c5eba..b5c5267 100644
--- a/bindings/python/libjio.c
+++ b/bindings/python/libjio.c
@@ -4,6 +4,7 @@
  * Alberto Bertogli (albertito@blitiri.com.ar)
  */
 
+#define PY_SSIZE_T_CLEAN 1
 
 #include <Python.h>
 
@@ -162,6 +163,106 @@ static PyObject *jf_pread(jfile_object *fp, PyObject *args)
 	return r;
 }
 
+/* readv */
+PyDoc_STRVAR(jf_readv__doc,
+"readv([buf1, buf2, ...])\n\
+\n\
+Reads the data from the file into the different buffers; returns the\n\
+number of bytes written.\n\
+The buffers must be objects that support slice assignment, like bytearray\n\
+(but *not* str).\n\
+Only available in Python >= 2.6.\n\
+It's a wrapper to jreadv().\n");
+
+/* readv requires the new Py_buffer interface, which is only available in
+ * Python >= 2.6 */
+#if PY_MAJOR_VERSION >= 3 || (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 6)
+static PyObject *jf_readv(jfile_object *fp, PyObject *args)
+{
+	long rv;
+	PyObject *buffers, *buf;
+	Py_buffer *views = NULL;
+	ssize_t len, pos = 0;
+	struct iovec *iov = NULL;
+
+	if (!PyArg_ParseTuple(args, "O:readv", &buffers))
+		return NULL;
+
+	len = PySequence_Length(buffers);
+	if (len < 0) {
+		PyErr_SetString(PyExc_TypeError, "iterable expected");
+		return NULL;
+	}
+
+	iov = malloc(sizeof(struct iovec) * len);
+	if (iov == NULL)
+		return PyErr_NoMemory();
+
+	views = malloc(sizeof(Py_buffer) * len);
+	if (views == NULL) {
+		free(iov);
+		return PyErr_NoMemory();
+	}
+
+	for (pos = 0; pos < len; pos++) {
+		buf = PySequence_GetItem(buffers, pos);
+		if (buf == NULL)
+			goto error;
+
+		if (!PyObject_CheckBuffer(buf)) {
+			PyErr_SetString(PyExc_TypeError,
+				"object must support the buffer interface");
+			goto error;
+		}
+
+		if (PyObject_GetBuffer(buf, &(views[pos]), PyBUF_CONTIG))
+			goto error;
+
+		iov[pos].iov_base = views[pos].buf;
+		iov[pos].iov_len = views[pos].len;
+	}
+
+	Py_BEGIN_ALLOW_THREADS
+	rv = jreadv(fp->fs, iov, len);
+	Py_END_ALLOW_THREADS
+
+	for (pos = 0; pos < len; pos++) {
+		PyBuffer_Release(&(views[pos]));
+	}
+
+	free(iov);
+	free(views);
+
+	if (rv < 0)
+		return PyErr_SetFromErrno(PyExc_IOError);
+
+	return PyLong_FromLong(rv);
+
+error:
+	/* We might get here with pos between 0 and len, so we must release
+	 * only what we have already taken */
+	pos--;
+	while (pos >= 0) {
+		PyBuffer_Release(&(views[pos]));
+		pos--;
+	}
+
+	free(iov);
+	free(views);
+	return NULL;
+}
+
+#else
+
+static PyObject *jf_readv(jfile_object *fp, PyObject *args)
+{
+	PyErr_SetString(PyExc_NotImplementedError,
+			"only supported in Python >= 2.6");
+	return NULL;
+}
+
+#endif /* python version >= 2.6 */
+
 /* write */
 PyDoc_STRVAR(jf_write__doc,
 "write(buf)\n\
@@ -217,6 +318,60 @@ static PyObject *jf_pwrite(jfile_object *fp, PyObject *args)
 	return PyLong_FromLong(rv);
 }
 
+/* writev */
+PyDoc_STRVAR(jf_writev__doc,
+"writev([buf1, buf2, ...])\n\
+\n\
+Writes the data contained in the different buffers to the file, returns the\n\
+number of bytes written.\n\
+The buffers must be strings or string-alike objects, like str or bytes.\n\
+It's a wrapper to jwritev().\n");
+
+static PyObject *jf_writev(jfile_object *fp, PyObject *args)
+{
+	long rv;
+	PyObject *buffers, *buf;
+	ssize_t len, pos;
+	struct iovec *iov;
+
+	if (!PyArg_ParseTuple(args, "O:writev", &buffers))
+		return NULL;
+
+	len = PySequence_Length(buffers);
+	if (len < 0) {
+		PyErr_SetString(PyExc_TypeError, "iterable expected");
+		return NULL;
+	}
+
+	iov = malloc(sizeof(struct iovec) * len);
+	if (iov == NULL)
+		return PyErr_NoMemory();
+
+	for (pos = 0; pos < len; pos++) {
+		buf = PySequence_GetItem(buffers, pos);
+		if (buf == NULL)
+			return NULL;
+
+		iov[pos].iov_len = 0;
+		if (!PyArg_Parse(buf, "s#:writev", &(iov[pos].iov_base),
+				&(iov[pos].iov_len))) {
+			free(iov);
+			return NULL;
+		}
+	}
+
+	Py_BEGIN_ALLOW_THREADS
+	rv = jwritev(fp->fs, iov, len);
+	Py_END_ALLOW_THREADS
+
+	free(iov);
+
+	if (rv < 0)
+		return PyErr_SetFromErrno(PyExc_IOError);
+
+	return PyLong_FromLong(rv);
+}
+
 /* truncate */
 PyDoc_STRVAR(jf_truncate__doc,
 "truncate(lenght)\n\
@@ -415,8 +570,10 @@ static PyMethodDef jfile_methods[] = {
 	{ "fileno", (PyCFunction) jf_fileno, METH_VARARGS, jf_fileno__doc },
 	{ "read", (PyCFunction) jf_read, METH_VARARGS, jf_read__doc },
 	{ "pread", (PyCFunction) jf_pread, METH_VARARGS, jf_pread__doc },
+	{ "readv", (PyCFunction) jf_readv, METH_VARARGS, jf_readv__doc },
 	{ "write", (PyCFunction) jf_write, METH_VARARGS, jf_write__doc },
 	{ "pwrite", (PyCFunction) jf_pwrite, METH_VARARGS, jf_pwrite__doc },
+	{ "writev", (PyCFunction) jf_writev, METH_VARARGS, jf_writev__doc },
 	{ "truncate", (PyCFunction) jf_truncate, METH_VARARGS,
 		jf_truncate__doc },
 	{ "lseek", (PyCFunction) jf_lseek, METH_VARARGS, jf_lseek__doc },