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 <mprivozn(a)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 <mprivozn(a)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