Source file
src/os/readfrom_linux.go
1
2
3
4
5 package os
6
7 import (
8 "internal/poll"
9 "io"
10 "syscall"
11 )
12
13 var (
14 pollCopyFileRange = poll.CopyFileRange
15 pollSplice = poll.Splice
16 )
17
18 func (f *File) readFrom(r io.Reader) (written int64, handled bool, err error) {
19
20
21
22
23
24 if f.appendMode {
25 return 0, false, nil
26 }
27
28 written, handled, err = f.copyFileRange(r)
29 if handled {
30 return
31 }
32 return f.spliceToFile(r)
33 }
34
35 func (f *File) spliceToFile(r io.Reader) (written int64, handled bool, err error) {
36 var (
37 remain int64
38 lr *io.LimitedReader
39 )
40 if lr, r, remain = tryLimitedReader(r); remain <= 0 {
41 return 0, true, nil
42 }
43
44 pfd := getPollFD(r)
45
46
47
48
49
50
51
52 if pfd == nil || !pfd.IsStream {
53 return
54 }
55
56 var syscallName string
57 written, handled, syscallName, err = pollSplice(&f.pfd, pfd, remain)
58
59 if lr != nil {
60 lr.N = remain - written
61 }
62
63 return written, handled, wrapSyscallError(syscallName, err)
64 }
65
66
67
68
69 func getPollFD(r io.Reader) *poll.FD {
70 sc, ok := r.(syscall.Conn)
71 if !ok {
72 return nil
73 }
74 rc, err := sc.SyscallConn()
75 if err != nil {
76 return nil
77 }
78 ipfd, ok := rc.(interface{ PollFD() *poll.FD })
79 if !ok {
80 return nil
81 }
82 return ipfd.PollFD()
83 }
84
85 func (f *File) copyFileRange(r io.Reader) (written int64, handled bool, err error) {
86 var (
87 remain int64
88 lr *io.LimitedReader
89 )
90 if lr, r, remain = tryLimitedReader(r); remain <= 0 {
91 return 0, true, nil
92 }
93
94 src, ok := r.(*File)
95 if !ok {
96 return 0, false, nil
97 }
98 if src.checkValid("ReadFrom") != nil {
99
100
101 return 0, false, nil
102 }
103
104 written, handled, err = pollCopyFileRange(&f.pfd, &src.pfd, remain)
105 if lr != nil {
106 lr.N -= written
107 }
108 return written, handled, wrapSyscallError("copy_file_range", err)
109 }
110
111
112
113
114 func tryLimitedReader(r io.Reader) (*io.LimitedReader, io.Reader, int64) {
115 var remain int64 = 1<<63 - 1
116
117 lr, ok := r.(*io.LimitedReader)
118 if !ok {
119 return nil, r, remain
120 }
121
122 remain = lr.N
123 return lr, lr.R, remain
124 }
125
View as plain text