Skip to content

Commit

Permalink
handling more errno for cow fast copy
Browse files Browse the repository at this point in the history
hopefully this can cover all cases that are fallback-able
reference: cp impl in coreutils
resolved #7
  • Loading branch information
Fallen-Breath committed Dec 19, 2023
1 parent 5f3e31c commit b911eae
Showing 1 changed file with 18 additions and 5 deletions.
23 changes: 18 additions & 5 deletions prime_backup/utils/file_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,30 @@
HAS_COPY_FILE_RANGE = callable(getattr(os, 'copy_file_range', None))


def __is_cow_not_supported_error(e: int) -> bool:
# https://github.com/coreutils/coreutils/blob/c343bee1b5de6087b70fe80db9e1f81bb1fc535c/src/copy.c#L292
return e in (
errno.ENOSYS, errno.ENOTTY, errno.EOPNOTSUPP, errno.ENOTSUP,
errno.EINVAL, errno.EBADF,
errno.EXDEV, errno.ETXTBSY,
errno.EPERM, errno.EACCES,
)


def copy_file_fast(src_path: Path, dst_path: Path):
# https://man7.org/linux/man-pages/man2/copy_file_range.2.html
if HAS_COPY_FILE_RANGE:
total_read = 0
try:
with open(src_path, 'rb') as f_src, open(dst_path, 'wb+') as f_dst:
while os.copy_file_range(f_src.fileno(), f_dst.fileno(), 2 ** 30):
pass
while n := os.copy_file_range(f_src.fileno(), f_dst.fileno(), 2 ** 30):
total_read += n
return
except OSError as e:
# https://man7.org/linux/man-pages/man2/copy_file_range.2.html
if e.errno in [errno.EXDEV, errno.EOPNOTSUPP]:
pass # retry with shutil.copyfile
# unsupported or read nothing -> retry with shutil.copyfile
# reference: https://github.com/coreutils/coreutils/blob/c343bee1b5de6087b70fe80db9e1f81bb1fc535c/src/copy.c#L312
if __is_cow_not_supported_error(e.errno) and total_read == 0:
pass
else:
raise

Expand Down

0 comments on commit b911eae

Please sign in to comment.