4545# include < copyfile.h>
4646# define _LIBCPP_FILESYSTEM_USE_COPYFILE
4747#else
48- # include < fstream>
4948# define _LIBCPP_FILESYSTEM_USE_FSTREAM
5049#endif
5150
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+
5259#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
5360# pragma comment(lib, "rt")
5461#endif
@@ -179,6 +186,42 @@ void __copy(const path& from, const path& to, copy_options options, error_code*
179186namespace detail {
180187namespace {
181188
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+
182225#if defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE)
183226bool copy_file_impl_copy_file_range (FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
184227 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
209252#if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE)
210253bool copy_file_impl_sendfile (FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
211254 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+ }
212261 do {
213262 ssize_t res;
214263 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
259308 }
260309 ec.clear ();
261310# endif
262- ec = {EINVAL, generic_category ()};
263- return false ;
311+
312+ return copy_file_impl_fstream (read_fd, write_fd, ec) ;
264313}
265314#elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE)
266315bool 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
285334}
286335#elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM)
287336bool 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);
319338}
320339#else
321340# error "Unknown implementation for copy_file_impl"
0 commit comments