summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortoonn <toonn@toonn.io>2023-06-14 18:55:24 +0200
committertoonn <toonn@toonn.io>2023-06-16 13:34:34 +0200
commit4a5c9fd1f2cac3a40bb75b9e7140025f359c42fe (patch)
tree555d78bd7f15e1b5bc0c085481be4b0921408250
parent1a6379f0613c6291a559d8c1ffee51628bc3d04b (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.py34
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,