@@ -604,14 +604,44 @@ extension FileManager {
604604 }
605605
606606 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 ) {
609609 throw CocoaError . error ( . fileWriteFileExists, userInfo: [ NSFilePathErrorKey: dstPath] )
610610 }
611611
612612 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+ }
615645 }
616646 }
617647 }
0 commit comments