github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/net/sendfile_bsd.go (about) 1 // Copyright 2011 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 // +build dragonfly freebsd 6 7 package net 8 9 import ( 10 "internal/poll" 11 "io" 12 "os" 13 ) 14 15 // sendFile copies the contents of r to c using the sendfile 16 // system call to minimize copies. 17 // 18 // if handled == true, sendFile returns the number of bytes copied and any 19 // non-EOF error. 20 // 21 // if handled == false, sendFile performed no work. 22 func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { 23 // FreeBSD and DragonFly use 0 as the "until EOF" value. 24 // If you pass in more bytes than the file contains, it will 25 // loop back to the beginning ad nauseam until it's sent 26 // exactly the number of bytes told to. As such, we need to 27 // know exactly how many bytes to send. 28 var remain int64 = 0 29 30 lr, ok := r.(*io.LimitedReader) 31 if ok { 32 remain, r = lr.N, lr.R 33 if remain <= 0 { 34 return 0, nil, true 35 } 36 } 37 f, ok := r.(*os.File) 38 if !ok { 39 return 0, nil, false 40 } 41 42 if remain == 0 { 43 fi, err := f.Stat() 44 if err != nil { 45 return 0, err, false 46 } 47 48 remain = fi.Size() 49 } 50 51 // The other quirk with FreeBSD/DragonFly's sendfile 52 // implementation is that it doesn't use the current position 53 // of the file -- if you pass it offset 0, it starts from 54 // offset 0. There's no way to tell it "start from current 55 // position", so we have to manage that explicitly. 56 pos, err := f.Seek(0, io.SeekCurrent) 57 if err != nil { 58 return 0, err, false 59 } 60 61 written, err = poll.SendFile(&c.pfd, int(f.Fd()), pos, remain) 62 63 if lr != nil { 64 lr.N = remain - written 65 } 66 return written, wrapSyscallError("sendfile", err), written > 0 67 }