1 // Copyright 2024 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package poll
6 7 import (
8 "internal/syscall/unix"
9 "syscall"
10 )
11 12 func supportCopyFileRange() bool {
13 return unix.SupportCopyFileRange()
14 }
15 16 // For best performance, call copy_file_range() with the largest len value
17 // possible. It is interruptible on most file systems, so there is no penalty
18 // for using very large len values, even SSIZE_MAX.
19 const maxCopyFileRangeRound = 1<<31 - 1
20 21 func handleCopyFileRangeErr(err error, copied, written int64) (bool, error) {
22 switch err {
23 case syscall.ENOSYS:
24 // The copy_file_range(2) function first appeared in FreeBSD 13.0.
25 // Go supports FreeBSD >= 12, so the system call
26 // may not be present. We've detected the FreeBSD version with
27 // unix.SupportCopyFileRange() at the beginning of this function,
28 // but we still want to check for ENOSYS here to prevent some rare
29 // case like https://go.dev/issue/58592
30 //
31 // If we see ENOSYS, we have certainly not transferred
32 // any data, so we can tell the caller that we
33 // couldn't handle the transfer and let them fall
34 // back to more generic code.
35 return false, nil
36 case syscall.EFBIG, syscall.EINVAL, syscall.EIO:
37 // For EFBIG, the copy has exceeds the process's file size limit
38 // or the maximum file size for the filesystem dst resides on, in
39 // this case, we leave it to generic copy.
40 //
41 // For EINVAL, there could be a few reasons:
42 // 1. Either dst or src refers to a file object that
43 // is not a regular file, for instance, a pipe.
44 // 2. src and dst refer to the same file and byte ranges
45 // overlap.
46 // 3. The flags argument is not 0.
47 // Neither of these cases should be considered handled by
48 // copy_file_range(2) because there is no data transfer, so
49 // just fall back to generic copy.
50 return false, nil
51 }
52 return true, err
53 }
54