1// Package cp offers simple file and directory copying for Go.
2package cp
3
4import (
5	"errors"
6	"io"
7	"os"
8	"path/filepath"
9	"strings"
10)
11
12var errCopyFileWithDir = errors.New("dir argument to CopyFile")
13
14// CopyFile copies the file with path src to dst. The new file must not exist.
15// It is created with the same permissions as src.
16func CopyFile(dst, src string) error {
17	rf, err := os.Open(src)
18	if err != nil {
19		return err
20	}
21	defer rf.Close()
22	rstat, err := rf.Stat()
23	if err != nil {
24		return err
25	}
26	if rstat.IsDir() {
27		return errCopyFileWithDir
28	}
29
30	wf, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_EXCL, rstat.Mode())
31	if err != nil {
32		return err
33	}
34	if _, err := io.Copy(wf, rf); err != nil {
35		wf.Close()
36		return err
37	}
38	return wf.Close()
39}
40
41// CopyAll copies the file or (recursively) the directory at src to dst.
42// Permissions are preserved. dst must not already exist.
43func CopyAll(dst, src string) error {
44	return filepath.Walk(src, makeWalkFn(dst, src))
45}
46
47func makeWalkFn(dst, src string) filepath.WalkFunc {
48	return func(path string, info os.FileInfo, err error) error {
49		if err != nil {
50			return err
51		}
52		dstPath := filepath.Join(dst, strings.TrimPrefix(path, src))
53		if info.IsDir() {
54			return os.Mkdir(dstPath, info.Mode())
55		}
56		return CopyFile(dstPath, path)
57	}
58}
59