@@ -109,36 +109,51 @@ func (h *ihash) Close() error {
109109
110110func (h * ihash ) ReadFrom (r io.Reader ) (int64 , error ) {
111111 if f , ok := r .(* os.File ); ok {
112- return h .readFromFile (f , - 1 )
112+ if w , err , handled := h .sendfile (f , - 1 ); handled {
113+ return w , err
114+ }
115+ if w , err , handled := h .splice (f , - 1 ); handled {
116+ return w , err
117+ }
113118 }
114119 if lr , ok := r .(* io.LimitedReader ); ok {
115- if f , ok := lr .R .(* os.File ); ok {
116- return h .readFromFile (f , lr .N )
117- }
120+ return h .readFromLimitedReader (lr )
118121 }
119122 return genericReadFrom (h , r )
120123}
121124
122- func (h * ihash ) readFromFile (f * os.File , limit int64 ) (int64 , error ) {
125+ func (h * ihash ) readFromLimitedReader (lr * io.LimitedReader ) (int64 , error ) {
126+ if f , ok := lr .R .(* os.File ); ok {
127+ if w , err , handled := h .sendfile (f , lr .N ); handled {
128+ return w , err
129+ }
130+ if w , err , handled := h .splice (f , lr .N ); handled {
131+ return w , err
132+ }
133+ }
134+ return genericReadFrom (h , lr )
135+ }
136+
137+ func (h * ihash ) splice (f * os.File , remain int64 ) (written int64 , err error , handled bool ) {
123138 offset , err := f .Seek (0 , io .SeekCurrent )
124139 if err != nil {
125- return 0 , err
140+ return 0 , nil , false
126141 }
127142 fi , err := f .Stat ()
128143 if err != nil {
129- return 0 , err
144+ return 0 , nil , false
130145 }
131- if limit == - 1 {
132- limit = fi .Size () - offset
146+ if remain == - 1 {
147+ remain = fi .Size () - offset
133148 }
134149 // mmap must align on a page boundary
135150 // mmap from 0, use data from offset
136151 bytes , err := syscall .Mmap (int (f .Fd ()), 0 , int (fi .Size ()),
137152 syscall .PROT_READ , syscall .MAP_SHARED )
138153 if err != nil {
139- return 0 , err
154+ return 0 , nil , false
140155 }
141- bytes = bytes [offset : offset + limit ]
156+ bytes = bytes [offset : offset + remain ]
142157 defer syscall .Munmap (bytes )
143158
144159 var (
@@ -153,7 +168,7 @@ func (h *ihash) readFromFile(f *os.File, limit int64) (int64, error) {
153168 for {
154169 n , err := h .Write (bytes [start :end ])
155170 if err != nil {
156- return int64 (start + n ), err
171+ return int64 (start + n ), err , true
157172 }
158173 start += n
159174 if start >= total {
@@ -164,23 +179,69 @@ func (h *ihash) readFromFile(f *os.File, limit int64) (int64, error) {
164179 end = total
165180 }
166181 }
167- return int64 ( total ) , nil
182+ return remain , nil , true
168183}
169184
170- // Write writes data to an AF_ALG socket, but instructs the kernel
171- // not to finalize the hash.
172- func (h * ihash ) Write (b []byte ) (int , error ) {
173- n , err := h .pipes [1 ].Vmsplice (b , 0 )
185+ func (h * ihash ) sendfile (f * os.File , remain int64 ) (written int64 , err error , handled bool ) {
186+ offset , err := f .Seek (0 , io .SeekCurrent )
174187 if err != nil {
175- return 0 , err
188+ return 0 , nil , false
176189 }
177-
178- _ , err = h .pipes [0 ].Splice (h .s .FD (), n , unix .SPLICE_F_MOVE | unix .SPLICE_F_MORE )
190+ fi , err := f .Stat ()
179191 if err != nil {
180- return 0 , err
192+ return 0 , nil , false
193+ }
194+ if remain == - 1 {
195+ remain = fi .Size () - offset
196+ }
197+ sc , err := f .SyscallConn ()
198+ if err != nil {
199+ return 0 , nil , false
200+ }
201+ var (
202+ n int
203+ werr error
204+ )
205+ err = sc .Read (func (fd uintptr ) bool {
206+ for {
207+ n , werr = syscall .Sendfile (h .s .FD (), int (fd ), & offset , int (remain ))
208+ if werr != nil {
209+ break
210+ }
211+ if int64 (n ) >= remain {
212+ break
213+ }
214+ remain -= int64 (n )
215+ written += int64 (n )
216+ }
217+ return true
218+ })
219+ if err == nil {
220+ err = werr
221+ }
222+ return written , err , true
223+ }
224+
225+ // Write writes data to an AF_ALG socket, but instructs the kernel
226+ // not to finalize the hash.
227+ func (h * ihash ) Write (b []byte ) (written int , err error ) {
228+ for {
229+ n , err := h .pipes [1 ].Vmsplice (b , 0 )
230+ written += n
231+ if err != nil {
232+ break
233+ }
234+ _ , err = h .pipes [0 ].Splice (h .s .FD (), n , unix .SPLICE_F_MOVE | unix .SPLICE_F_MORE )
235+ if err != nil {
236+ break
237+ }
238+ if n >= len (b ) {
239+ break
240+ }
241+ b = b [n :]
181242 }
182243
183- return len ( b ), nil
244+ return
184245}
185246
186247// Sum reads data from an AF_ALG socket, and appends it to the input
0 commit comments