@@ -36,48 +36,33 @@ func SendFile(dstFD *FD, src int, size int64) (n int64, err error, handled bool)
36
36
return sendFile (dstFD , src , nil , size )
37
37
}
38
38
39
- // Darwin/FreeBSD/DragonFly/Solaris's sendfile implementation
40
- // doesn't use the current position of the file --
41
- // if you pass it offset 0, it starts from offset 0.
42
- // There's no way to tell it "start from current position",
43
- // so we have to manage that explicitly.
39
+ // Non-Linux sendfile implementations don't use the current position of the source file,
40
+ // so we need to look up the position, pass it explicitly, and adjust it after
41
+ // sendfile returns.
44
42
start , err := ignoringEINTR2 (func () (int64 , error ) {
45
43
return syscall .Seek (src , 0 , io .SeekCurrent )
46
44
})
47
45
if err != nil {
48
46
return 0 , err , false
49
47
}
50
48
51
- // Solaris requires us to pass a length to send,
52
- // rather than accepting 0 as "send everything".
53
- //
54
- // Seek to the end of the source file to find its length.
55
- //
56
- // Important: If we ever remove this block
57
- // (because Solaris has added a way to send everything, or we discovered a
58
- // previously-unknown existing way),
59
- // then some of the sendFile function will need updating.
60
- //
61
- // On Solaris, sendfile can return n>0 and EINVAL when successfully copying to a file.
62
- // We ignore the EINVAL in this case.
63
- //
64
- // On non-Solaris platforms, when size==0 we call sendfile until it returns
65
- // n==0 and success, indicating that it has copied the entire source file.
66
- // If we were to do this on Solaris, then the final sendfile call could return (0, EINVAL),
67
- // which we would treat as an error rather than successful completion of the copy.
68
- // This never happens, because when size==0 on Solaris,
69
- // we look up the actual file size here.
70
- // If we change that, we need to handle the (0, EINVAL) case below.
71
49
mustReposition := false
72
- if runtime .GOOS == "solaris" && size == 0 {
73
- end , err := ignoringEINTR2 (func () (int64 , error ) {
74
- return syscall .Seek (src , 0 , io .SeekEnd )
75
- })
76
- if err != nil {
77
- return 0 , err , false
50
+ switch runtime .GOOS {
51
+ case "solaris" , "illumos" :
52
+ // Solaris/illumos requires us to pass a length to send,
53
+ // rather than accepting 0 as "send everything".
54
+ //
55
+ // Seek to the end of the source file to find its length.
56
+ if size == 0 {
57
+ end , err := ignoringEINTR2 (func () (int64 , error ) {
58
+ return syscall .Seek (src , 0 , io .SeekEnd )
59
+ })
60
+ if err != nil {
61
+ return 0 , err , false
62
+ }
63
+ size = end - start
64
+ mustReposition = true
78
65
}
79
- size = end - start
80
- mustReposition = true
81
66
}
82
67
83
68
pos := start
@@ -115,6 +100,22 @@ func sendFile(dstFD *FD, src int, offset *int64, size int64) (written int64, err
115
100
if n > 0 {
116
101
written += int64 (n )
117
102
}
103
+
104
+ switch runtime .GOOS {
105
+ case "solaris" , "illumos" :
106
+ // A quirk on Solaris/illumos: sendfile() claims to support out_fd
107
+ // as a regular file but returns EINVAL when the out_fd
108
+ // is not a socket of SOCK_STREAM, while it actually sends
109
+ // out data anyway and updates the file offset.
110
+ //
111
+ // We ignore EINVAL if any sendfile call returned n > 0,
112
+ // to handle the case where the last call returns 0 to indicate
113
+ // no more data to send.
114
+ if err == syscall .EINVAL && written > 0 {
115
+ err = nil
116
+ }
117
+ }
118
+
118
119
switch err {
119
120
case nil :
120
121
// We're done if sendfile copied no bytes
@@ -158,18 +159,11 @@ func sendFileChunk(dst, src int, offset *int64, size int) (n int, err error) {
158
159
case "linux" :
159
160
// The offset is always nil on Linux.
160
161
n , err = syscall .Sendfile (dst , src , offset , size )
161
- case "solaris" :
162
+ case "solaris" , "illumos" :
162
163
// Trust the offset, not the return value from sendfile.
163
164
start := * offset
164
165
n , err = syscall .Sendfile (dst , src , offset , size )
165
166
n = int (* offset - start )
166
- // A quirk on Solaris: sendfile() claims to support out_fd
167
- // as a regular file but returns EINVAL when the out_fd
168
- // is not a socket of SOCK_STREAM, while it actually sends
169
- // out data anyway and updates the file offset.
170
- if err == syscall .EINVAL && n > 0 {
171
- err = nil
172
- }
173
167
default :
174
168
start := * offset
175
169
n , err = syscall .Sendfile (dst , src , offset , size )
0 commit comments