diff --git a/lfs/util.go b/lfs/util.go index 82530aca..833eb860 100644 --- a/lfs/util.go +++ b/lfs/util.go @@ -45,6 +45,12 @@ func (w *CallbackReader) Read(p []byte) (int, error) { } func CopyWithCallback(writer io.Writer, reader io.Reader, totalSize int64, cb CopyCallback) (int64, error) { + if success, _ := CloneFile(writer, reader); success { + if cb != nil { + cb(totalSize, totalSize, 0) + } + return totalSize, nil + } if cb == nil { return io.Copy(writer, reader) } diff --git a/lfs/util_generic.go b/lfs/util_generic.go new file mode 100644 index 00000000..89fd3bca --- /dev/null +++ b/lfs/util_generic.go @@ -0,0 +1,11 @@ +// +build !linux !cgo + +package lfs + +import ( + "io" +) + +func CloneFile(writer io.Writer, reader io.Reader) (bool, error) { + return false, nil +} diff --git a/lfs/util_linux.go b/lfs/util_linux.go new file mode 100644 index 00000000..0f718fdf --- /dev/null +++ b/lfs/util_linux.go @@ -0,0 +1,35 @@ +// +build linux,cgo + +package lfs + +/* +#include + +#undef BTRFS_IOCTL_MAGIC +#define BTRFS_IOCTL_MAGIC 0x94 +#undef BTRFS_IOC_CLONE +#define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int) +*/ +import "C" + +import ( + "os" + "io" + "syscall" +) + +const ( + BtrfsIocClone = C.BTRFS_IOC_CLONE +) + +func CloneFile(writer io.Writer, reader io.Reader) (bool, error) { + fdst, fdstFound := writer.(*os.File) + fsrc, fsrcFound := reader.(*os.File) + if fdstFound && fsrcFound { + if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fdst.Fd(), BtrfsIocClone, fsrc.Fd()); err != 0 { + return false, err + } + return true, nil + } + return false, nil +}