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