[Libguestfs] [PATCH nbdkit] python: Allow extents to return any iterable (which includes lists).

Richard W.M. Jones rjones at redhat.com
Mon Aug 10 17:38:16 UTC 2020


Thanks: Nir Soffer.
Enhances: commit c12e3cb150259f0058727a50341a2d14bb0015a3
---
 plugins/python/nbdkit-python-plugin.pod |  3 +-
 plugins/python/python.c                 | 39 +++++++++++++++----------
 2 files changed, 25 insertions(+), 17 deletions(-)

diff --git a/plugins/python/nbdkit-python-plugin.pod b/plugins/python/nbdkit-python-plugin.pod
index d7b6033f..ddae677e 100644
--- a/plugins/python/nbdkit-python-plugin.pod
+++ b/plugins/python/nbdkit-python-plugin.pod
@@ -377,7 +377,8 @@ optionally using C<nbdkit.set_error> first.
 (Optional)
 
  def extents(h, count, offset, flags):
-   # return a list of (offset, length, type) tuples:
+   # return an iterable object (eg. list) of
+   # (offset, length, type) tuples:
    return [ (off1, len1, type1), (off2, len2, type2), ... ]
 
 =back
diff --git a/plugins/python/python.c b/plugins/python/python.c
index 46b912e2..27c5ede2 100644
--- a/plugins/python/python.c
+++ b/plugins/python/python.c
@@ -1035,7 +1035,8 @@ py_extents (void *handle, uint32_t count, uint64_t offset,
   struct handle *h = handle;
   PyObject *fn;
   PyObject *r;
-  Py_ssize_t i, size;
+  PyObject *iter, *t;
+  size_t size;
 
   if (callback_defined ("extents", &fn)) {
     PyErr_Clear ();
@@ -1045,29 +1046,25 @@ py_extents (void *handle, uint32_t count, uint64_t offset,
     if (check_python_failure ("extents") == -1)
       return -1;
 
-    /* We expect a list of extents to be returned.  Each extent is a
-     * tuple (offset, length, type).  The list must not be empty.
-     */
-    if (!PyList_Check (r)) {
-      nbdkit_error ("extents method did not return a list");
-      Py_DECREF (r);
-      return -1;
-    }
-    size = PyList_Size (r);
-    if (size < 1) {
-      nbdkit_error ("extents method cannot return an empty list");
+    iter = PyObject_GetIter (r);
+    if (iter == NULL) {
+      nbdkit_error ("extents method did not return "
+                    "something which is iterable");
       Py_DECREF (r);
       return -1;
     }
 
-    for (i = 0; i < size; ++i) {
-      PyObject *t, *py_offset, *py_length, *py_type;
+    size = 0;
+    while ((t = PyIter_Next (iter)) != NULL) {
+      PyObject *py_offset, *py_length, *py_type;
       uint64_t extent_offset, extent_length;
       uint32_t extent_type;
 
-      t = PyList_GetItem (r, i);
+      size++;
+
       if (!PyTuple_Check (t) || PyTuple_Size (t) != 3) {
-        nbdkit_error ("extents method did not return a list of 3-tuples");
+        nbdkit_error ("extents method did not return an iterable of 3-tuples");
+        Py_DECREF (iter);
         Py_DECREF (r);
         return -1;
       }
@@ -1078,16 +1075,26 @@ py_extents (void *handle, uint32_t count, uint64_t offset,
       extent_length = PyLong_AsUnsignedLongLong (py_length);
       extent_type = PyLong_AsUnsignedLong (py_type);
       if (check_python_failure ("PyLong") == -1) {
+        Py_DECREF (iter);
         Py_DECREF (r);
         return -1;
       }
       if (nbdkit_add_extent (extents,
                              extent_offset, extent_length, extent_type) == -1) {
+        Py_DECREF (iter);
         Py_DECREF (r);
         return -1;
       }
     }
 
+    if (size < 1) {
+      nbdkit_error ("extents method cannot return an empty list");
+      Py_DECREF (iter);
+      Py_DECREF (r);
+      return -1;
+    }
+
+    Py_DECREF (iter);
     Py_DECREF (r);
   }
   else {
-- 
2.27.0




More information about the Libguestfs mailing list