]> Cypherpunks.ru repositories - gostls13.git/blob - misc/cgo/testcarchive/overlaydir_test.go
67974c5ed8da09851a648f8a60fb59fdfc126d30
[gostls13.git] / misc / cgo / testcarchive / overlaydir_test.go
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 carchive_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
24         srcRoot, err := filepath.Abs(srcRoot)
25         if err != nil {
26                 return err
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() {
52                         return os.MkdirAll(dstPath, perm|0200)
53                 }
54
55                 // If the OS supports symlinks, use them instead of copying bytes.
56                 if err := os.Symlink(srcPath, dstPath); err == nil {
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 }