Skip to content

Instantly share code, notes, and snippets.

@dexterp
Last active April 11, 2024 19:15
Show Gist options
  • Save dexterp/37c01890afdccd7e8cde1d11719a2ca6 to your computer and use it in GitHub Desktop.
Save dexterp/37c01890afdccd7e8cde1d11719a2ca6 to your computer and use it in GitHub Desktop.
GO Move Files Across devices
package main
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
// MoveAll recursively move a directory or file from src to dst.
func MoveAll(src, dst string) error {
err := CopyAll(src, dst)
if err != nil {
return err
}
err = os.RemoveAll(src)
return err
}
// CopyAll recursively copy a directory or file from src to dst.
func CopyAll(src, dst string) error {
/* Source Checks */
// Check src exists
srcInfo, err := os.Stat(src)
if errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("move %s %s: no such file or directory", src, dst)
} else if err != nil {
return err
}
// Check file is a regular file
if !srcInfo.Mode().IsRegular() && !srcInfo.Mode().IsDir() {
return fmt.Errorf("move %s %s: not a file or directory", src, dst)
}
// Check parent directory of destination exits
dir := filepath.Dir(dst)
dstInfo, err := os.Stat(dir)
if errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("move %s %s: no such file or directory", src, dst)
}
// Check if parent of destination is a directory
if dstInfo.Mode()&os.ModeDir != os.ModeDir {
return fmt.Errorf("move %s %s: parent of destination is not a directory", src, dst)
}
type metadata struct {
path string
info os.FileInfo
}
err = filepath.Walk(src, func(srcPath string, srcPathInfo os.FileInfo, err error) error {
srcMode := srcPathInfo.Mode()
dstPath := filepath.Join(dst, strings.TrimPrefix(srcPath, src))
switch {
case errors.Is(err, os.ErrNotExist):
return err
case srcMode.IsDir():
err = os.MkdirAll(dstPath, os.ModePerm)
return err
case srcMode.IsRegular():
_, err := Copy(srcPath, dstPath)
return err
case srcMode&os.ModeSymlink != 0:
link, err := os.Readlink(srcPathInfo.Name())
if err != nil {
return err
}
err = os.Symlink(dstPath, link)
return err
}
return fmt.Errorf("move %s %s: unsupported file type", srcPath, dstPath)
})
return err
}
// Move move src file to dst, returns the number of bytes that were moved.
func Move(src, dst string) (int64, error) {
n, err := Copy(src, dst)
if err != nil {
return n, err
}
err = os.Remove(src)
return n, err
}
// Copy copy src file to dst, returns the number of bytes that were copied.
func Copy(src, dst string) (int64, error) {
sourceFileStat, err := os.Stat(src)
if err != nil {
return 0, err
}
if !sourceFileStat.Mode().IsRegular() {
return 0, fmt.Errorf("%s is not a regular file", src)
}
source, err := os.Open(src)
if err != nil {
return 0, err
}
defer source.Close()
destination, err := os.Create(dst)
if err != nil {
return 0, err
}
defer destination.Close()
nBytes, err := io.Copy(destination, source)
return nBytes, err
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment