@@ -604,14 +604,44 @@ extension FileManager {
604
604
}
605
605
606
606
try withNTPathRepresentation ( of: dstPath) { wszDestination in
607
- var faAttributes : WIN32_FILE_ATTRIBUTE_DATA = . init( )
608
- if GetFileAttributesExW ( wszDestination, GetFileExInfoStandard, & faAttributes ) {
607
+ var faDestinationnAttributes : WIN32_FILE_ATTRIBUTE_DATA = . init( )
608
+ if GetFileAttributesExW ( wszDestination, GetFileExInfoStandard, & faDestinationnAttributes ) {
609
609
throw CocoaError . error ( . fileWriteFileExists, userInfo: [ NSFilePathErrorKey: dstPath] )
610
610
}
611
611
612
612
try withNTPathRepresentation ( of: srcPath) { wszSource in
613
- if !MoveFileExW( wszSource, wszDestination, DWORD ( MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH) ) {
614
- throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: false , paths: [ srcPath, dstPath] )
613
+ var faSourceAttributes : WIN32_FILE_ATTRIBUTE_DATA = . init( )
614
+ guard GetFileAttributesExW ( wszSource, GetFileExInfoStandard, & faSourceAttributes) else {
615
+ throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: true , paths: [ srcPath] )
616
+ }
617
+
618
+ // MoveFileExW does not work if the source and destination are
619
+ // on different volumes and the source is a directory. In that
620
+ // case, we need to do a recursive copy & remove.
621
+ if PathIsSameRootW ( wszSource, wszDestination) ||
622
+ faSourceAttributes. dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == 0 {
623
+ if !MoveFileExW( wszSource, wszDestination, DWORD ( MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH) ) {
624
+ throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: false , paths: [ srcPath, dstPath] )
625
+ }
626
+ } else {
627
+ try _copyOrLinkDirectoryHelper ( atPath: srcPath, toPath: dstPath, variant: " Move " ) { ( src, dst, type) in
628
+ do {
629
+ switch type {
630
+ case . typeRegular:
631
+ try _copyRegularFile ( atPath: src, toPath: dst, variant: " Move " )
632
+ case . typeSymbolicLink:
633
+ try _copySymlink ( atPath: src, toPath: dst, variant: " Move " )
634
+ default :
635
+ break
636
+ }
637
+ } catch {
638
+ if !shouldProceedAfterError( error, movingItemAtPath: src, toPath: dst, isURL: isURL) {
639
+ throw error
640
+ }
641
+ }
642
+
643
+ try _removeItem ( atPath: src, isURL: isURL, alreadyConfirmed: true )
644
+ }
615
645
}
616
646
}
617
647
}
0 commit comments