Skip to content

Instantly share code, notes, and snippets.

@rikonor
Created April 23, 2019 08:29
Show Gist options
  • Select an option

  • Save rikonor/bdae8510d8ed5a8decd1c99d62f2350d to your computer and use it in GitHub Desktop.

Select an option

Save rikonor/bdae8510d8ed5a8decd1c99d62f2350d to your computer and use it in GitHub Desktop.
Rename a file with fallback when encountering "invalid cross-device link"
package rename
// renameFile renames a file
// it can be used instead of os.Rename in cases where we attempt
// to move files between partitions (e.g when using Docker volumes)
func renameFile(src string, dst string) error {
err := os.Rename(src, dst)
if err == nil {
return nil
}
if !isInvalidCrossDeviceLinkErr(err) {
return errs.Append(err, "failed to rename file")
}
// fallback to manual copying of the file
if err := copyFile(src, dst); err != nil {
return errs.Append(err, "failed to copy file")
}
// remove src file
if err := os.Remove(src); err != nil {
return errs.Append(err, "failed to remove src file")
}
return nil
}
func copyFile(src string, dst string) error {
// Open source file
fSrc, err := os.Open(src)
if err != nil {
return err
}
defer fSrc.Close()
// Create destination file
fDst, err := os.Create(dst)
if err != nil {
return err
}
defer fDst.Close()
// Copy from source to destination
if _, err := io.Copy(fDst, fSrc); err != nil {
return err
}
return nil
}
func isInvalidCrossDeviceLinkErr(err error) bool {
lErr, ok := err.(*os.LinkError)
if !ok {
return false
}
uErr, ok := lErr.Err.(syscall.Errno)
if !ok {
return false
}
if int(uErr) != 18 {
return false
}
return true
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment