Skip to content

Commit 7bf491d

Browse files
committed
Use CopyFileEx for fs::copy on Windows
Signed-off-by: Peter Atashian <[email protected]>
1 parent 4a21775 commit 7bf491d

File tree

4 files changed

+75
-15
lines changed

4 files changed

+75
-15
lines changed

src/libstd/fs.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use core::prelude::*;
2121

2222
use fmt;
2323
use ffi::OsString;
24-
use io::{self, Error, ErrorKind, SeekFrom, Seek, Read, Write};
24+
use io::{self, SeekFrom, Seek, Read, Write};
2525
use path::{Path, PathBuf};
2626
use sys::fs as fs_imp;
2727
use sys_common::{AsInnerMut, FromInner, AsInner};
@@ -858,20 +858,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
858858
/// ```
859859
#[stable(feature = "rust1", since = "1.0.0")]
860860
pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
861-
let from = from.as_ref();
862-
let to = to.as_ref();
863-
if !from.is_file() {
864-
return Err(Error::new(ErrorKind::InvalidInput,
865-
"the source path is not an existing file"))
866-
}
867-
868-
let mut reader = try!(File::open(from));
869-
let mut writer = try!(File::create(to));
870-
let perm = try!(reader.metadata()).permissions();
871-
872-
let ret = try!(io::copy(&mut reader, &mut writer));
873-
try!(set_permissions(to, perm));
874-
Ok(ret)
861+
fs_imp::copy(from.as_ref(), to.as_ref())
875862
}
876863

877864
/// Creates a new hard link on the filesystem.

src/libstd/sys/unix/fs.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,3 +516,20 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
516516
buf.truncate(p);
517517
Ok(PathBuf::from(OsString::from_vec(buf)))
518518
}
519+
520+
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
521+
let from = from.as_ref();
522+
let to = to.as_ref();
523+
if !from.is_file() {
524+
return Err(Error::new(ErrorKind::InvalidInput,
525+
"the source path is not an existing file"))
526+
}
527+
528+
let mut reader = try!(File::open(from));
529+
let mut writer = try!(File::create(to));
530+
let perm = try!(reader.metadata()).permissions();
531+
532+
let ret = try!(io::copy(&mut reader, &mut writer));
533+
try!(set_permissions(to, perm));
534+
Ok(ret)
535+
}

src/libstd/sys/windows/c.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ pub const STD_ERROR_HANDLE: libc::DWORD = -12i32 as libc::DWORD;
6666

6767
pub const HANDLE_FLAG_INHERIT: libc::DWORD = 0x00000001;
6868

69+
pub const PROGRESS_CONTINUE: libc::DWORD = 0;
70+
pub const PROGRESS_CANCEL: libc::DWORD = 1;
71+
pub const PROGRESS_STOP: libc::DWORD = 2;
72+
pub const PROGRESS_QUIET: libc::DWORD = 3;
73+
74+
pub const COPY_FILE_ALLOW_DECRYPTED_DESTINATION: libc::DWORD = 0x00000008;
75+
6976
#[repr(C)]
7077
#[cfg(target_arch = "x86")]
7178
pub struct WSADATA {
@@ -249,6 +256,19 @@ pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE;
249256
pub type PSRWLOCK = *mut SRWLOCK;
250257
pub type ULONG = c_ulong;
251258
pub type ULONG_PTR = c_ulong;
259+
pub type LPBOOL = *mut BOOL;
260+
261+
pub type LPPROGRESS_ROUTINE = ::option::Option<unsafe extern "system" fn(
262+
TotalFileSize: libc::LARGE_INTEGER,
263+
TotalBytesTransferred: libc::LARGE_INTEGER,
264+
StreamSize: libc::LARGE_INTEGER,
265+
StreamBytesTransferred: libc::LARGE_INTEGER,
266+
dwStreamNumber: DWORD,
267+
dwCallbackReason: DWORD,
268+
hSourceFile: HANDLE,
269+
hDestinationFile: HANDLE,
270+
lpData: LPVOID,
271+
) -> DWORD>;
252272

253273
#[repr(C)]
254274
pub struct CONDITION_VARIABLE { pub ptr: LPVOID }
@@ -413,6 +433,14 @@ extern "system" {
413433
pub fn SetHandleInformation(hObject: libc::HANDLE,
414434
dwMask: libc::DWORD,
415435
dwFlags: libc::DWORD) -> libc::BOOL;
436+
pub fn CopyFileExW(
437+
lpExistingFileName: libc::LPCWSTR,
438+
lpNewFileName: libc::LPCWSTR,
439+
lpProgressRoutine: LPPROGRESS_ROUTINE,
440+
lpData: libc::LPVOID,
441+
pbCancel: LPBOOL,
442+
dwCopyFlags: libc::DWORD,
443+
) -> libc::BOOL;
416444
}
417445

418446
// Functions that aren't available on Windows XP, but we still use them and just

src/libstd/sys/windows/fs.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,3 +575,31 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
575575
PathBuf::from(OsString::from_wide(buf))
576576
})
577577
}
578+
579+
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
580+
unsafe extern "system" fn callback(
581+
_TotalFileSize: libc::LARGE_INTEGER,
582+
TotalBytesTransferred: libc::LARGE_INTEGER,
583+
_StreamSize: libc::LARGE_INTEGER,
584+
_StreamBytesTransferred: libc::LARGE_INTEGER,
585+
_dwStreamNumber: libc::DWORD,
586+
_dwCallbackReason: libc::DWORD,
587+
_hSourceFile: HANDLE,
588+
_hDestinationFile: HANDLE,
589+
lpData: libc::LPVOID,
590+
) -> libc::DWORD {
591+
// Alternative is to just grab TotalFileSize and return PROGRESS_QUIET
592+
*(lpData as *mut i64) = TotalBytesTransferred;
593+
c::PROGRESS_CONTINUE
594+
}
595+
let pfrom = to_utf16(from);
596+
let pto = to_utf16(to);
597+
let mut size = 0i64;
598+
// Do we want to allow encrypted files to be copied to a decrypted destination?
599+
try!(cvt(unsafe {
600+
c::CopyFileExW(pfrom.as_ptr(), pto.as_ptr(), Some(callback),
601+
&mut size as *mut _ as *mut _, ptr::null_mut(),
602+
c::COPY_FILE_ALLOW_DECRYPTED_DESTINATION)
603+
}));
604+
Ok(size as u64)
605+
}

0 commit comments

Comments
 (0)