cuelang.org/go@v0.10.1/internal/vcs/copyfs_test.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package vcs 6 7 import ( 8 "io" 9 "io/fs" 10 "os" 11 "path/filepath" 12 ) 13 14 // copyFS is copied from Go tip as of 315b6ae682a2a4e7718924a45b8b311a0fe10043. 15 // It's slightly adapted to avoid localizing names, 16 // because that relies on Go internal functions and we don't need 17 // to be that careful for this use case. 18 // TODO use [os.CopyFS] when we can. 19 20 // copyFS copies the file system fsys into the directory dir, 21 // creating dir if necessary. 22 // 23 // Newly created directories and files have their default modes 24 // where any bits from the file in fsys that are not part of the 25 // standard read, write, and execute permissions will be zeroed 26 // out, and standard read and write permissions are set for owner, 27 // group, and others while retaining any existing execute bits from 28 // the file in fsys. 29 // 30 // Symbolic links in fsys are not supported, a *PathError with Err set 31 // to ErrInvalid is returned on symlink. 32 // 33 // Copying stops at and returns the first error encountered. 34 func copyFS(dir string, fsys fs.FS) error { 35 return fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { 36 if err != nil { 37 return err 38 } 39 40 // The original version calls safefilepath.Localize here 41 // but we don't have access to that and the context is 42 // limited enough that it shouldn't matter. 43 newPath := filepath.Join(dir, path) 44 if d.IsDir() { 45 return os.MkdirAll(newPath, 0777) 46 } 47 48 // TODO(panjf2000): handle symlinks with the help of fs.ReadLinkFS 49 // once https://go.dev/issue/49580 is done. 50 // we also need safefilepath.IsLocal from https://go.dev/cl/564295. 51 if !d.Type().IsRegular() { 52 return &os.PathError{Op: "CopyFS", Path: path, Err: os.ErrInvalid} 53 } 54 55 r, err := fsys.Open(path) 56 if err != nil { 57 return err 58 } 59 defer r.Close() 60 info, err := r.Stat() 61 if err != nil { 62 return err 63 } 64 w, err := os.OpenFile(newPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666|info.Mode()&0777) 65 if err != nil { 66 return err 67 } 68 69 if _, err := io.Copy(w, r); err != nil { 70 w.Close() 71 return &os.PathError{Op: "Copy", Path: newPath, Err: err} 72 } 73 return w.Close() 74 }) 75 }