4949# include < copyfile.h>
5050# define _LIBCPP_FILESYSTEM_USE_COPYFILE
5151#else
52- # include < fstream>
5352# define _LIBCPP_FILESYSTEM_USE_FSTREAM
5453#endif
5554
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+
5663#if defined(__ELF__) && defined(_LIBCPP_LINK_RT_LIB)
5764# pragma comment(lib, "rt")
5865#endif
@@ -183,6 +190,42 @@ void __copy(const path& from, const path& to, copy_options options, error_code*
183190namespace detail {
184191namespace {
185192
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+
186229#if defined(_LIBCPP_FILESYSTEM_USE_COPY_FILE_RANGE)
187230bool copy_file_impl_copy_file_range (FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
188231 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
214257#if defined(_LIBCPP_FILESYSTEM_USE_SENDFILE)
215258bool copy_file_impl_sendfile (FileDescriptor& read_fd, FileDescriptor& write_fd, error_code& ec) {
216259 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+ }
217266 do {
218267 ssize_t res;
219268 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
264313 }
265314 ec.clear ();
266315# endif
267- ec = {EINVAL, generic_category ()};
268- return false ;
316+
317+ return copy_file_impl_fstream (read_fd, write_fd, ec) ;
269318}
270319#elif defined(_LIBCPP_FILESYSTEM_USE_COPYFILE)
271320bool 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
290339}
291340#elif defined(_LIBCPP_FILESYSTEM_USE_FSTREAM)
292341bool 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);
324343}
325344#else
326345# error "Unknown implementation for copy_file_impl"
0 commit comments