138 lines
2.6 KiB
Go
138 lines
2.6 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
)
|
|
|
|
func copySize(srcs []string) (int64, error) {
|
|
var total int64
|
|
|
|
for _, src := range srcs {
|
|
_, err := os.Lstat(src)
|
|
if os.IsNotExist(err) {
|
|
return total, fmt.Errorf("src does not exist: %q", src)
|
|
}
|
|
|
|
err = filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return fmt.Errorf("walk: %s", err)
|
|
}
|
|
total += info.Size()
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return total, err
|
|
}
|
|
}
|
|
|
|
return total, nil
|
|
}
|
|
|
|
func copyFile(src, dst string, info os.FileInfo, nums chan int64) error {
|
|
buf := make([]byte, 4096)
|
|
|
|
r, err := os.Open(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer r.Close()
|
|
|
|
w, err := os.Create(dst)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for {
|
|
n, err := r.Read(buf)
|
|
if err != nil && err != io.EOF {
|
|
w.Close()
|
|
os.Remove(dst)
|
|
return err
|
|
}
|
|
|
|
if n == 0 {
|
|
break
|
|
}
|
|
|
|
if _, err := w.Write(buf[:n]); err != nil {
|
|
return err
|
|
}
|
|
|
|
nums <- int64(n)
|
|
}
|
|
|
|
if err := w.Close(); err != nil {
|
|
os.Remove(dst)
|
|
return err
|
|
}
|
|
|
|
if err := os.Chmod(dst, info.Mode()); err != nil {
|
|
os.Remove(dst)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func copyAll(srcs []string, dstDir string) (nums chan int64, errs chan error) {
|
|
nums = make(chan int64, 1024)
|
|
errs = make(chan error, 1024)
|
|
|
|
go func() {
|
|
for _, src := range srcs {
|
|
dst := filepath.Join(dstDir, filepath.Base(src))
|
|
|
|
_, err := os.Lstat(dst)
|
|
if !os.IsNotExist(err) {
|
|
var newPath string
|
|
for i := 1; !os.IsNotExist(err); i++ {
|
|
newPath = fmt.Sprintf("%s.~%d~", dst, i)
|
|
_, err = os.Lstat(newPath)
|
|
}
|
|
dst = newPath
|
|
}
|
|
|
|
filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
errs <- fmt.Errorf("walk: %s", err)
|
|
return nil
|
|
}
|
|
rel, err := filepath.Rel(src, path)
|
|
if err != nil {
|
|
errs <- fmt.Errorf("relative: %s", err)
|
|
return nil
|
|
}
|
|
newPath := filepath.Join(dst, rel)
|
|
if info.IsDir() {
|
|
if err := os.MkdirAll(newPath, info.Mode()); err != nil {
|
|
errs <- fmt.Errorf("mkdir: %s", err)
|
|
}
|
|
nums <- info.Size()
|
|
} else if info.Mode()&os.ModeSymlink != 0 { /* Symlink */
|
|
if rlink, err := os.Readlink(path); err != nil {
|
|
errs <- fmt.Errorf("symlink: %s", err)
|
|
} else {
|
|
if err := os.Symlink(rlink, newPath); err != nil {
|
|
errs <- fmt.Errorf("symlink: %s", err)
|
|
}
|
|
}
|
|
nums <- info.Size()
|
|
} else {
|
|
if err := copyFile(path, newPath, info, nums); err != nil {
|
|
errs <- fmt.Errorf("copy: %s", err)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
close(errs)
|
|
}()
|
|
|
|
return nums, errs
|
|
}
|