github.com/sercand/please@v13.4.0+incompatible/src/fs/copy.go (about) 1 package fs 2 3 import ( 4 "os" 5 "path" 6 "runtime" 7 ) 8 9 // CopyOrLinkFile either copies or hardlinks a file based on the link argument. 10 // Falls back to a copy if link fails and fallback is true. 11 func CopyOrLinkFile(from, to string, mode os.FileMode, link, fallback bool) error { 12 if link { 13 if err := os.Link(from, to); err == nil || !fallback { 14 return err 15 } else if runtime.GOOS != "linux" && os.IsNotExist(err) { 16 // There is an awkward issue on several non-Linux platforms where links to 17 // symlinks actually try to link to the target rather than the link itself. 18 // In that case we try to recreate a similar symlink at the destination. 19 if info, err := os.Lstat(from); err == nil && (info.Mode()&os.ModeSymlink) != 0 { 20 dest, err := os.Readlink(from) 21 if err != nil { 22 return err 23 } 24 return os.Symlink(dest, to) 25 } 26 return err 27 } 28 } 29 return CopyFile(from, to, mode) 30 } 31 32 // RecursiveCopy copies either a single file or a directory. 33 func RecursiveCopy(from string, to string, mode os.FileMode) error { 34 return recursiveCopyOrLinkFile(from, to, mode, false, false) 35 } 36 37 // RecursiveLink hardlinks either a single file or a directory. 38 // Note that you can't hardlink directories so the behaviour is much the same as a recursive copy. 39 // If it can't link then it falls back to a copy. 40 func RecursiveLink(from string, to string, mode os.FileMode) error { 41 return recursiveCopyOrLinkFile(from, to, mode, true, true) 42 } 43 44 // recursiveCopyOrLinkFile recursively copies or links a file or directory. 45 // If 'link' is true then we'll hardlink files instead of copying them. 46 // If 'fallback' is true then we'll fall back to a copy if linking fails. 47 func recursiveCopyOrLinkFile(from string, to string, mode os.FileMode, link, fallback bool) error { 48 if info, err := os.Stat(from); err == nil && info.IsDir() { 49 return WalkMode(from, func(name string, isDir bool, fileMode os.FileMode) error { 50 dest := path.Join(to, name[len(from):]) 51 if isDir { 52 return os.MkdirAll(dest, DirPermissions) 53 } 54 return CopyOrLinkFile(name, dest, mode, link, fallback) 55 }) 56 } 57 return CopyOrLinkFile(from, to, mode, link, fallback) 58 }