@@ -12,7 +12,7 @@ use crate::slice;
1212use crate :: sync:: Arc ;
1313use crate :: sys:: handle:: Handle ;
1414use crate :: sys:: time:: SystemTime ;
15- use crate :: sys:: { c, cvt, Align8 } ;
15+ use crate :: sys:: { c, compat , cvt, Align8 } ;
1616use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
1717use crate :: thread;
1818
@@ -1419,36 +1419,88 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
14191419}
14201420
14211421pub fn copy ( from : & Path , to : & Path ) -> io:: Result < u64 > {
1422- unsafe extern "system" fn callback (
1423- _TotalFileSize : c:: LARGE_INTEGER ,
1424- _TotalBytesTransferred : c:: LARGE_INTEGER ,
1425- _StreamSize : c:: LARGE_INTEGER ,
1426- StreamBytesTransferred : c:: LARGE_INTEGER ,
1427- dwStreamNumber : c:: DWORD ,
1428- _dwCallbackReason : c:: DWORD ,
1429- _hSourceFile : c:: HANDLE ,
1430- _hDestinationFile : c:: HANDLE ,
1431- lpData : c:: LPCVOID ,
1432- ) -> c:: DWORD {
1433- if dwStreamNumber == 1 {
1434- * ( lpData as * mut i64 ) = StreamBytesTransferred ;
1435- }
1436- c:: PROGRESS_CONTINUE
1437- }
14381422 let pfrom = maybe_verbatim ( from) ?;
14391423 let pto = maybe_verbatim ( to) ?;
1440- let mut size = 0i64 ;
1441- cvt ( unsafe {
1442- c:: CopyFileExW (
1443- pfrom. as_ptr ( ) ,
1444- pto. as_ptr ( ) ,
1445- Some ( callback) ,
1446- & mut size as * mut _ as * mut _ ,
1447- ptr:: null_mut ( ) ,
1448- 0 ,
1449- )
1450- } ) ?;
1451- Ok ( size as u64 )
1424+
1425+ // NT 4+
1426+ //
1427+ // For some reason, unicows implements CopyFileExW similarly to other functions (convert to
1428+ // ANSI, call ...A API). However, 9x/ME don't support CopyFileExA either! This means we have to
1429+ // check both for the API to exist *and* that we're running on NT.
1430+ if c:: CopyFileExW :: available ( ) && compat:: version:: is_windows_nt ( ) {
1431+ unsafe extern "system" fn callback (
1432+ _TotalFileSize : c:: LARGE_INTEGER ,
1433+ _TotalBytesTransferred : c:: LARGE_INTEGER ,
1434+ _StreamSize : c:: LARGE_INTEGER ,
1435+ StreamBytesTransferred : c:: LARGE_INTEGER ,
1436+ dwStreamNumber : c:: DWORD ,
1437+ _dwCallbackReason : c:: DWORD ,
1438+ _hSourceFile : c:: HANDLE ,
1439+ _hDestinationFile : c:: HANDLE ,
1440+ lpData : c:: LPCVOID ,
1441+ ) -> c:: DWORD {
1442+ if dwStreamNumber == 1 {
1443+ * ( lpData as * mut i64 ) = StreamBytesTransferred ;
1444+ }
1445+ c:: PROGRESS_CONTINUE
1446+ }
1447+
1448+ let mut size = 0i64 ;
1449+ cvt ( unsafe {
1450+ c:: CopyFileExW (
1451+ pfrom. as_ptr ( ) ,
1452+ pto. as_ptr ( ) ,
1453+ Some ( callback) ,
1454+ & mut size as * mut _ as * mut _ ,
1455+ ptr:: null_mut ( ) ,
1456+ 0 ,
1457+ )
1458+ } ) ?;
1459+ Ok ( size as u64 )
1460+ } else {
1461+ // NT 3.51 and earlier, or 9x/ME
1462+
1463+ // If `CopyFileExW` is not available, we have to copy the file with the non-Ex API,
1464+ // then open it with `dwDesiredAccess = 0` (query attributes only),
1465+ // then use `GetFileSize` to retrieve the size
1466+ cvt ( unsafe {
1467+ c:: CopyFileW (
1468+ pfrom. as_ptr ( ) ,
1469+ pto. as_ptr ( ) ,
1470+ c:: FALSE , // FALSE: allow overwriting
1471+ )
1472+ } ) ?;
1473+
1474+ let handle = unsafe {
1475+ c:: CreateFileW (
1476+ pto. as_ptr ( ) ,
1477+ 0 ,
1478+ c:: FILE_SHARE_READ | c:: FILE_SHARE_WRITE ,
1479+ ptr:: null_mut ( ) ,
1480+ c:: OPEN_EXISTING ,
1481+ 0 ,
1482+ ptr:: null_mut ( ) ,
1483+ )
1484+ } ;
1485+
1486+ let handle = if let Ok ( handle) = OwnedHandle :: try_from ( handle) {
1487+ handle
1488+ } else {
1489+ return Err ( Error :: last_os_error ( ) ) ;
1490+ } ;
1491+
1492+ let mut upper_dword: c:: DWORD = 0 ;
1493+ let lower_dword = unsafe { c:: GetFileSize ( handle. as_raw_handle ( ) , & mut upper_dword) } ;
1494+
1495+ if lower_dword == c:: INVALID_FILE_SIZE {
1496+ let errno = crate :: sys:: os:: errno ( ) ;
1497+ if errno != c:: STATUS_SUCCESS {
1498+ return Err ( Error :: from_raw_os_error ( errno) ) ;
1499+ }
1500+ }
1501+
1502+ Ok ( ( upper_dword as u64 ) << 32 | lower_dword as u64 )
1503+ }
14521504}
14531505
14541506#[ allow( dead_code) ]
0 commit comments