~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/utils/fs/copy.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2014 Canonical Ltd.
 
2
// Licensed under the LGPLv3, see LICENCE file for details.
 
3
 
 
4
package fs
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "io"
 
9
        "os"
 
10
        "path/filepath"
 
11
)
 
12
 
 
13
// Copy recursively copies the file, directory or symbolic link at src
 
14
// to dst. The destination must not exist. Symbolic links are not
 
15
// followed.
 
16
//
 
17
// If the copy fails half way through, the destination might be left
 
18
// partially written.
 
19
func Copy(src, dst string) error {
 
20
        srcInfo, srcErr := os.Lstat(src)
 
21
        if srcErr != nil {
 
22
                return srcErr
 
23
        }
 
24
        _, dstErr := os.Lstat(dst)
 
25
        if dstErr == nil {
 
26
                // TODO(rog) add a flag to permit overwriting?
 
27
                return fmt.Errorf("will not overwrite %q", dst)
 
28
        }
 
29
        if !os.IsNotExist(dstErr) {
 
30
                return dstErr
 
31
        }
 
32
        switch mode := srcInfo.Mode(); mode & os.ModeType {
 
33
        case os.ModeSymlink:
 
34
                return copySymLink(src, dst)
 
35
        case os.ModeDir:
 
36
                return copyDir(src, dst, mode)
 
37
        case 0:
 
38
                return copyFile(src, dst, mode)
 
39
        default:
 
40
                return fmt.Errorf("cannot copy file with mode %v", mode)
 
41
        }
 
42
}
 
43
 
 
44
func copySymLink(src, dst string) error {
 
45
        target, err := os.Readlink(src)
 
46
        if err != nil {
 
47
                return err
 
48
        }
 
49
        return os.Symlink(target, dst)
 
50
}
 
51
 
 
52
func copyFile(src, dst string, mode os.FileMode) error {
 
53
        srcf, err := os.Open(src)
 
54
        if err != nil {
 
55
                return err
 
56
        }
 
57
        defer srcf.Close()
 
58
        dstf, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, mode.Perm())
 
59
        if err != nil {
 
60
                return err
 
61
        }
 
62
        defer dstf.Close()
 
63
        // Make the actual permissions match the source permissions
 
64
        // even in the presence of umask.
 
65
        if err := os.Chmod(dstf.Name(), mode.Perm()); err != nil {
 
66
                return err
 
67
        }
 
68
        if _, err := io.Copy(dstf, srcf); err != nil {
 
69
                return fmt.Errorf("cannot copy %q to %q: %v", src, dst, err)
 
70
        }
 
71
        return nil
 
72
}
 
73
 
 
74
func copyDir(src, dst string, mode os.FileMode) error {
 
75
        srcf, err := os.Open(src)
 
76
        if err != nil {
 
77
                return err
 
78
        }
 
79
        defer srcf.Close()
 
80
        if mode&0500 == 0 {
 
81
                // The source directory doesn't have write permission,
 
82
                // so give the new directory write permission anyway
 
83
                // so that we have permission to create its contents.
 
84
                // We'll make the permissions match at the end.
 
85
                mode |= 0500
 
86
        }
 
87
        if err := os.Mkdir(dst, mode.Perm()); err != nil {
 
88
                return err
 
89
        }
 
90
        for {
 
91
                names, err := srcf.Readdirnames(100)
 
92
                for _, name := range names {
 
93
                        if err := Copy(filepath.Join(src, name), filepath.Join(dst, name)); err != nil {
 
94
                                return err
 
95
                        }
 
96
                }
 
97
                if err == io.EOF {
 
98
                        break
 
99
                }
 
100
                if err != nil {
 
101
                        return fmt.Errorf("error reading directory %q: %v", src, err)
 
102
                }
 
103
        }
 
104
        if err := os.Chmod(dst, mode.Perm()); err != nil {
 
105
                return err
 
106
        }
 
107
        return nil
 
108
}