Ian Lance Taylor | 8f2b844 | 2019-08-23 15:38:02 -0700 | [diff] [blame] | 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 stdio_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 | |
Ian Lance Taylor | c2225a7 | 2020-01-02 15:05:27 -0800 | [diff] [blame] | 24 | srcRoot, err := filepath.Abs(srcRoot) |
Ian Lance Taylor | 8f2b844 | 2019-08-23 15:38:02 -0700 | [diff] [blame] | 25 | if err != nil { |
Ian Lance Taylor | c2225a7 | 2020-01-02 15:05:27 -0800 | [diff] [blame] | 26 | return err |
Ian Lance Taylor | 8f2b844 | 2019-08-23 15:38:02 -0700 | [diff] [blame] | 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() { |
Ian Lance Taylor | c2225a7 | 2020-01-02 15:05:27 -0800 | [diff] [blame] | 52 | return os.MkdirAll(dstPath, perm|0200) |
Ian Lance Taylor | 8f2b844 | 2019-08-23 15:38:02 -0700 | [diff] [blame] | 53 | } |
| 54 | |
| 55 | // If the OS supports symlinks, use them instead of copying bytes. |
Ian Lance Taylor | c2225a7 | 2020-01-02 15:05:27 -0800 | [diff] [blame] | 56 | if err := os.Symlink(srcPath, dstPath); err == nil { |
Ian Lance Taylor | 8f2b844 | 2019-08-23 15:38:02 -0700 | [diff] [blame] | 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 | } |