20
20
_winapi = None
21
21
22
22
23
- def get_copy_blocksize (infd ):
23
+ def _get_copy_blocksize (infd ):
24
24
"""Determine blocksize for fastcopying on Linux.
25
25
Hopefully the whole file will be copied in a single call.
26
26
The copying itself should be performed in a loop 'till EOF is
@@ -40,56 +40,64 @@ def get_copy_blocksize(infd):
40
40
41
41
42
42
if fcntl and hasattr (fcntl , 'FICLONE' ):
43
- def clonefd (source_fd , target_fd ):
43
+ def _ficlone (source_fd , target_fd ):
44
44
"""
45
45
Perform a lightweight copy of two files, where the data blocks are
46
46
copied only when modified. This is known as Copy on Write (CoW),
47
47
instantaneous copy or reflink.
48
48
"""
49
49
fcntl .ioctl (target_fd , fcntl .FICLONE , source_fd )
50
50
else :
51
- clonefd = None
51
+ _ficlone = None
52
52
53
53
54
54
if posix and hasattr (posix , '_fcopyfile' ):
55
- def copyfd (source_fd , target_fd ):
55
+ def _fcopyfile (source_fd , target_fd ):
56
56
"""
57
57
Copy a regular file content using high-performance fcopyfile(3)
58
58
syscall (macOS).
59
59
"""
60
60
posix ._fcopyfile (source_fd , target_fd , posix ._COPYFILE_DATA )
61
- elif hasattr (os , 'copy_file_range' ):
62
- def copyfd (source_fd , target_fd ):
61
+ else :
62
+ _fcopyfile = None
63
+
64
+
65
+ if hasattr (os , 'copy_file_range' ):
66
+ def _copy_file_range (source_fd , target_fd ):
63
67
"""
64
68
Copy data from one regular mmap-like fd to another by using a
65
69
high-performance copy_file_range(2) syscall that gives filesystems
66
70
an opportunity to implement the use of reflinks or server-side
67
71
copy.
68
72
This should work on Linux >= 4.5 only.
69
73
"""
70
- blocksize = get_copy_blocksize (source_fd )
74
+ blocksize = _get_copy_blocksize (source_fd )
71
75
offset = 0
72
76
while True :
73
77
sent = os .copy_file_range (source_fd , target_fd , blocksize ,
74
78
offset_dst = offset )
75
79
if sent == 0 :
76
80
break # EOF
77
81
offset += sent
78
- elif hasattr (os , 'sendfile' ):
79
- def copyfd (source_fd , target_fd ):
82
+ else :
83
+ _copy_file_range = None
84
+
85
+
86
+ if hasattr (os , 'sendfile' ):
87
+ def _sendfile (source_fd , target_fd ):
80
88
"""Copy data from one regular mmap-like fd to another by using
81
89
high-performance sendfile(2) syscall.
82
90
This should work on Linux >= 2.6.33 only.
83
91
"""
84
- blocksize = get_copy_blocksize (source_fd )
92
+ blocksize = _get_copy_blocksize (source_fd )
85
93
offset = 0
86
94
while True :
87
95
sent = os .sendfile (target_fd , source_fd , offset , blocksize )
88
96
if sent == 0 :
89
97
break # EOF
90
98
offset += sent
91
99
else :
92
- copyfd = None
100
+ _sendfile = None
93
101
94
102
95
103
if _winapi and hasattr (_winapi , 'CopyFile2' ):
@@ -114,18 +122,36 @@ def copyfileobj(source_f, target_f):
114
122
else :
115
123
try :
116
124
# Use OS copy-on-write where available.
117
- if clonefd :
125
+ if _ficlone :
118
126
try :
119
- clonefd (source_fd , target_fd )
127
+ _ficlone (source_fd , target_fd )
120
128
return
121
129
except OSError as err :
122
130
if err .errno not in (EBADF , EOPNOTSUPP , ETXTBSY , EXDEV ):
123
131
raise err
124
132
125
133
# Use OS copy where available.
126
- if copyfd :
127
- copyfd (source_fd , target_fd )
128
- return
134
+ if _fcopyfile :
135
+ try :
136
+ _fcopyfile (source_fd , target_fd )
137
+ return
138
+ except OSError as err :
139
+ if err .errno not in (EINVAL , ENOTSUP ):
140
+ raise err
141
+ if _copy_file_range :
142
+ try :
143
+ _copy_file_range (source_fd , target_fd )
144
+ return
145
+ except OSError as err :
146
+ if err .errno not in (ETXTBSY , EXDEV ):
147
+ raise err
148
+ if _sendfile :
149
+ try :
150
+ _sendfile (source_fd , target_fd )
151
+ return
152
+ except OSError as err :
153
+ if err .errno != ENOTSOCK :
154
+ raise err
129
155
except OSError as err :
130
156
# Produce more useful error messages.
131
157
err .filename = source_f .name
0 commit comments