diff options
-rw-r--r-- | src/libstd/sys/unix/fs.rs | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 77968ffded..889d21cad6 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs | |||
@@ -794,6 +794,7 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { | |||
794 | Ok(PathBuf::from(OsString::from_vec(buf))) | 794 | Ok(PathBuf::from(OsString::from_vec(buf))) |
795 | } | 795 | } |
796 | 796 | ||
797 | #[cfg(not(any(target_os = "linux", target_os = "android")))] | ||
797 | pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { | 798 | pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { |
798 | use fs::{File, set_permissions}; | 799 | use fs::{File, set_permissions}; |
799 | if !from.is_file() { | 800 | if !from.is_file() { |
@@ -809,3 +810,90 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { | |||
809 | set_permissions(to, perm)?; | 810 | set_permissions(to, perm)?; |
810 | Ok(ret) | 811 | Ok(ret) |
811 | } | 812 | } |
813 | |||
814 | #[cfg(any(target_os = "linux", target_os = "android"))] | ||
815 | pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { | ||
816 | use cmp; | ||
817 | use fs::{File, set_permissions}; | ||
818 | use sync::atomic::{AtomicBool, Ordering}; | ||
819 | |||
820 | // Kernel prior to 4.5 don't have copy_file_range | ||
821 | // We store the availability in a global to avoid unneccessary syscalls | ||
822 | static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true); | ||
823 | |||
824 | unsafe fn copy_file_range( | ||
825 | fd_in: libc::c_int, | ||
826 | off_in: *mut libc::loff_t, | ||
827 | fd_out: libc::c_int, | ||
828 | off_out: *mut libc::loff_t, | ||
829 | len: libc::size_t, | ||
830 | flags: libc::c_uint, | ||
831 | ) -> libc::c_long { | ||
832 | libc::syscall( | ||
833 | libc::SYS_copy_file_range, | ||
834 | fd_in, | ||
835 | off_in, | ||
836 | fd_out, | ||
837 | off_out, | ||
838 | len, | ||
839 | flags, | ||
840 | ) | ||
841 | } | ||
842 | |||
843 | if !from.is_file() { | ||
844 | return Err(Error::new(ErrorKind::InvalidInput, | ||
845 | "the source path is not an existing regular file")) | ||
846 | } | ||
847 | |||
848 | let mut reader = File::open(from)?; | ||
849 | let mut writer = File::create(to)?; | ||
850 | let (perm, len) = { | ||
851 | let metadata = reader.metadata()?; | ||
852 | (metadata.permissions(), metadata.size()) | ||
853 | }; | ||
854 | |||
855 | let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); | ||
856 | let mut written = 0u64; | ||
857 | while written < len { | ||
858 | let copy_result = if has_copy_file_range { | ||
859 | let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize; | ||
860 | let copy_result = unsafe { | ||
861 | // We actually don't have to adjust the offsets, | ||
862 | // because copy_file_range adjusts the file offset automatically | ||
863 | cvt(copy_file_range(reader.as_raw_fd(), | ||
864 | ptr::null_mut(), | ||
865 | writer.as_raw_fd(), | ||
866 | ptr::null_mut(), | ||
867 | bytes_to_copy, | ||
868 | 0) | ||
869 | ) | ||
870 | }; | ||
871 | if let Err(ref copy_err) = copy_result { | ||
872 | if let Some(libc::ENOSYS) = copy_err.raw_os_error() { | ||
873 | HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); | ||
874 | } | ||
875 | } | ||
876 | copy_result | ||
877 | } else { | ||
878 | Err(io::Error::from_raw_os_error(libc::ENOSYS)) | ||
879 | }; | ||
880 | match copy_result { | ||
881 | Ok(ret) => written += ret as u64, | ||
882 | Err(err) => { | ||
883 | match err.raw_os_error() { | ||
884 | Some(os_err) if os_err == libc::ENOSYS || os_err == libc::EXDEV => { | ||
885 | // Either kernel is too old or the files are not mounted on the same fs. | ||
886 | // Try again with fallback method | ||
887 | assert_eq!(written, 0); | ||
888 | let ret = io::copy(&mut reader, &mut writer)?; | ||
889 | set_permissions(to, perm)?; | ||
890 | return Ok(ret) | ||
891 | }, | ||
892 | _ => return Err(err), | ||
893 | } | ||
894 | } | ||
895 | } | ||
896 | } | ||
897 | set_permissions(to, perm)?; | ||
898 | Ok(written) | ||
899 | } | ||