copy.go
· 3.0 KiB · Go
Surowy
/* MIT License
*
* Copyright (c) 2017 Roland Singer [[email protected]]
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// CopyFile copies the contents of the file named src to the file named
// by dst. The file will be created if it does not already exist. If the
// destination file exists, all it's contents will be replaced by the contents
// of the source file. The file mode will be copied from the source and
// the copied data is synced/flushed to stable storage.
func CopyFile(src, dst string) (err error) {
in, err := os.Open(src)
if err != nil {
return
}
defer in.Close()
out, err := os.Create(dst)
if err != nil {
return
}
defer func() {
if e := out.Close(); e != nil {
err = e
}
}()
_, err = io.Copy(out, in)
if err != nil {
return
}
err = out.Sync()
if err != nil {
return
}
si, err := os.Stat(src)
if err != nil {
return
}
err = os.Chmod(dst, si.Mode())
if err != nil {
return
}
return
}
// CopyDir recursively copies a directory tree, attempting to preserve permissions.
// Source directory must exist, destination directory must *not* exist.
// Symlinks are ignored and skipped.
func CopyDir(src string, dst string) (err error) {
src = filepath.Clean(src)
dst = filepath.Clean(dst)
si, err := os.Stat(src)
if err != nil {
return err
}
if !si.IsDir() {
return fmt.Errorf("source is not a directory")
}
_, err = os.Stat(dst)
if err != nil && !os.IsNotExist(err) {
return
}
if err == nil {
return fmt.Errorf("destination already exists")
}
err = os.MkdirAll(dst, si.Mode())
if err != nil {
return
}
entries, err := ioutil.ReadDir(src)
if err != nil {
return
}
for _, entry := range entries {
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())
if entry.IsDir() {
err = CopyDir(srcPath, dstPath)
if err != nil {
return
}
} else {
// Skip symlinks.
if entry.Mode()&os.ModeSymlink != 0 {
continue
}
err = CopyFile(srcPath, dstPath)
if err != nil {
return
}
}
}
return
}
| 1 | /* MIT License |
| 2 | * |
| 3 | * Copyright (c) 2017 Roland Singer [[email protected]] |
| 4 | * |
| 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 6 | * of this software and associated documentation files (the "Software"), to deal |
| 7 | * in the Software without restriction, including without limitation the rights |
| 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 9 | * copies of the Software, and to permit persons to whom the Software is |
| 10 | * furnished to do so, subject to the following conditions: |
| 11 | * |
| 12 | * The above copyright notice and this permission notice shall be included in all |
| 13 | * copies or substantial portions of the Software. |
| 14 | * |
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 21 | * SOFTWARE. |
| 22 | */ |
| 23 | |
| 24 | // CopyFile copies the contents of the file named src to the file named |
| 25 | // by dst. The file will be created if it does not already exist. If the |
| 26 | // destination file exists, all it's contents will be replaced by the contents |
| 27 | // of the source file. The file mode will be copied from the source and |
| 28 | // the copied data is synced/flushed to stable storage. |
| 29 | func CopyFile(src, dst string) (err error) { |
| 30 | in, err := os.Open(src) |
| 31 | if err != nil { |
| 32 | return |
| 33 | } |
| 34 | defer in.Close() |
| 35 | |
| 36 | out, err := os.Create(dst) |
| 37 | if err != nil { |
| 38 | return |
| 39 | } |
| 40 | defer func() { |
| 41 | if e := out.Close(); e != nil { |
| 42 | err = e |
| 43 | } |
| 44 | }() |
| 45 | |
| 46 | _, err = io.Copy(out, in) |
| 47 | if err != nil { |
| 48 | return |
| 49 | } |
| 50 | |
| 51 | err = out.Sync() |
| 52 | if err != nil { |
| 53 | return |
| 54 | } |
| 55 | |
| 56 | si, err := os.Stat(src) |
| 57 | if err != nil { |
| 58 | return |
| 59 | } |
| 60 | err = os.Chmod(dst, si.Mode()) |
| 61 | if err != nil { |
| 62 | return |
| 63 | } |
| 64 | |
| 65 | return |
| 66 | } |
| 67 | |
| 68 | // CopyDir recursively copies a directory tree, attempting to preserve permissions. |
| 69 | // Source directory must exist, destination directory must *not* exist. |
| 70 | // Symlinks are ignored and skipped. |
| 71 | func CopyDir(src string, dst string) (err error) { |
| 72 | src = filepath.Clean(src) |
| 73 | dst = filepath.Clean(dst) |
| 74 | |
| 75 | si, err := os.Stat(src) |
| 76 | if err != nil { |
| 77 | return err |
| 78 | } |
| 79 | if !si.IsDir() { |
| 80 | return fmt.Errorf("source is not a directory") |
| 81 | } |
| 82 | |
| 83 | _, err = os.Stat(dst) |
| 84 | if err != nil && !os.IsNotExist(err) { |
| 85 | return |
| 86 | } |
| 87 | if err == nil { |
| 88 | return fmt.Errorf("destination already exists") |
| 89 | } |
| 90 | |
| 91 | err = os.MkdirAll(dst, si.Mode()) |
| 92 | if err != nil { |
| 93 | return |
| 94 | } |
| 95 | |
| 96 | entries, err := ioutil.ReadDir(src) |
| 97 | if err != nil { |
| 98 | return |
| 99 | } |
| 100 | |
| 101 | for _, entry := range entries { |
| 102 | srcPath := filepath.Join(src, entry.Name()) |
| 103 | dstPath := filepath.Join(dst, entry.Name()) |
| 104 | |
| 105 | if entry.IsDir() { |
| 106 | err = CopyDir(srcPath, dstPath) |
| 107 | if err != nil { |
| 108 | return |
| 109 | } |
| 110 | } else { |
| 111 | // Skip symlinks. |
| 112 | if entry.Mode()&os.ModeSymlink != 0 { |
| 113 | continue |
| 114 | } |
| 115 | |
| 116 | err = CopyFile(srcPath, dstPath) |
| 117 | if err != nil { |
| 118 | return |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | return |
| 124 | } |
| 125 |