-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrootfs.go
96 lines (89 loc) · 2.2 KB
/
rootfs.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
package main
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
// MakeRootFS creates a working directory where rootfs and manifest
// would reside. If overwrite is set, deletes a pre-existing directory
func MakeRootFS(files []string, args *Arguments) (err error) {
var (
srcDir string
dstDir string
fi os.FileInfo
cutLen int
)
// overwrite?
if args.Force {
os.RemoveAll(args.RootFS)
}
err = os.MkdirAll(args.RootFS, 0771)
if err != nil {
return err
}
// create manifest and rootfs dir:
manifest := filepath.Join(args.RootFS, "manifest")
rootfs := filepath.Join(args.RootFS, "rootfs")
tmps := strings.Replace(DefaultManifest, "%app-name%", args.AppName, 1)
mbytes := []byte(strings.Replace(tmps, "%app-description%", args.AppDesc, 1))
if args.Manifest != "" {
mbytes, err = ioutil.ReadFile(args.Manifest)
if err != nil {
return err
}
}
ioutil.WriteFile(manifest, mbytes, 0660)
os.Mkdir(rootfs, 0771)
// we need to place all found files into a target directory
// which isn't root. To do that, determine the common parent
// directory for them on this host, and "chroot" from there
// into args.Target
if args.Target != "" {
cutLen = len(CommonHome(files)) - 1
}
// populate rootfs:
for _, p := range files {
// create a similar directory under rootfs, with same access flags:
srcDir = filepath.Dir(p)
dstDir = filepath.Join(rootfs, args.Target, srcDir[cutLen:])
fi, err = os.Stat(srcDir)
if err != nil {
return err
}
os.MkdirAll(dstDir, fi.Mode())
// try to create a hard link first (much faster):
dest := filepath.Join(dstDir, filepath.Base(p))
err = os.Link(p, dest)
if err != nil {
// fall back to copying a file:
if err = CopyFile(p, dest); err != nil {
return err
}
}
}
return nil
}
// CopyFile makes a copy of a file preserving its access flags
func CopyFile(src, dst string) (err error) {
in, err := os.Open(src)
if err != nil {
return err
}
fi, err := in.Stat()
if err != nil {
return err
}
defer in.Close()
out, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE, fi.Mode())
if err != nil {
return err
}
defer out.Close()
if _, err := io.Copy(out, in); err != nil {
return err
}
err = out.Sync()
return nil
}