-
Notifications
You must be signed in to change notification settings - Fork 0
/
copy.go
97 lines (81 loc) · 1.82 KB
/
copy.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package kit
import (
"io"
"os"
"path/filepath"
)
// CopyDir xxx
func CopyDir(src, dest string) error {
info, err := os.Lstat(src)
if err != nil {
return err
}
return copy(src, dest, info)
}
// copy dispatches copy-funcs according to the mode.
// Because this "copy" could be called recursively,
// "info" MUST be given here, NOT nil.
func copy(src, dest string, info os.FileInfo) error {
if info.IsDir() {
return dcopy(src, dest)
}
return fcopy(src, dest, info)
}
// fcopy is for just a file,
// with considering existence of parent directory
// and file permission.
func fcopy(src, dest string, info os.FileInfo) error {
err := os.MkdirAll(filepath.Dir(dest), os.ModePerm)
if err != nil {
return err
}
f, err := os.Create(dest)
if err != nil {
return err
}
defer fclose(f, &err)
s, err := os.Open(src)
if err != nil {
return err
}
defer fclose(s, &err)
_, err = io.Copy(f, s)
if err != nil {
return err
}
return f.Sync() // needed?
}
// dcopy is for a directory,
// with scanning contents inside the directory
// and pass everything to "copy" recursively.
func dcopy(srcdir, destdir string) (err error) {
if err = os.MkdirAll(destdir, os.FileMode(0755)); err != nil {
return
}
entries, err := os.ReadDir(srcdir)
if err != nil {
return
}
for _, entry := range entries {
einfo, err2 := entry.Info()
if err2 != nil {
LogWarn("dcopy", "err", err2)
continue
}
name := einfo.Name()
cs, cd := filepath.Join(srcdir, name), filepath.Join(destdir, name)
if err = copy(cs, cd, einfo); err != nil {
// If any error, exit immediately
return
}
}
return
}
// fclose ANYHOW closes file,
// with asiging error raised during Close,
// BUT respecting the error already reported.
func fclose(f *os.File, reported *error) {
if err := f.Close(); *reported == nil {
*reported = err
}
}