diff options
author | Daniel Silverstone <daniel.silverstone@codethink.co.uk> | 2012-10-09 10:15:04 +0000 |
---|---|---|
committer | Daniel Silverstone <daniel.silverstone@codethink.co.uk> | 2012-10-09 10:15:04 +0000 |
commit | 044af57e054496361f297277c2170194759f1dc6 (patch) | |
tree | f77ec4e29b4f1408d04a410c243c523dc2b60e22 | |
parent | 05834974c55caae117f16b33c5fc164f323462c4 (diff) | |
download | morph-044af57e054496361f297277c2170194759f1dc6.tar.gz |
Add a sparse-aware (for writing) copyfileobj.
-rw-r--r-- | morphlib/util.py | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/morphlib/util.py b/morphlib/util.py index af7c59ba..100f4b6b 100644 --- a/morphlib/util.py +++ b/morphlib/util.py @@ -161,3 +161,42 @@ def new_repo_caches(app): # pragma: no cover rrc = None return lrc, rrc + + +# This acquired from rdiff-backup which is GPLv2+ and a patch from 2011 +# which has not yet been merged, combined with a tad of tidying from us. +def copyfileobj(inputfp, outputfp, blocksize=1024*1024): # pragma: no cover + """Copies file inputfp to outputfp in blocksize intervals""" + + sparse = False + buf = None + while 1: + inbuf = inputfp.read(blocksize) + if not inbuf: break + if not buf: + buf = inbuf + else: + buf += inbuf + + # Combine "short" reads + if (len(buf) < blocksize): + continue + + buflen = len(buf) + if buf == "\x00" * buflen: + outputfp.seek(buflen, os.SEEK_CUR) + buf = None + # flag sparse=True, that we seek()ed, but have not written yet + # The filesize is wrong until we write + sparse = True + else: + outputfp.write(buf) + buf = None + # We wrote, so clear sparse. + sparse = False + + if buf: + outputfp.write(buf) + elif sparse: + outputfp.seek(-1, os.SEEK_CUR) + outputfp.write("\x00") |