From 3d4c3e860c225e0e9ead6c2ff0ac183560b4205b Mon Sep 17 00:00:00 2001 From: "Doncho N. Gunchev" Date: Sat, 3 Dec 2011 02:38:52 +0200 Subject: [PATCH] Add mksparse.py (create sparse files) --- misc/mksparse.py | 105 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100755 misc/mksparse.py diff --git a/misc/mksparse.py b/misc/mksparse.py new file mode 100755 index 0000000..d1e4a87 --- /dev/null +++ b/misc/mksparse.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""\ +============================================== +mksparse.py - sparse file / disk image creator +============================================== + +Usage: mksparse.py [k|m|g] + This will create with size . If the suffix is +not given then the size is in bytes, 'k' stands for kilobytes (1024), +'m' for megabytes and 'g' for gigabyes (K/M/G are not implemented, one +can type 000 easy enough). + +Simple python script that creates sparse files on unix / Win2k NTFS5. +This script opens a file for writing, seeks at the desired position +(or file size) and truncates the file there. Can be handy while +playing with qemu / bochs / loopback images. + +Tested on linux-2.6 only. + +Author: Doncho N. Gunchev +Based on Brad Watson's work mkimage.py from + http://lists.gnu.org/archive/html/qemu-devel/2004-07/msg00733.html + http://qemu.dad-answers.com/download/qemu/utilities/QEMU-HD-Create/ +""" + +__version__ = "0.1" +__author__ = "Doncho Gunchev , Brad Watson" +__depends__ = ['Python-2.4'] +#__copyright__ = """Have to ask Brad Watson, GPL?""" + + + +def mk_sparse(file_name, file_size): + """ Create a sparse file by truncating it at given position""" + try: + f = open(sys.argv[1],"wb+") + except Exception, e: + raise Exception("Error: Can't create file '" + file_name + "':\n" + str(e)) + else: + try: + # Note that I don't wan (you too) to write() anything in the file + # because this will consume at least one sector/block. + f.truncate(int(file_size)) + except Exception, e: + f.close() # clean the mess... TODO: more checks if this does not fail? + os.unlink(sys.argv[1]) + raise Exception("Error: Can't truncate '%s'\n%s" % (file_name, str(e))) + try: # Hmm, do I need this at all? Maybe yes (judging from the strange errors + # that occure in gzip at object destruction) + f.close() + except Exception, e: + raise Exception("Error: Can't close '%s'\n%s" % (file_name, str(e))) + + + +if __name__ == "__main__": + import os.path + import re + import sys + + if len(sys.argv) != 3: + # .pyo (docstrings stripped) workaround + print >> sys.stderr, __doc__ and __doc__ or "Usage: mksparse.py [kmg]" + print >> sys.stderr, "Version:", __version__ + sys.exit(1) + + # 'Process' command line parameters + file_name = sys.argv[1] + file_size = sys.argv[2] + # validate file size + try: + (size, dim) = re.match('^(\d+)([KkMmGg])?$', file_size).groups() + except Exception, e: + print >> sys.stderr, (sys.argv[0] + ': ' + + "Bad image size given: " + repr(file_size)) + sys.exit(2) + + # Check if the file exists, -f (force) would be a good parameter + if os.path.exists(file_name): + print >> sys.stderr, (sys.argv[0] + ': ' + + ("Error: file (directory) '%s' already exists!" % (file_name))) + sys.exit(3) + + dim = dim.lower() + # Calculate size in bytes + size = long(size) + if dim == 'k': + size *= 1024 + elif dim == 'm': + size *= 1024 * 1024 + elif dim == 'g': + size *= 1024 * 1024 * 1024 + elif dim != None: + print >> sys.stderr, (sys.argv[0] + ': ' + + "Internal error: size modifier " + repr(dim) + " not handled.") + sys.exit(4) + + file_size = size + try: + mk_sparse(file_name, file_size) + except Exception, e: + print >> sys.stderr, sys.argv[0] + ': ' + str(e) + sys.exit(1)