mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-23 19:39:05 +00:00
73 lines
1.6 KiB
Go
73 lines
1.6 KiB
Go
|
// Copyright (C) 2019 The Syncthing Authors.
|
||
|
//
|
||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||
|
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||
|
|
||
|
// +build !windows,!solaris,!darwin
|
||
|
|
||
|
package fs
|
||
|
|
||
|
import (
|
||
|
"syscall"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
func init() {
|
||
|
registerCopyRangeImplementation(CopyRangeMethodIoctl, copyRangeImplementationForBasicFile(copyRangeIoctl))
|
||
|
}
|
||
|
|
||
|
const FICLONE = 0x40049409
|
||
|
const FICLONERANGE = 0x4020940d
|
||
|
|
||
|
/*
|
||
|
http://man7.org/linux/man-pages/man2/ioctl_ficlonerange.2.html
|
||
|
|
||
|
struct file_clone_range {
|
||
|
__s64 src_fd;
|
||
|
__u64 src_offset;
|
||
|
__u64 src_length;
|
||
|
__u64 dest_offset;
|
||
|
};
|
||
|
*/
|
||
|
type fileCloneRange struct {
|
||
|
srcFd int64
|
||
|
srcOffset uint64
|
||
|
srcLength uint64
|
||
|
dstOffset uint64
|
||
|
}
|
||
|
|
||
|
func copyRangeIoctl(src, dst basicFile, srcOffset, dstOffset, size int64) error {
|
||
|
fi, err := src.Stat()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// https://www.man7.org/linux/man-pages/man2/ioctl_ficlonerange.2.html
|
||
|
// If src_length is zero, the ioctl reflinks to the end of the source file.
|
||
|
if srcOffset+size == fi.Size() {
|
||
|
size = 0
|
||
|
}
|
||
|
|
||
|
if srcOffset == 0 && dstOffset == 0 && size == 0 {
|
||
|
// Optimization for whole file copies.
|
||
|
_, _, errNo := syscall.Syscall(syscall.SYS_IOCTL, dst.Fd(), FICLONE, src.Fd())
|
||
|
if errNo != 0 {
|
||
|
return errNo
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
params := fileCloneRange{
|
||
|
srcFd: int64(src.Fd()),
|
||
|
srcOffset: uint64(srcOffset),
|
||
|
srcLength: uint64(size),
|
||
|
dstOffset: uint64(dstOffset),
|
||
|
}
|
||
|
_, _, errNo := syscall.Syscall(syscall.SYS_IOCTL, dst.Fd(), FICLONERANGE, uintptr(unsafe.Pointer(¶ms)))
|
||
|
if errNo != 0 {
|
||
|
return errNo
|
||
|
}
|
||
|
return nil
|
||
|
}
|