use fmt;
use ffi::OsString;
-use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
+use io::{self, SeekFrom, Seek, Read, Write};
use path::{Path, PathBuf};
use sys::fs as fs_imp;
use sys_common::{AsInnerMut, FromInner, AsInner};
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
- let from = from.as_ref();
- let to = to.as_ref();
- if !from.is_file() {
- return Err(Error::new(ErrorKind::InvalidInput,
- "the source path is not an existing file"))
- }
-
- let mut reader = try!(File::open(from));
- let mut writer = try!(File::create(to));
- let perm = try!(reader.metadata()).permissions();
-
- let ret = try!(io::copy(&mut reader, &mut writer));
- try!(set_permissions(to, perm));
- Ok(ret)
+ fs_imp::copy(from.as_ref(), to.as_ref())
}
/// Creates a new hard link on the filesystem.
}
}
+ #[test]
+ fn copy_src_does_not_exist() {
+ let tmpdir = tmpdir();
+ let from = Path2::new("test/nonexistent-bogus-path");
+ let to = tmpdir.join("out.txt");
+ check!(check!(File::create(&to)).write(b"hello"));
+ assert!(fs::copy(&from, &to).is_err());
+ assert!(!from.exists());
+ let mut v = Vec::new();
+ check!(check!(File::open(&to)).read_to_end(&mut v));
+ assert_eq!(v, b"hello");
+ }
+
#[test]
fn copy_file_ok() {
let tmpdir = tmpdir();
check!(fs::set_permissions(&out, attr.permissions()));
}
+ #[cfg(windows)]
+ #[test]
+ fn copy_file_preserves_streams() {
+ let tmp = tmpdir();
+ check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
+ assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 6);
+ assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0);
+ let mut v = Vec::new();
+ check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v));
+ assert_eq!(v, b"carrot".to_vec());
+ }
+
#[cfg(not(windows))] // FIXME(#10264) operation not permitted?
#[test]
fn symlinks_work() {
use ffi::{CString, CStr, OsString, OsStr};
use fmt;
-use io::{self, Error, SeekFrom};
+use io::{self, Error, ErrorKind, SeekFrom};
use libc::{self, c_int, size_t, off_t, c_char, mode_t};
use mem;
use path::{Path, PathBuf};
buf.truncate(p);
Ok(PathBuf::from(OsString::from_vec(buf)))
}
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ use fs::{File, PathExt, set_permissions};
+ if !from.is_file() {
+ return Err(Error::new(ErrorKind::InvalidInput,
+ "the source path is not an existing file"))
+ }
+
+ let mut reader = try!(File::open(from));
+ let mut writer = try!(File::create(to));
+ let perm = try!(reader.metadata()).permissions();
+
+ let ret = try!(io::copy(&mut reader, &mut writer));
+ try!(set_permissions(to, perm));
+ Ok(ret)
+}
pub const HANDLE_FLAG_INHERIT: libc::DWORD = 0x00000001;
+pub const PROGRESS_CONTINUE: libc::DWORD = 0;
+pub const PROGRESS_CANCEL: libc::DWORD = 1;
+pub const PROGRESS_STOP: libc::DWORD = 2;
+pub const PROGRESS_QUIET: libc::DWORD = 3;
+
#[repr(C)]
#[cfg(target_arch = "x86")]
pub struct WSADATA {
pub type PSRWLOCK = *mut SRWLOCK;
pub type ULONG = c_ulong;
pub type ULONG_PTR = c_ulong;
+pub type LPBOOL = *mut BOOL;
+
+pub type LPPROGRESS_ROUTINE = ::option::Option<unsafe extern "system" fn(
+ TotalFileSize: libc::LARGE_INTEGER,
+ TotalBytesTransferred: libc::LARGE_INTEGER,
+ StreamSize: libc::LARGE_INTEGER,
+ StreamBytesTransferred: libc::LARGE_INTEGER,
+ dwStreamNumber: DWORD,
+ dwCallbackReason: DWORD,
+ hSourceFile: HANDLE,
+ hDestinationFile: HANDLE,
+ lpData: LPVOID,
+) -> DWORD>;
#[repr(C)]
pub struct CONDITION_VARIABLE { pub ptr: LPVOID }
pub fn SetHandleInformation(hObject: libc::HANDLE,
dwMask: libc::DWORD,
dwFlags: libc::DWORD) -> libc::BOOL;
+ pub fn CopyFileExW(lpExistingFileName: libc::LPCWSTR,
+ lpNewFileName: libc::LPCWSTR,
+ lpProgressRoutine: LPPROGRESS_ROUTINE,
+ lpData: libc::LPVOID,
+ pbCancel: LPBOOL,
+ dwCopyFlags: libc::DWORD) -> libc::BOOL;
}
// Functions that aren't available on Windows XP, but we still use them and just
PathBuf::from(OsString::from_wide(buf))
})
}
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ unsafe extern "system" fn callback(
+ _TotalFileSize: libc::LARGE_INTEGER,
+ TotalBytesTransferred: libc::LARGE_INTEGER,
+ _StreamSize: libc::LARGE_INTEGER,
+ _StreamBytesTransferred: libc::LARGE_INTEGER,
+ _dwStreamNumber: libc::DWORD,
+ _dwCallbackReason: libc::DWORD,
+ _hSourceFile: HANDLE,
+ _hDestinationFile: HANDLE,
+ lpData: libc::LPVOID,
+ ) -> libc::DWORD {
+ *(lpData as *mut i64) = TotalBytesTransferred;
+ c::PROGRESS_CONTINUE
+ }
+ let pfrom = to_utf16(from);
+ let pto = to_utf16(to);
+ let mut size = 0i64;
+ try!(cvt(unsafe {
+ c::CopyFileExW(pfrom.as_ptr(), pto.as_ptr(), Some(callback),
+ &mut size as *mut _ as *mut _, ptr::null_mut(), 0)
+ }));
+ Ok(size as u64)
+}