kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/configs/configload/copy_dir.go (about)

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