diff --git a/fs/copy.go b/fs/copy.go index 0ffd7f223..a1fe73539 100644 --- a/fs/copy.go +++ b/fs/copy.go @@ -24,10 +24,12 @@ func copyDirectory(dst, src string, inodes map[uint64]string) error { return errors.Errorf("source is not directory") } - if _, err := os.Stat(dst); err != nil { + if st, err := os.Stat(dst); err != nil { if err := os.Mkdir(dst, stat.Mode()); err != nil { return errors.Wrapf(err, "failed to mkdir %s", dst) } + } else if !st.IsDir() { + return errors.Errorf("cannot copy to non-directory: %s", dst) } else { if err := os.Chmod(dst, stat.Mode()); err != nil { return errors.Wrapf(err, "failed to chmod on %s", dst) @@ -46,12 +48,14 @@ func copyDirectory(dst, src string, inodes map[uint64]string) error { for _, fi := range fis { source := filepath.Join(src, fi.Name()) target := filepath.Join(dst, fi.Name()) - if fi.IsDir() { + + switch { + case fi.IsDir(): if err := copyDirectory(target, source, inodes); err != nil { return err } continue - } else if (fi.Mode() & os.ModeType) == 0 { + case (fi.Mode() & os.ModeType) == 0: link, err := GetLinkSource(target, fi, inodes) if err != nil { return errors.Wrap(err, "failed to get hardlink") @@ -63,7 +67,7 @@ func copyDirectory(dst, src string, inodes map[uint64]string) error { } else if err := copyFile(source, target); err != nil { return errors.Wrap(err, "failed to copy files") } - } else if (fi.Mode() & os.ModeSymlink) == os.ModeSymlink { + case (fi.Mode() & os.ModeSymlink) == os.ModeSymlink: link, err := os.Readlink(source) if err != nil { return errors.Wrapf(err, "failed to read link: %s", source) @@ -71,10 +75,11 @@ func copyDirectory(dst, src string, inodes map[uint64]string) error { if err := os.Symlink(link, target); err != nil { return errors.Wrapf(err, "failed to create symlink: %s", target) } - } else if (fi.Mode() & os.ModeDevice) == os.ModeDevice { - // TODO: support devices - return errors.New("devices not supported") - } else { + case (fi.Mode() & os.ModeDevice) == os.ModeDevice: + if err := copyDevice(target, fi); err != nil { + return errors.Wrapf(err, "failed to create device") + } + default: // TODO: Support pipes and sockets return errors.Wrapf(err, "unsupported mode %s", fi.Mode()) } diff --git a/fs/copy_linux.go b/fs/copy_linux.go index 7ecd57480..f264b4a2a 100644 --- a/fs/copy_linux.go +++ b/fs/copy_linux.go @@ -108,3 +108,11 @@ func copyXAttrs(dst, src string) error { return nil } + +func copyDevice(dst string, fi os.FileInfo) error { + st, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + return errors.New("unsupported stat type") + } + return syscall.Mknod(dst, uint32(fi.Mode().Perm()), int(st.Rdev)) +} diff --git a/fs/copy_windows.go b/fs/copy_windows.go index 47ff2c532..e17c91217 100644 --- a/fs/copy_windows.go +++ b/fs/copy_windows.go @@ -25,3 +25,7 @@ func copyFileContent(dst, src *os.File) error { func copyXAttrs(dst, src string) error { return nil } + +func copyDevice(dst string, fi os.FileInfo) error { + return errors.New("device copy not supported") +} diff --git a/fs/diff.go b/fs/diff.go index 77d5732a0..1a2c55ac6 100644 --- a/fs/diff.go +++ b/fs/diff.go @@ -100,7 +100,7 @@ func Changes(ctx context.Context, upper, lower string) (context.Context, <-chan cc.errL.Unlock() cancel() } - defer close(changes) + close(changes) }() return cc, changes diff --git a/fs/path.go b/fs/path.go index 8abf4f1cc..0060a6654 100644 --- a/fs/path.go +++ b/fs/path.go @@ -99,6 +99,8 @@ func sameFile(f1, f2 *currentPath) (bool, error) { const compareChuckSize = 32 * 1024 +// compareFileContent compares the content of 2 same sized files +// by comparing each byte. func compareFileContent(p1, p2 string) (bool, error) { f1, err := os.Open(p1) if err != nil {