github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/copy/copy_dir.go (about) 1 package copy 2 3 import ( 4 "io" 5 "os" 6 "path/filepath" 7 "strings" 8 ) 9 10 // CopyDir recursively copies all of the files within the directory given in 11 // src to the directory given in dst. 12 // 13 // Both directories should already exist. If the destination directory is 14 // non-empty then the new files will merge in with the old, overwriting any 15 // files that have a relative path in common between source and destination. 16 // 17 // Recursive copying of directories is inevitably a rather opinionated sort of 18 // operation, so this function won't be appropriate for all use-cases. Some 19 // of the "opinions" it has are described in the following paragraphs: 20 // 21 // Symlinks in the source directory are recreated with the same target in the 22 // destination directory. If the symlink is to a directory itself, that 23 // directory is not recursively visited for further copying. 24 // 25 // File and directory modes are not preserved exactly, but the executable 26 // flag is preserved for files on operating systems where it is significant. 27 // 28 // Any "dot files" it encounters along the way are skipped, even on platforms 29 // that do not normally ascribe special meaning to files with names starting 30 // with dots. 31 // 32 // Callers may rely on the above details and other undocumented details of 33 // this function, so if you intend to change it be sure to review the callers 34 // first and make sure they are compatible with the change you intend to make. 35 func CopyDir(dst, src string) error { 36 src, err := filepath.EvalSymlinks(src) 37 if err != nil { 38 return err 39 } 40 41 walkFn := func(path string, info os.FileInfo, err error) error { 42 if err != nil { 43 return err 44 } 45 46 if path == src { 47 return nil 48 } 49 50 if strings.HasPrefix(filepath.Base(path), ".") { 51 // Skip any dot files 52 if info.IsDir() { 53 return filepath.SkipDir 54 } else { 55 return nil 56 } 57 } 58 59 // The "path" has the src prefixed to it. We need to join our 60 // destination with the path without the src on it. 61 dstPath := filepath.Join(dst, path[len(src):]) 62 63 // we don't want to try and copy the same file over itself. 64 if eq, err := SameFile(path, dstPath); eq { 65 return nil 66 } else if err != nil { 67 return err 68 } 69 70 // If we have a directory, make that subdirectory, then continue 71 // the walk. 72 if info.IsDir() { 73 if path == filepath.Join(src, dst) { 74 // dst is in src; don't walk it. 75 return nil 76 } 77 78 if err := os.MkdirAll(dstPath, 0755); err != nil { 79 return err 80 } 81 82 return nil 83 } 84 85 // If the current path is a symlink, recreate the symlink relative to 86 // the dst directory 87 if info.Mode()&os.ModeSymlink == os.ModeSymlink { 88 target, err := os.Readlink(path) 89 if err != nil { 90 return err 91 } 92 93 return os.Symlink(target, dstPath) 94 } 95 96 // If we have a file, copy the contents. 97 srcF, err := os.Open(path) 98 if err != nil { 99 return err 100 } 101 defer srcF.Close() 102 103 dstF, err := os.Create(dstPath) 104 if err != nil { 105 return err 106 } 107 defer dstF.Close() 108 109 if _, err := io.Copy(dstF, srcF); err != nil { 110 return err 111 } 112 113 // Chmod it 114 return os.Chmod(dstPath, info.Mode()) 115 } 116 117 return filepath.Walk(src, walkFn) 118 } 119 120 // SameFile returns true if the two given paths refer to the same physical 121 // file on disk, using the unique file identifiers from the underlying 122 // operating system. For example, on Unix systems this checks whether the 123 // two files are on the same device and have the same inode. 124 func SameFile(a, b string) (bool, error) { 125 if a == b { 126 return true, nil 127 } 128 129 aInfo, err := os.Lstat(a) 130 if err != nil { 131 if os.IsNotExist(err) { 132 return false, nil 133 } 134 return false, err 135 } 136 137 bInfo, err := os.Lstat(b) 138 if err != nil { 139 if os.IsNotExist(err) { 140 return false, nil 141 } 142 return false, err 143 } 144 145 return os.SameFile(aInfo, bInfo), nil 146 }