|
|
@@ -1,49 +1,19 @@ |
|
|
|
# Implementation of hole punching via fallocate, if the OS |
|
|
|
# and filesystem support it. |
|
|
|
|
|
|
|
try: |
|
|
|
import os |
|
|
|
import ctypes |
|
|
|
import ctypes.util |
|
|
|
|
|
|
|
def make_fallocate(): |
|
|
|
libc_name = ctypes.util.find_library('c') |
|
|
|
libc = ctypes.CDLL(libc_name, use_errno=True) |
|
|
|
|
|
|
|
_fallocate = libc.fallocate |
|
|
|
_fallocate.restype = ctypes.c_int |
|
|
|
_fallocate.argtypes = [ ctypes.c_int, ctypes.c_int, |
|
|
|
ctypes.c_int64, ctypes.c_int64 ] |
|
|
|
|
|
|
|
del libc |
|
|
|
del libc_name |
|
|
|
|
|
|
|
def fallocate(fd, mode, offset, len_): |
|
|
|
res = _fallocate(fd, mode, offset, len_) |
|
|
|
if res != 0: # pragma: no cover |
|
|
|
errno = ctypes.get_errno() |
|
|
|
raise IOError(errno, os.strerror(errno)) |
|
|
|
return fallocate |
|
|
|
|
|
|
|
fallocate = make_fallocate() |
|
|
|
del make_fallocate |
|
|
|
except Exception: # pragma: no cover |
|
|
|
fallocate = None |
|
|
|
|
|
|
|
FALLOC_FL_KEEP_SIZE = 0x01 |
|
|
|
FALLOC_FL_PUNCH_HOLE = 0x02 |
|
|
|
import fallocate |
|
|
|
|
|
|
|
def punch_hole(filename, offset, length, ignore_errors = True): |
|
|
|
"""Punch a hole in the file. This isn't well supported, so errors |
|
|
|
are ignored by default.""" |
|
|
|
try: |
|
|
|
if fallocate is None: # pragma: no cover |
|
|
|
raise IOError("fallocate not available") |
|
|
|
with open(filename, "r+") as f: |
|
|
|
fallocate(f.fileno(), |
|
|
|
FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, |
|
|
|
offset, length) |
|
|
|
except IOError: # pragma: no cover |
|
|
|
fallocate.fallocate( |
|
|
|
f.fileno(), |
|
|
|
offset, |
|
|
|
length, |
|
|
|
fallocate.FALLOC_FL_KEEP_SIZE | fallocate.FALLOC_FL_PUNCH_HOLE) |
|
|
|
except Exception: |
|
|
|
if ignore_errors: |
|
|
|
return |
|
|
|
raise |