cuelang.org/go@v0.10.1/internal/copy/copy.go (about) 1 // Copyright 2019 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package copy provides utilities to copy files and directories. 16 package copy 17 18 import ( 19 "fmt" 20 "io" 21 "os" 22 "path/filepath" 23 ) 24 25 // File creates dst and copies the contents src to it. 26 func File(src, dst string) error { 27 src = filepath.Clean(src) 28 dst = filepath.Clean(dst) 29 30 stat, err := os.Stat(src) 31 if err != nil { 32 return fmt.Errorf("copy file: %v", err) 33 } 34 err = copyFile(stat, src, dst) 35 if err != nil { 36 return fmt.Errorf("copy file: %v", err) 37 } 38 return nil 39 } 40 41 // Dir copies a src directory to its destination. 42 func Dir(src, dst string) error { 43 src = filepath.Clean(src) 44 dst = filepath.Clean(dst) 45 46 stat, err := os.Stat(src) 47 if err != nil { 48 return fmt.Errorf("copy failed: %v", err) 49 } else if !stat.IsDir() { 50 return fmt.Errorf("copy failed: source is not a directory") 51 } 52 53 err = copyDir(stat, src, dst) 54 if err != nil { 55 return fmt.Errorf("copy failed: %v", err) 56 } 57 return nil 58 } 59 60 func copyDir(info os.FileInfo, src, dst string) error { 61 if _, err := os.Stat(dst); err != nil { 62 if !os.IsNotExist(err) { 63 return fmt.Errorf("dest err %s: %v", dst, err) 64 } 65 if err := os.MkdirAll(dst, info.Mode()); err != nil { 66 return fmt.Errorf("making dest %s: %v", dst, err) 67 } 68 } 69 70 entries, err := os.ReadDir(src) 71 if err != nil { 72 return fmt.Errorf("reading dir %s: %v", src, err) 73 } 74 75 for _, e := range entries { 76 srcPath := filepath.Join(src, e.Name()) 77 dstPath := filepath.Join(dst, e.Name()) 78 79 info, err := e.Info() 80 if err != nil { 81 return err 82 } 83 switch e.Type() { 84 case os.ModeSymlink: 85 err = copySymLink(info, srcPath, dstPath) 86 case os.ModeDir: 87 err = copyDir(info, srcPath, dstPath) 88 default: 89 err = copyFile(info, srcPath, dstPath) 90 } 91 if err != nil { 92 return err 93 } 94 } 95 return nil 96 } 97 98 func copySymLink(info os.FileInfo, src, dst string) error { 99 mode := info.Mode() 100 link, err := os.Readlink(src) 101 if err != nil { 102 return err 103 } 104 err = os.Symlink(link, dst) 105 if err != nil { 106 return err 107 } 108 return os.Chmod(dst, mode) 109 } 110 111 func copyFile(info os.FileInfo, src, dst string) (err error) { 112 in, err := os.Open(src) 113 if err != nil { 114 return fmt.Errorf("error reading %s: %v", src, err) 115 } 116 defer in.Close() 117 118 out, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, info.Mode()) 119 if err != nil { 120 return fmt.Errorf("error creating %s: %v", dst, err) 121 } 122 defer func() { 123 cErr := out.Close() 124 if err == nil { 125 err = cErr 126 } 127 }() 128 129 _, err = io.Copy(out, in) 130 if err != nil { 131 return fmt.Errorf("error copying %s: %v", dst, err) 132 } 133 return err 134 }