github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/container/externalbuilder/copy.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package externalbuilder 8 9 import ( 10 "io" 11 "os" 12 "path/filepath" 13 "strings" 14 15 "github.com/hechain20/hechain/common/flogging" 16 "github.com/pkg/errors" 17 ) 18 19 // CopyDir creates a copy of a dir 20 func CopyDir(logger *flogging.FabricLogger, srcroot, destroot string) error { 21 err := filepath.Walk(srcroot, func(path string, info os.FileInfo, err error) error { 22 if err != nil { 23 return err 24 } 25 26 srcsubpath, err := filepath.Rel(srcroot, path) 27 if err != nil { 28 return err 29 } 30 destpath := filepath.Join(destroot, srcsubpath) 31 32 switch { 33 case info.IsDir(): 34 return os.MkdirAll(destpath, info.Mode()) 35 case info.Mode()&os.ModeSymlink == os.ModeSymlink: 36 // filepath.Walk does not follow symbolic links; we need to copy 37 // symbolic links as-is because some chaincode types (Node.js) rely 38 // on the use of symbolic links. 39 return copySymlink(srcroot, path, destpath) 40 case info.Mode().IsRegular(): 41 // Intermediate directories are ensured to exist because parent 42 // node is always visited before children in `filepath.Walk`. 43 return copyFile(path, destpath) 44 default: 45 // It's something else that we don't support copying (device, socket, etc) 46 return errors.Errorf("refusing to copy unsupported file %s with mode %o", path, info.Mode()) 47 } 48 }) 49 // If an error occurred, clean up any created files. 50 if err != nil { 51 if err := os.RemoveAll(destroot); err != nil { 52 logger.Errorf("failed to remove destination directory %s after copy error: %s", destroot, err) 53 } 54 return errors.WithMessagef(err, "failed to copy %s to %s", srcroot, destroot) 55 } 56 return nil 57 } 58 59 func copySymlink(srcroot, srcpath, destpath string) error { 60 // If the symlink is absolute, then we do not want to copy it. 61 symlinkDest, err := os.Readlink(srcpath) 62 if err != nil { 63 return err 64 } 65 if filepath.IsAbs(symlinkDest) { 66 return errors.Errorf("refusing to copy absolute symlink %s -> %s", srcpath, symlinkDest) 67 } 68 69 // Determine where the symlink points to. If it points outside 70 // of the source root, then we do not want to copy it. 71 symlinkDir := filepath.Dir(srcpath) 72 symlinkTarget := filepath.Clean(filepath.Join(symlinkDir, symlinkDest)) 73 relativeTarget, err := filepath.Rel(srcroot, symlinkTarget) 74 if err != nil { 75 return err 76 } 77 if relativeTargetElements := strings.Split(relativeTarget, string(os.PathSeparator)); len(relativeTargetElements) >= 1 && relativeTargetElements[0] == ".." { 78 return errors.Errorf("refusing to copy symlink %s -> %s pointing outside of source root", srcpath, symlinkDest) 79 } 80 81 return os.Symlink(symlinkDest, destpath) 82 } 83 84 func copyFile(srcpath, destpath string) error { 85 srcFile, err := os.Open(srcpath) 86 if err != nil { 87 return err 88 } 89 defer srcFile.Close() 90 91 info, err := srcFile.Stat() 92 if err != nil { 93 return err 94 } 95 96 destFile, err := os.Create(destpath) 97 if err != nil { 98 return err 99 } 100 defer destFile.Close() 101 102 if err = os.Chmod(destFile.Name(), info.Mode()); err != nil { 103 return err 104 } 105 106 if _, err = io.Copy(destFile, srcFile); err != nil { 107 return err 108 } 109 110 return nil 111 }