diff options
author | toonn <toonn@toonn.io> | 2023-06-14 18:55:24 +0200 |
---|---|---|
committer | toonn <toonn@toonn.io> | 2023-06-16 13:34:34 +0200 |
commit | 4a5c9fd1f2cac3a40bb75b9e7140025f359c42fe (patch) | |
tree | 555d78bd7f15e1b5bc0c085481be4b0921408250 | |
parent | 1a6379f0613c6291a559d8c1ffee51628bc3d04b (diff) |
ext/shutil_generatorized: copy_file_range only on recent Linux
The method is not defined on platforms that don't have the
`copy_file_range` syscall, e.g., Linux before 5.3 or macOS.
-rw-r--r-- | ranger/ext/shutil_generatorized.py | 34 |
1 files changed, 18 insertions, 16 deletions
diff --git a/ranger/ext/shutil_generatorized.py b/ranger/ext/shutil_generatorized.py index 7d7675fd..a5a6a0d4 100644 --- a/ranger/ext/shutil_generatorized.py +++ b/ranger/ext/shutil_generatorized.py @@ -9,7 +9,7 @@ import sys from shutil import (_samefile, rmtree, _basename, _destinsrc, Error, SpecialFileError) from ranger.ext.safe_path import get_safe_path -__all__ = ["copyfileobj", "copyfileobjnew", "copyfile", "copystat", "copy2", "BLOCK_SIZE", +__all__ = ["copyfileobj", "copyfileobj_range", "copyfile", "copystat", "copy2", "BLOCK_SIZE", "copytree", "move", "rmtree", "Error", "SpecialFileError"] BLOCK_SIZE = 16 * 1024 @@ -111,12 +111,18 @@ def copyfileobj(fsrc, fdst, length=BLOCK_SIZE): yield done -def copyfileobjnew(fsrc, fdst, length=BLOCK_SIZE): - """copy data from fsrc to fdst with new copy method to enable copy-on-write""" +def copyfileobj_range(fsrc, fdst, length=BLOCK_SIZE): + """copy data from fsrc to fdst with copy_file_range to enable CoW""" + try: + copy = os.copy_file_range + except AttributeError: + raise CopyFileRangeUnsupported + src_fd = fsrc.fileno() + dst_fd = fdst.fileno() done = 0 while 1: # copy_file_range returns number of bytes read, or -1 if there was an error - read = os.copy_file_range(fsrc.fileno(), fdst.fileno(), length) + read = copy(src_fd, dst_fd, length) if read == 0: break done += read @@ -141,19 +147,15 @@ def copyfile(src, dst, enable_copy_on_write=False): with open(src, 'rb') as fsrc: with open(dst, 'wb') as fdst: - if enable_copy_on_write: - try: - for done in copyfileobjnew(fsrc, fdst): - yield done - except OSError: - # Return to start of files first, then use old method - fsrc.seek(0, 0) - fdst.seek(0, 0) - for done in copyfileobj(fsrc, fdst): - yield done - else: - for done in copyfileobj(fsrc, fdst): + try: + for done in copyfileobj_range(fsrc, fdst): yield done + except (CopyFileRangeUnsupported, OSError): + # Return to start of files first, then use old method + fsrc.seek(0, 0) + fdst.seek(0, 0) + for done in copyfileobj(fsrc, fdst): + yield done def copy2(src, dst, overwrite=False, symlinks=False, make_safe_path=get_safe_path, |