Browse Source

local fs rename: if it fails with a cross device error try a copy

I don't want to add a new setting for this, at least until we get the
first complain for a slow rename :)

Fixes #440
Nicola Murino 4 years ago
parent
commit
e1bf46c6a5
4 changed files with 32 additions and 9 deletions
  1. 0 7
      vfs/fileinfo_windows.go
  2. 9 2
      vfs/osfs.go
  3. 7 0
      vfs/sys_unix.go
  4. 16 0
      vfs/sys_windows.go

+ 0 - 7
vfs/fileinfo_windows.go

@@ -1,7 +0,0 @@
-package vfs
-
-import "syscall"
-
-func (fi FileInfo) getFileInfoSys() interface{} {
-	return syscall.Win32FileAttributeData{}
-}

+ 9 - 2
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.

+ 7 - 0
vfs/fileinfo_unix.go → 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)
+}

+ 16 - 0
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)
+}