Fix rename when files are on different partition
Change-Id: I865bd90846d617b6619a2b5796b1767e2de8baba
diff --git a/osutil/rename.go b/osutil/rename.go
new file mode 100644
index 0000000..ccb6822
--- /dev/null
+++ b/osutil/rename.go
@@ -0,0 +1,27 @@
+package osutil
+
+import (
+ "os"
+ "os/exec"
+ "syscall"
+)
+
+func Rename(src, dst string) error {
+ if err := os.Rename(src, dst); err != nil {
+ // Check if the rename operation failed
+ // because the source and destination are
+ // located on different mount points.
+ linkErr, ok := err.(*os.LinkError)
+ if !ok {
+ return err
+ }
+ errno, ok := linkErr.Err.(syscall.Errno)
+ if !ok || errno != syscall.EXDEV {
+ return err
+ }
+ // Fall back to a non-atomic rename.
+ cmd := exec.Command("mv", src, dst)
+ return cmd.Run()
+ }
+ return nil
+}
diff --git a/project/project.go b/project/project.go
index e668c12..57b0b6d 100644
--- a/project/project.go
+++ b/project/project.go
@@ -27,6 +27,7 @@
"fuchsia.googlesource.com/jiri/gitutil"
"fuchsia.googlesource.com/jiri/googlesource"
"fuchsia.googlesource.com/jiri/log"
+ "fuchsia.googlesource.com/jiri/osutil"
"fuchsia.googlesource.com/jiri/runutil"
)
@@ -172,7 +173,7 @@
if err := ioutil.WriteFile(tmp, data, 0644); err != nil {
return fmtError(err)
}
- return fmtError(os.Rename(tmp, filename))
+ return fmtError(osutil.Rename(tmp, filename))
}
type LocalConfig struct {
@@ -2553,7 +2554,7 @@
if err := os.Chmod(tmpDir, os.FileMode(0755)); err != nil {
return fmtError(err)
}
- if err := os.Rename(tmpDir, op.destination); err != nil {
+ if err := osutil.Rename(tmpDir, op.destination); err != nil {
return fmtError(err)
}
if err := checkoutHeadRevision(jirix, op.project, false); err != nil {
@@ -2700,7 +2701,7 @@
if err := os.MkdirAll(path, perm); err != nil {
return fmtError(err)
}
- if err := os.Rename(op.source, op.destination); err != nil {
+ if err := osutil.Rename(op.source, op.destination); err != nil {
return fmtError(err)
}
}
diff --git a/update.go b/update.go
index 47f3710..e73314c 100644
--- a/update.go
+++ b/update.go
@@ -212,16 +212,16 @@
return err
}
- err = os.Rename(path, oldfile.Name())
+ err = osutil.Rename(path, oldfile.Name())
if err != nil {
return err
}
// Replace the existing version.
- err = os.Rename(newfile.Name(), path)
+ err = osutil.Rename(newfile.Name(), path)
if err != nil {
// Try to rollback the change in case of error.
- rerr := os.Rename(oldfile.Name(), path)
+ rerr := osutil.Rename(oldfile.Name(), path)
if rerr != nil {
return rerr
}