Source file src/cmd/cgo/internal/cgotest/overlaydir.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 cgotest
     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  func OverlayDir(dstRoot, srcRoot string) error {
    16  	dstRoot = filepath.Clean(dstRoot)
    17  	if err := os.MkdirAll(dstRoot, 0777); err != nil {
    18  		return err
    19  	}
    20  
    21  	srcRoot, err := filepath.Abs(srcRoot)
    22  	if err != nil {
    23  		return err
    24  	}
    25  
    26  	return filepath.Walk(srcRoot, func(srcPath string, info os.FileInfo, err error) error {
    27  		if err != nil || srcPath == srcRoot {
    28  			return err
    29  		}
    30  
    31  		suffix := strings.TrimPrefix(srcPath, srcRoot)
    32  		for len(suffix) > 0 && suffix[0] == filepath.Separator {
    33  			suffix = suffix[1:]
    34  		}
    35  		dstPath := filepath.Join(dstRoot, suffix)
    36  
    37  		perm := info.Mode() & os.ModePerm
    38  		if info.Mode()&os.ModeSymlink != 0 {
    39  			info, err = os.Stat(srcPath)
    40  			if err != nil {
    41  				return err
    42  			}
    43  			perm = info.Mode() & os.ModePerm
    44  		}
    45  
    46  		// Always copy directories (don't symlink them).
    47  		// If we add a file in the overlay, we don't want to add it in the original.
    48  		if info.IsDir() {
    49  			return os.MkdirAll(dstPath, perm|0200)
    50  		}
    51  
    52  		// If the OS supports symlinks, use them instead of copying bytes.
    53  		if err := os.Symlink(srcPath, dstPath); err == nil {
    54  			return nil
    55  		}
    56  
    57  		// Otherwise, copy the bytes.
    58  		src, err := os.Open(srcPath)
    59  		if err != nil {
    60  			return err
    61  		}
    62  		defer src.Close()
    63  
    64  		dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, perm)
    65  		if err != nil {
    66  			return err
    67  		}
    68  
    69  		_, err = io.Copy(dst, src)
    70  		if closeErr := dst.Close(); err == nil {
    71  			err = closeErr
    72  		}
    73  		return err
    74  	})
    75  }
    76  

View as plain text