Source file
src/os/zero_copy_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
19
20 func wrapSyscallError(name string, err error) error {
21 if _, ok := err.(syscall.Errno); ok {
22 err = NewSyscallError(name, err)
23 }
24 return err
25 }
26
27 func (f *File) writeTo(w io.Writer) (written int64, handled bool, err error) {
28 pfd, network := getPollFDAndNetwork(w)
29
30 if pfd == nil || !pfd.IsStream || !isUnixOrTCP(string(network)) {
31 return
32 }
33
34 sc, err := f.SyscallConn()
35 if err != nil {
36 return
37 }
38
39 rerr := sc.Read(func(fd uintptr) (done bool) {
40 written, err, handled = poll.SendFile(pfd, int(fd), 1<<63-1)
41 return true
42 })
43
44 if err == nil {
45 err = rerr
46 }
47
48 return written, handled, wrapSyscallError("sendfile", err)
49 }
50
51 func (f *File) readFrom(r io.Reader) (written int64, handled bool, err error) {
52
53
54
55
56
57 if f.appendMode {
58 return 0, false, nil
59 }
60
61 written, handled, err = f.copyFileRange(r)
62 if handled {
63 return
64 }
65 return f.spliceToFile(r)
66 }
67
68 func (f *File) spliceToFile(r io.Reader) (written int64, handled bool, err error) {
69 var (
70 remain int64
71 lr *io.LimitedReader
72 )
73 if lr, r, remain = tryLimitedReader(r); remain <= 0 {
74 return 0, true, nil
75 }
76
77 pfd, _ := getPollFDAndNetwork(r)
78
79
80
81
82
83
84
85 if pfd == nil || !pfd.IsStream {
86 return
87 }
88
89 written, handled, err = pollSplice(&f.pfd, pfd, remain)
90
91 if lr != nil {
92 lr.N = remain - written
93 }
94
95 return written, handled, wrapSyscallError("splice", err)
96 }
97
98 func (f *File) copyFileRange(r io.Reader) (written int64, handled bool, err error) {
99 var (
100 remain int64
101 lr *io.LimitedReader
102 )
103 if lr, r, remain = tryLimitedReader(r); remain <= 0 {
104 return 0, true, nil
105 }
106
107 var src *File
108 switch v := r.(type) {
109 case *File:
110 src = v
111 case fileWithoutWriteTo:
112 src = v.File
113 default:
114 return 0, false, nil
115 }
116
117 if src.checkValid("ReadFrom") != nil {
118
119
120 return 0, false, nil
121 }
122
123 written, handled, err = pollCopyFileRange(&f.pfd, &src.pfd, remain)
124 if lr != nil {
125 lr.N -= written
126 }
127 return written, handled, wrapSyscallError("copy_file_range", err)
128 }
129
130
131
132
133 func getPollFDAndNetwork(i any) (*poll.FD, poll.String) {
134 sc, ok := i.(syscall.Conn)
135 if !ok {
136 return nil, ""
137 }
138 rc, err := sc.SyscallConn()
139 if err != nil {
140 return nil, ""
141 }
142 irc, ok := rc.(interface {
143 PollFD() *poll.FD
144 Network() poll.String
145 })
146 if !ok {
147 return nil, ""
148 }
149 return irc.PollFD(), irc.Network()
150 }
151
152
153
154
155 func tryLimitedReader(r io.Reader) (*io.LimitedReader, io.Reader, int64) {
156 var remain int64 = 1<<63 - 1
157
158 lr, ok := r.(*io.LimitedReader)
159 if !ok {
160 return nil, r, remain
161 }
162
163 remain = lr.N
164 return lr, lr.R, remain
165 }
166
167 func isUnixOrTCP(network string) bool {
168 switch network {
169 case "tcp", "tcp4", "tcp6", "unix":
170 return true
171 default:
172 return false
173 }
174 }
175
View as plain text