]>
Commit | Line | Data |
---|---|---|
aa8901e9 ILT |
1 | // Copyright 2019 The Go Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file. | |
4 | ||
5 | package so_test | |
6 | ||
7 | import ( | |
8 | "io" | |
9 | "os" | |
10 | "path/filepath" | |
11 | "strings" | |
12 | ) | |
13 | ||
14 | // overlayDir makes a minimal-overhead copy of srcRoot in which new files may be added. | |
15 | // | |
16 | // TODO: Once we no longer need to support the misc module in GOPATH mode, | |
17 | // factor this function out into a package to reduce duplication. | |
18 | func overlayDir(dstRoot, srcRoot string) error { | |
19 | dstRoot = filepath.Clean(dstRoot) | |
20 | if err := os.MkdirAll(dstRoot, 0777); err != nil { | |
21 | return err | |
22 | } | |
23 | ||
5a8ea165 | 24 | srcRoot, err := filepath.Abs(srcRoot) |
aa8901e9 | 25 | if err != nil { |
5a8ea165 | 26 | return err |
aa8901e9 ILT |
27 | } |
28 | ||
29 | return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error { | |
30 | if err != nil || srcPath == srcRoot { | |
31 | return err | |
32 | } | |
33 | ||
34 | suffix := strings.TrimPrefix(srcPath, srcRoot) | |
35 | for len(suffix) > 0 && suffix[0] == filepath.Separator { | |
36 | suffix = suffix[1:] | |
37 | } | |
38 | dstPath := filepath.Join(dstRoot, suffix) | |
39 | ||
40 | perm := info.Mode() & os.ModePerm | |
41 | if info.Mode()&os.ModeSymlink != 0 { | |
42 | info, err = os.Stat(srcPath) | |
43 | if err != nil { | |
44 | return err | |
45 | } | |
46 | perm = info.Mode() & os.ModePerm | |
47 | } | |
48 | ||
49 | // Always copy directories (don't symlink them). | |
50 | // If we add a file in the overlay, we don't want to add it in the original. | |
51 | if info.IsDir() { | |
5a8ea165 | 52 | return os.MkdirAll(dstPath, perm|0200) |
aa8901e9 ILT |
53 | } |
54 | ||
55 | // If the OS supports symlinks, use them instead of copying bytes. | |
5a8ea165 | 56 | if err := os.Symlink(srcPath, dstPath); err == nil { |
aa8901e9 ILT |
57 | return nil |
58 | } | |
59 | ||
60 | // Otherwise, copy the bytes. | |
61 | src, err := os.Open(srcPath) | |
62 | if err != nil { | |
63 | return err | |
64 | } | |
65 | defer src.Close() | |
66 | ||
67 | dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm) | |
68 | if err != nil { | |
69 | return err | |
70 | } | |
71 | ||
72 | _, err = io.Copy(dst, src) | |
73 | if closeErr := dst.Close(); err == nil { | |
74 | err = closeErr | |
75 | } | |
76 | return err | |
77 | }) | |
78 | } |