github.com/hashicorp/go-getter/v2@v2.2.2/get_file_copy.go (about) 1 package getter 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "os" 8 ) 9 10 // readerFunc is syntactic sugar for read interface. 11 type readerFunc func(p []byte) (n int, err error) 12 13 func (rf readerFunc) Read(p []byte) (n int, err error) { return rf(p) } 14 15 // Copy is a io.Copy cancellable by context 16 func Copy(ctx context.Context, dst io.Writer, src io.Reader) (int64, error) { 17 // Copy will call the Reader and Writer interface multiple time, in order 18 // to copy by chunk (avoiding loading the whole file in memory). 19 return io.Copy(dst, readerFunc(func(p []byte) (int, error) { 20 21 select { 22 case <-ctx.Done(): 23 // context has been canceled 24 // stop process and propagate "context canceled" error 25 return 0, ctx.Err() 26 default: 27 // otherwise just run default io.Reader implementation 28 return src.Read(p) 29 } 30 })) 31 } 32 33 // copyReader copies from an io.Reader into a file, using umask to create the dst file 34 func copyReader(dst string, src io.Reader, fmode, umask os.FileMode, fileSizeLimit int64) error { 35 dstF, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fmode) 36 if err != nil { 37 return err 38 } 39 defer dstF.Close() 40 41 if fileSizeLimit > 0 { 42 src = io.LimitReader(src, fileSizeLimit) 43 } 44 45 _, err = io.Copy(dstF, src) 46 if err != nil { 47 return err 48 } 49 50 // Explicitly chmod; the process umask is unconditionally applied otherwise. 51 // We'll mask the mode with our own umask, but that may be different than 52 // the process umask 53 return os.Chmod(dst, mode(fmode, umask)) 54 } 55 56 // copyFile copies a file in chunks from src path to dst path, using umask to create the dst file 57 func copyFile(ctx context.Context, dst, src string, disableSymlinks bool, fmode, umask os.FileMode) (int64, error) { 58 59 if disableSymlinks { 60 fileInfo, err := os.Lstat(src) 61 if err != nil { 62 return 0, fmt.Errorf("failed to check copy file source for symlinks: %w", err) 63 } 64 65 if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink { 66 return 0, ErrSymlinkCopy 67 } 68 } 69 70 srcF, err := os.Open(src) 71 if err != nil { 72 return 0, err 73 } 74 defer srcF.Close() 75 76 dstF, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, fmode) 77 if err != nil { 78 return 0, err 79 } 80 defer dstF.Close() 81 82 count, err := Copy(ctx, dstF, srcF) 83 if err != nil { 84 return 0, err 85 } 86 87 // Explicitly chmod; the process umask is unconditionally applied otherwise. 88 // We'll mask the mode with our own umask, but that may be different than 89 // the process umask 90 err = os.Chmod(dst, mode(fmode, umask)) 91 return count, err 92 }