-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
/
basicfs_copy_range_ioctl.go
93 lines (81 loc) · 2.09 KB
/
basicfs_copy_range_ioctl.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// 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 linux,!ppc,!ppc64,!ppc64le
package fs
import (
"io"
"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
}
if srcOffset+size > fi.Size() {
return io.ErrUnexpectedEOF
}
// 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.
var errNo syscall.Errno
_, err := withFileDescriptors(src, dst, func(srcFd, dstFd uintptr) (int, error) {
_, _, errNo = syscall.Syscall(syscall.SYS_IOCTL, dstFd, FICLONE, srcFd)
return 0, nil
})
// Failure in withFileDescriptors
if err != nil {
return err
}
if errNo != 0 {
return errNo
}
return nil
}
var errNo syscall.Errno
_, err = withFileDescriptors(src, dst, func(srcFd, dstFd uintptr) (int, error) {
params := fileCloneRange{
srcFd: int64(srcFd),
srcOffset: uint64(srcOffset),
srcLength: uint64(size),
dstOffset: uint64(dstOffset),
}
_, _, errNo = syscall.Syscall(syscall.SYS_IOCTL, dstFd, FICLONERANGE, uintptr(unsafe.Pointer(¶ms)))
return 0, nil
})
// Failure in withFileDescriptors
if err != nil {
return err
}
if errNo != 0 {
return errNo
}
return nil
}