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