This patch is similar to what I sent for libvirt. It extends
callbacks so that they work with block devices.

Signed-off-by: Michal Privoznik <mpriv...@redhat.com>
---
 examples/sparsestream.py | 73 +++++++++++++++++++++++++++++-----------
 1 file changed, 54 insertions(+), 19 deletions(-)

diff --git a/examples/sparsestream.py b/examples/sparsestream.py
index d7c09b7..4e96d43 100755
--- a/examples/sparsestream.py
+++ b/examples/sparsestream.py
@@ -4,27 +4,27 @@
 # Authors:
 #   Michal Privoznik <mpriv...@redhat.com>
 
-import libvirt, sys, os
+import libvirt, stat, sys, os
 
-def bytesWriteHandler(stream, buf, opaque):
-    fd = opaque
-    return os.write(fd, buf)
+def bytesWriteHandler(stream, buf, cbData):
+    return os.write(cbData["fd"], buf)
 
-def bytesReadHandler(stream, nbytes, opaque):
-    fd = opaque
-    return os.read(fd, nbytes)
+def bytesReadHandler(stream, nbytes, cbData):
+    return os.read(cbData["fd"], nbytes)
 
-def recvSkipHandler(stream, length, opaque):
-    fd = opaque
-    cur = os.lseek(fd, length, os.SEEK_CUR)
-    return os.ftruncate(fd, cur)
+def recvSkipHandler(stream, length, cbData):
+    fd = cbData["fd"]
+    if cbData["isBlock"]:
+        os.write(fd, b'\x00' * length)
+    else :
+        cur = os.lseek(fd, length, os.SEEK_CUR)
+        os.ftruncate(fd, cur)
+    return 0
 
-def sendSkipHandler(stream, length, opaque):
-    fd = opaque
-    return os.lseek(fd, length, os.SEEK_CUR)
+def sendSkipHandler(stream, length, cbData):
+    return os.lseek(cbData["fd"], length, os.SEEK_CUR)
 
-def holeHandler(stream, opaque):
-    fd = opaque
+def inDataRegular(fd):
     cur = os.lseek(fd, 0, os.SEEK_CUR)
 
     try:
@@ -73,13 +73,45 @@ def holeHandler(stream, opaque):
     os.lseek(fd, cur, os.SEEK_SET)
     return [inData, sectionLen]
 
+def inDataDetectZeores(fd):
+    cur = os.lseek(fd, 0, os.SEEK_CUR)
+    chunksize = 32 * 1024 * 1024 # 2MiB
+
+    buf = os.read(fd, chunksize)
+
+    zeroes = bytes(len(buf))
+    inData = buf != zeroes
+    sectionLen = len(buf)
+    print("cur: %d inData: %s sectionLen: %d" % (cur, inData, sectionLen))
+
+    os.lseek(fd, cur, os.SEEK_SET)
+    return [inData, sectionLen]
+
+
+def holeHandler(stream, cbData):
+    if cbData["isBlock"]:
+        return inDataDetectZeores(cbData["fd"])
+    else:
+        return inDataRegular(cbData["fd"])
+
 def download(vol, st, filename):
     offset = 0
     length = 0
+    isBlock = False
 
-    fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, mode=0o0660)
+    try:
+        sb = os.stat(filename)
+        isBlock = stat.S_ISBLK(sb.st_mode)
+    except FileNotFoundError:
+        pass
+
+    if isBlock:
+        fd = os.open(filename, os.O_WRONLY, mode=0o0660)
+    else:
+        fd = os.open(filename, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 
mode=0o0660)
+    cbData = {"fd": fd, "isBlock": isBlock}
     vol.download(st, offset, length, 
libvirt.VIR_STORAGE_VOL_DOWNLOAD_SPARSE_STREAM)
-    st.sparseRecvAll(bytesWriteHandler, recvSkipHandler, fd)
+    st.sparseRecvAll(bytesWriteHandler, recvSkipHandler, cbData)
 
     os.close(fd)
 
@@ -87,9 +119,12 @@ def upload(vol, st, filename):
     offset = 0
     length = 0
 
+    sb = os.stat(filename)
+    isBlock = stat.S_ISBLK(sb.st_mode)
     fd = os.open(filename, os.O_RDONLY)
+    cbData = {"fd": fd, "isBlock": isBlock}
     vol.upload(st, offset, length, 
libvirt.VIR_STORAGE_VOL_UPLOAD_SPARSE_STREAM)
-    st.sparseSendAll(bytesReadHandler, holeHandler, sendSkipHandler, fd)
+    st.sparseSendAll(bytesReadHandler, holeHandler, sendSkipHandler, cbData)
 
     os.close(fd)
 
-- 
2.26.2

Reply via email to