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  }