// Package gorecurcopy provides recursive copying in Go (golang) with a // minimum of extra packages. Original concept by Oleg Neumyvakin // (https://stackoverflow.com/users/1592008/oleg-neumyvakin) and modified // by Dirk Avery. // Slightly modified by me. package main import ( "fmt" "io" "io/ioutil" "os" "path/filepath" // "syscall" ) // copyDir recursively copies a src directory to a destination. func copyDir(src, dst string) error { entries, err := ioutil.ReadDir(src) if err != nil { return err } for _, entry := range entries { sourcePath := filepath.Join(src, entry.Name()) destPath := filepath.Join(dst, entry.Name()) fileInfo, err := os.Lstat(sourcePath) if err != nil { return err } switch fileInfo.Mode() & os.ModeType { case os.ModeDir: if err := _createDir(destPath, 0755); err != nil { return err } if err := copyDir(sourcePath, destPath); err != nil { return err } case os.ModeSymlink: if err := copySymlink(sourcePath, destPath); err != nil { return err } default: if err := _copy(sourcePath, destPath); err != nil { return err } } /* stat, ok := fileInfo.Sys().(*syscall.Stat_t) if !ok { return fmt.Errorf("failed to get raw syscall.Stat_t data for '%s'", sourcePath) } if err := os.Lchown(destPath, int(stat.Uid), int(stat.Gid)); err != nil { return err } */ isSymlink := entry.Mode()&os.ModeSymlink != 0 if !isSymlink { if err := os.Chmod(destPath, entry.Mode()); err != nil { return err } } } return nil } // Copy copies a src file to a dst file where src and dst are regular files. func _copy(src, dst string) error { sourceFileStat, err := os.Stat(src) if err != nil { return err } if !sourceFileStat.Mode().IsRegular() { return fmt.Errorf("%s is not a regular file", src) } source, err := os.Open(src) if err != nil { return err } defer source.Close() destination, err := os.Create(dst) if err != nil { return err } defer destination.Close() _, err = io.Copy(destination, source) return err } func _exists(path string) bool { if _, err := os.Stat(path); os.IsNotExist(err) { return false } return true } func _createDir(dir string, perm os.FileMode) error { if _exists(dir) { return nil } if err := os.MkdirAll(dir, perm); err != nil { return fmt.Errorf("failed to create directory: '%s', error: '%s'", dir, err.Error()) } return nil } // copySymlink copies a symbolic link from src to dst. func copySymlink(src, dst string) error { link, err := os.Readlink(src) if err != nil { return err } return os.Symlink(link, dst) }