summaryrefslogtreecommitdiff
path: root/morphlib/util.py
diff options
context:
space:
mode:
authorDaniel Silverstone <daniel.silverstone@codethink.co.uk>2012-10-09 10:15:04 +0000
committerDaniel Silverstone <daniel.silverstone@codethink.co.uk>2012-10-09 10:15:04 +0000
commit044af57e054496361f297277c2170194759f1dc6 (patch)
treef77ec4e29b4f1408d04a410c243c523dc2b60e22 /morphlib/util.py
parent05834974c55caae117f16b33c5fc164f323462c4 (diff)
downloadmorph-044af57e054496361f297277c2170194759f1dc6.tar.gz
Add a sparse-aware (for writing) copyfileobj.
Diffstat (limited to 'morphlib/util.py')
-rw-r--r--morphlib/util.py39
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")