github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/configs/configload/copy_dir.go (about)

     1  package configload
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  )
     9  
    10  // copyDir copies the src directory contents into dst. Both directories
    11  // should already exist.
    12  func copyDir(dst, src string) error {
    13  	src, err := filepath.EvalSymlinks(src)
    14  	if err != nil {
    15  		return err
    16  	}
    17  
    18  	walkFn := func(path string, info os.FileInfo, err error) error {
    19  		if err != nil {
    20  			return err
    21  		}
    22  
    23  		if path == src {
    24  			return nil
    25  		}
    26  
    27  		if strings.HasPrefix(filepath.Base(path), ".") {
    28  			// Skip any dot files
    29  			if info.IsDir() {
    30  				return filepath.SkipDir
    31  			} else {
    32  				return nil
    33  			}
    34  		}
    35  
    36  		// The "path" has the src prefixed to it. We need to join our
    37  		// destination with the path without the src on it.
    38  		dstPath := filepath.Join(dst, path[len(src):])
    39  
    40  		// we don't want to try and copy the same file over itself.
    41  		if eq, err := sameFile(path, dstPath); eq {
    42  			return nil
    43  		} else if err != nil {
    44  			return err
    45  		}
    46  
    47  		// If we have a directory, make that subdirectory, then continue
    48  		// the walk.
    49  		if info.IsDir() {
    50  			if path == filepath.Join(src, dst) {
    51  				// dst is in src; don't walk it.
    52  				return nil
    53  			}
    54  
    55  			if err := os.MkdirAll(dstPath, 0755); err != nil {
    56  				return err
    57  			}
    58  
    59  			return nil
    60  		}
    61  
    62  		// If we have a file, copy the contents.
    63  		srcF, err := os.Open(path)
    64  		if err != nil {
    65  			return err
    66  		}
    67  		defer srcF.Close()
    68  
    69  		dstF, err := os.Create(dstPath)
    70  		if err != nil {
    71  			return err
    72  		}
    73  		defer dstF.Close()
    74  
    75  		if _, err := io.Copy(dstF, srcF); err != nil {
    76  			return err
    77  		}
    78  
    79  		// Chmod it
    80  		return os.Chmod(dstPath, info.Mode())
    81  	}
    82  
    83  	return filepath.Walk(src, walkFn)
    84  }
    85  
    86  // sameFile tried to determine if to paths are the same file.
    87  // If the paths don't match, we lookup the inode on supported systems.
    88  func sameFile(a, b string) (bool, error) {
    89  	if a == b {
    90  		return true, nil
    91  	}
    92  
    93  	aIno, err := inode(a)
    94  	if err != nil {
    95  		if os.IsNotExist(err) {
    96  			return false, nil
    97  		}
    98  		return false, err
    99  	}
   100  
   101  	bIno, err := inode(b)
   102  	if err != nil {
   103  		if os.IsNotExist(err) {
   104  			return false, nil
   105  		}
   106  		return false, err
   107  	}
   108  
   109  	if aIno > 0 && aIno == bIno {
   110  		return true, nil
   111  	}
   112  
   113  	return false, nil
   114  }