45
45
# include < copyfile.h>
46
46
# define _LIBCPP_FILESYSTEM_USE_COPYFILE
47
47
#else
48
- # include < fstream>
49
48
# define _LIBCPP_FILESYSTEM_USE_FSTREAM
50
49
#endif
51
50
51
+ // sendfile and copy_file_range need to fall back
52
+ // to the fstream implementation for special files
53
+ #if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE) || defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE) || \
54
+ defined (_LIBCPP_FILESYSTEM_USE_FSTREAM)
55
+ # include < fstream>
56
+ # define _LIBCPP_FILESYSTEM_NEED_FSTREAM
57
+ #endif
58
+
52
59
#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
53
60
# pragma comment(lib, "rt")
54
61
#endif
@@ -179,6 +186,42 @@ void __copy(const path& from, const path& to, copy_options options, error_code*
179
186
namespace detail {
180
187
namespace {
181
188
189
+ #if defined(_LIBCPP_FILESYSTEM_NEED_FSTREAM)
190
+ bool copy_file_impl_fstream (FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
191
+ ifstream in;
192
+ in.__open (read_fd.fd , ios::binary);
193
+ if (!in.is_open ()) {
194
+ // This assumes that __open didn't reset the error code.
195
+ ec = capture_errno ();
196
+ return false ;
197
+ }
198
+ read_fd.fd = -1 ;
199
+ ofstream out;
200
+ out.__open (write_fd.fd , ios::binary);
201
+ if (!out.is_open ()) {
202
+ ec = capture_errno ();
203
+ return false ;
204
+ }
205
+ write_fd.fd = -1 ;
206
+
207
+ if (in.good () && out.good ()) {
208
+ using InIt = istreambuf_iterator<char >;
209
+ using OutIt = ostreambuf_iterator<char >;
210
+ InIt bin (in);
211
+ InIt ein;
212
+ OutIt bout (out);
213
+ copy (bin, ein, bout);
214
+ }
215
+ if (out.fail () || in.fail ()) {
216
+ ec = make_error_code (errc::io_error);
217
+ return false ;
218
+ }
219
+
220
+ ec.clear ();
221
+ return true ;
222
+ }
223
+ #endif
224
+
182
225
#if defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE)
183
226
bool copy_file_impl_copy_file_range (FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
184
227
size_t count = read_fd.get_stat ().st_size ;
@@ -209,6 +252,12 @@ bool copy_file_impl_copy_file_range(FileDescriptor& read_fd, FileDescriptor& wri
209
252
#if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE)
210
253
bool copy_file_impl_sendfile (FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
211
254
size_t count = read_fd.get_stat ().st_size ;
255
+ // a zero-length file is either empty, or not copyable by this syscall
256
+ // return early to avoid the syscall cost
257
+ if (count == 0 ) {
258
+ ec = {EINVAL, generic_category ()};
259
+ return false ;
260
+ }
212
261
do {
213
262
ssize_t res;
214
263
if ((res = ::sendfile (write_fd.fd , read_fd.fd , nullptr , count)) == -1 ) {
@@ -259,8 +308,8 @@ bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_cod
259
308
}
260
309
ec.clear ();
261
310
# endif
262
- ec = {EINVAL, generic_category ()};
263
- return false ;
311
+
312
+ return copy_file_impl_fstream (read_fd, write_fd, ec) ;
264
313
}
265
314
#elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE)
266
315
bool copy_file_impl (FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
@@ -285,37 +334,7 @@ bool copy_file_impl(FileDescriptor& read_fd, FileDescriptor& write_fd, error_cod
285
334
}
286
335
#elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM)
287
336
bool copy_file_impl (FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
288
- ifstream in;
289
- in.__open (read_fd.fd , ios::binary);
290
- if (!in.is_open ()) {
291
- // This assumes that __open didn't reset the error code.
292
- ec = capture_errno ();
293
- return false ;
294
- }
295
- read_fd.fd = -1 ;
296
- ofstream out;
297
- out.__open (write_fd.fd , ios::binary);
298
- if (!out.is_open ()) {
299
- ec = capture_errno ();
300
- return false ;
301
- }
302
- write_fd.fd = -1 ;
303
-
304
- if (in.good () && out.good ()) {
305
- using InIt = istreambuf_iterator<char >;
306
- using OutIt = ostreambuf_iterator<char >;
307
- InIt bin (in);
308
- InIt ein;
309
- OutIt bout (out);
310
- copy (bin, ein, bout);
311
- }
312
- if (out.fail () || in.fail ()) {
313
- ec = make_error_code (errc::io_error);
314
- return false ;
315
- }
316
-
317
- ec.clear ();
318
- return true ;
337
+ return copy_file_impl_fstream (read_fd, write_fd, ec);
319
338
}
320
339
#else
321
340
# error "Unknown implementation for copy_file_impl"
0 commit comments