Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use fcopyfile() / sendfile() where available.
  • Loading branch information
barneygale committed May 15, 2024
commit 092a0e018ffecb8baa52ea36f02ab777ab223d7f
4 changes: 2 additions & 2 deletions Lib/pathlib/_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import functools
from glob import _Globber, _no_recurse_symlinks
from errno import ENOTDIR, ELOOP
from shutil import copyfileobj
from shutil import _fastcopy
from stat import S_ISDIR, S_ISLNK, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO


Expand Down Expand Up @@ -787,7 +787,7 @@ def copy(self, target, follow_symlinks=True):

with self.open('rb') as f_source:
with target.open('wb') as f_target:
copyfileobj(f_source, f_target)
_fastcopy(f_source, f_target)

# FIXME: how do we copy metadata between PathBase instances?
return target
Expand Down
45 changes: 24 additions & 21 deletions Lib/shutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,29 @@ class _GiveupOnFastCopy(Exception):
file copy when fast-copy functions fail to do so.
"""

def _fastcopy(fsrc, fdst, file_size=0):
# macOS
if _HAS_FCOPYFILE:
try:
_fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
return
except _GiveupOnFastCopy:
pass
# Linux
elif _USE_CP_SENDFILE:
try:
_fastcopy_sendfile(fsrc, fdst)
return
except _GiveupOnFastCopy:
pass
# Windows, see:
# https://github.com/python/cpython/pull/7160#discussion_r195405230
elif _WINDOWS and file_size > 0:
_copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
return

copyfileobj(fsrc, fdst)

def _fastcopy_fcopyfile(fsrc, fdst, flags):
"""Copy a regular file content or metadata by using high-performance
fcopyfile(3) syscall (macOS).
Expand Down Expand Up @@ -260,27 +283,7 @@ def copyfile(src, dst, *, follow_symlinks=True):
with open(src, 'rb') as fsrc:
try:
with open(dst, 'wb') as fdst:
# macOS
if _HAS_FCOPYFILE:
try:
_fastcopy_fcopyfile(fsrc, fdst, posix._COPYFILE_DATA)
return dst
except _GiveupOnFastCopy:
pass
# Linux
elif _USE_CP_SENDFILE:
try:
_fastcopy_sendfile(fsrc, fdst)
return dst
except _GiveupOnFastCopy:
pass
# Windows, see:
# https://github.com/python/cpython/pull/7160#discussion_r195405230
elif _WINDOWS and file_size > 0:
_copyfileobj_readinto(fsrc, fdst, min(file_size, COPY_BUFSIZE))
return dst

copyfileobj(fsrc, fdst)
_fastcopy(fsrc, fdst, file_size)

# Issue 43219, raise a less confusing exception
except IsADirectoryError as e:
Expand Down