diff --git a/vfs/fileinfo_windows.go b/vfs/fileinfo_windows.go deleted file mode 100644 index 9947677c..00000000 --- a/vfs/fileinfo_windows.go +++ /dev/null @@ -1,7 +0,0 @@ -package vfs - -import "syscall" - -func (fi FileInfo) getFileInfoSys() interface{} { - return syscall.Win32FileAttributeData{} -} diff --git a/vfs/osfs.go b/vfs/osfs.go index d749a9f2..c2c913e2 100644 --- a/vfs/osfs.go +++ b/vfs/osfs.go @@ -11,6 +11,7 @@ import ( "time" "github.com/eikenb/pipeat" + fscopy "github.com/otiai10/copy" "github.com/pkg/sftp" "github.com/rs/xid" @@ -98,8 +99,14 @@ func (*OsFs) Create(name string, flag int) (File, *PipeWriter, func(), error) { } // Rename renames (moves) source to target -func (*OsFs) Rename(source, target string) error { - return os.Rename(source, target) +func (fs *OsFs) Rename(source, target string) error { + err := os.Rename(source, target) + if err != nil && isCrossDeviceError(err) { + fsLog(fs, logger.LevelWarn, "cross device error detected while renaming %#v -> %#v. Trying a copy, this could take a long time", + source, target) + return fscopy.Copy(source, target) + } + return err } // Remove removes the named file or (empty) directory. diff --git a/vfs/fileinfo_unix.go b/vfs/sys_unix.go similarity index 77% rename from vfs/fileinfo_unix.go rename to vfs/sys_unix.go index a28ed3ea..6c98f0f0 100644 --- a/vfs/fileinfo_unix.go +++ b/vfs/sys_unix.go @@ -3,8 +3,11 @@ package vfs import ( + "errors" "os" "syscall" + + "golang.org/x/sys/unix" ) var ( @@ -27,3 +30,7 @@ func (fi FileInfo) getFileInfoSys() interface{} { Uid: uint32(defaultUID), Gid: uint32(defaultGID)} } + +func isCrossDeviceError(err error) bool { + return errors.Is(err, unix.EXDEV) +} diff --git a/vfs/sys_windows.go b/vfs/sys_windows.go new file mode 100644 index 00000000..0521a2e8 --- /dev/null +++ b/vfs/sys_windows.go @@ -0,0 +1,16 @@ +package vfs + +import ( + "errors" + "syscall" + + "golang.org/x/sys/windows" +) + +func (fi FileInfo) getFileInfoSys() interface{} { + return syscall.Win32FileAttributeData{} +} + +func isCrossDeviceError(err error) bool { + return errors.Is(err, windows.ERROR_NOT_SAME_DEVICE) +}