Skip to content

Instantly share code, notes, and snippets.

@vontrapp
Forked from jimparis/punch.py
Last active December 22, 2015 22:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save vontrapp/6540376 to your computer and use it in GitHub Desktop.
Save vontrapp/6540376 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
import ctypes
import ctypes.util
import os
import re
null_re = re.compile('^\0*$')
c_off_t = ctypes.c_int64
def make_fallocate():
libc_name = ctypes.util.find_library('c')
libc = ctypes.CDLL(libc_name)
_fallocate = libc.fallocate
_fallocate.restype = ctypes.c_int
_fallocate.argtypes = [ctypes.c_int, ctypes.c_int, c_off_t, c_off_t]
del libc
del libc_name
def fallocate(fd, mode, offset, len_):
res = _fallocate(fd.fileno(), mode, offset, len_)
if res != 0:
raise IOError(res, 'fallocate')
return fallocate
fallocate = make_fallocate()
del make_fallocate
FALLOC_FL_KEEP_SIZE = 0x01
FALLOC_FL_PUNCH_HOLE = 0x02
def punch(filename, verbose, blocksize=None):
if verbose:
print "processing", filename
with open(filename, 'r+') as f:
if not blocksize:
blocksize = os.fstatvfs(f.fileno()).f_bsize
offset = 0
length = 0
while True:
buf = f.read(blocksize)
if not buf:
break
if null_re.match(buf):
if verbose:
print "punching hole at offset", offset, "length", len(buf)
fallocate(f, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
offset, len(buf))
offset = offset + blocksize
if __name__ == '__main__':
import sys
import argparse
parser = argparse.ArgumentParser(
description = "Punch out the empty areas in a file, making it sparse")
parser.add_argument('file', metavar='FILE',
help='file(s) to modify in-place', nargs='+')
parser.add_argument('-v', '--verbose', action="store_true", default=False,
help='be verbose')
parser.add_argument('-b', '--blocksize', metavar='BS', default=None,
help='override detected filesystem blocksize')
args = parser.parse_args()
for filename in args.file:
punch(filename, args.verbose, args.blocksize)
@petermaloney
Copy link

fixing a bug... setting -b results in an error

$ python punch.py.orig -b 4096 "$d"
Traceback (most recent call last):
  File "punch.py.orig", line 69, in <module>
    punch(filename, args.verbose, args.blocksize)
  File "punch.py.orig", line 46, in punch
    buf = f.read(blocksize)
TypeError: an integer is required
--- punch.py.orig       2014-07-18 10:01:01.189842667 +0200
+++ punch.py    2014-07-17 17:39:53.012197857 +0200
@@ -40,6 +40,8 @@
     with open(filename, 'r+') as f:
         if not blocksize:
             blocksize = os.fstatvfs(f.fileno()).f_bsize
+        else:
+            blocksize = int(blocksize)
         offset = 0
         length = 0
         while True:
@@ -67,4 +69,4 @@
     args = parser.parse_args()
     for filename in args.file:
         punch(filename, args.verbose, args.blocksize)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment