summaryrefslogtreecommitdiff
path: root/vendor/github.com/mrunalp/fileutils/fileutils.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mrunalp/fileutils/fileutils.go')
-rw-r--r--vendor/github.com/mrunalp/fileutils/fileutils.go161
1 files changed, 161 insertions, 0 deletions
diff --git a/vendor/github.com/mrunalp/fileutils/fileutils.go b/vendor/github.com/mrunalp/fileutils/fileutils.go
new file mode 100644
index 000000000..b60cb909c
--- /dev/null
+++ b/vendor/github.com/mrunalp/fileutils/fileutils.go
@@ -0,0 +1,161 @@
+package fileutils
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "syscall"
+)
+
+// CopyFile copies the file at source to dest
+func CopyFile(source string, dest string) error {
+ si, err := os.Lstat(source)
+ if err != nil {
+ return err
+ }
+
+ st, ok := si.Sys().(*syscall.Stat_t)
+ if !ok {
+ return fmt.Errorf("could not convert to syscall.Stat_t")
+ }
+
+ uid := int(st.Uid)
+ gid := int(st.Gid)
+
+ // Handle symlinks
+ if si.Mode()&os.ModeSymlink != 0 {
+ target, err := os.Readlink(source)
+ if err != nil {
+ return err
+ }
+ if err := os.Symlink(target, dest); err != nil {
+ return err
+ }
+ }
+
+ // Handle device files
+ if st.Mode&syscall.S_IFMT == syscall.S_IFBLK || st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
+ devMajor := int64(major(uint64(st.Rdev)))
+ devMinor := int64(minor(uint64(st.Rdev)))
+ mode := uint32(si.Mode() & 07777)
+ if st.Mode&syscall.S_IFMT == syscall.S_IFBLK {
+ mode |= syscall.S_IFBLK
+ }
+ if st.Mode&syscall.S_IFMT == syscall.S_IFCHR {
+ mode |= syscall.S_IFCHR
+ }
+ if err := syscall.Mknod(dest, mode, int(mkdev(devMajor, devMinor))); err != nil {
+ return err
+ }
+ }
+
+ // Handle regular files
+ if si.Mode().IsRegular() {
+ sf, err := os.Open(source)
+ if err != nil {
+ return err
+ }
+ defer sf.Close()
+
+ df, err := os.Create(dest)
+ if err != nil {
+ return err
+ }
+ defer df.Close()
+
+ _, err = io.Copy(df, sf)
+ if err != nil {
+ return err
+ }
+ }
+
+ // Chown the file
+ if err := os.Lchown(dest, uid, gid); err != nil {
+ return err
+ }
+
+ // Chmod the file
+ if !(si.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ if err := os.Chmod(dest, si.Mode()); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// CopyDirectory copies the files under the source directory
+// to dest directory. The dest directory is created if it
+// does not exist.
+func CopyDirectory(source string, dest string) error {
+ fi, err := os.Stat(source)
+ if err != nil {
+ return err
+ }
+
+ // Get owner.
+ st, ok := fi.Sys().(*syscall.Stat_t)
+ if !ok {
+ return fmt.Errorf("could not convert to syscall.Stat_t")
+ }
+
+ // We have to pick an owner here anyway.
+ if err := MkdirAllNewAs(dest, fi.Mode(), int(st.Uid), int(st.Gid)); err != nil {
+ return err
+ }
+
+ return filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ // Get the relative path
+ relPath, err := filepath.Rel(source, path)
+ if err != nil {
+ return nil
+ }
+
+ if info.IsDir() {
+ // Skip the source directory.
+ if path != source {
+ // Get the owner.
+ st, ok := info.Sys().(*syscall.Stat_t)
+ if !ok {
+ return fmt.Errorf("could not convert to syscall.Stat_t")
+ }
+
+ uid := int(st.Uid)
+ gid := int(st.Gid)
+
+ if err := os.Mkdir(filepath.Join(dest, relPath), info.Mode()); err != nil {
+ return err
+ }
+
+ if err := os.Lchown(filepath.Join(dest, relPath), uid, gid); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+
+ // Copy the file.
+ if err := CopyFile(path, filepath.Join(dest, relPath)); err != nil {
+ return err
+ }
+
+ return nil
+ })
+}
+
+func major(device uint64) uint64 {
+ return (device >> 8) & 0xfff
+}
+
+func minor(device uint64) uint64 {
+ return (device & 0xff) | ((device >> 12) & 0xfff00)
+}
+
+func mkdev(major int64, minor int64) uint32 {
+ return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
+}