github.com/bir3/gocompiler@v0.9.2202/src/internal/poll/sendfile_windows.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 package poll 6 7 import ( 8 "io" 9 "syscall" 10 ) 11 12 // SendFile wraps the TransmitFile call. 13 func SendFile(fd *FD, src syscall.Handle, n int64) (written int64, err error) { 14 if fd.kind == kindPipe { 15 // TransmitFile does not work with pipes 16 return 0, syscall.ESPIPE 17 } 18 if ft, _ := syscall.GetFileType(src); ft == syscall.FILE_TYPE_PIPE { 19 return 0, syscall.ESPIPE 20 } 21 22 if err := fd.writeLock(); err != nil { 23 return 0, err 24 } 25 defer fd.writeUnlock() 26 27 o := &fd.wop 28 o.handle = src 29 30 // TODO(brainman): skip calling syscall.Seek if OS allows it 31 curpos, err := syscall.Seek(o.handle, 0, io.SeekCurrent) 32 if err != nil { 33 return 0, err 34 } 35 36 if n <= 0 { // We don't know the size of the file so infer it. 37 // Find the number of bytes offset from curpos until the end of the file. 38 n, err = syscall.Seek(o.handle, -curpos, io.SeekEnd) 39 if err != nil { 40 return 41 } 42 // Now seek back to the original position. 43 if _, err = syscall.Seek(o.handle, curpos, io.SeekStart); err != nil { 44 return 45 } 46 } 47 48 // TransmitFile can be invoked in one call with at most 49 // 2,147,483,646 bytes: the maximum value for a 32-bit integer minus 1. 50 // See https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-transmitfile 51 const maxChunkSizePerCall = int64(0x7fffffff - 1) 52 53 for n > 0 { 54 chunkSize := maxChunkSizePerCall 55 if chunkSize > n { 56 chunkSize = n 57 } 58 59 o.qty = uint32(chunkSize) 60 o.o.Offset = uint32(curpos) 61 o.o.OffsetHigh = uint32(curpos >> 32) 62 63 nw, err := execIO(o, func(o *operation) error { 64 return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND) 65 }) 66 if err != nil { 67 return written, err 68 } 69 70 curpos += int64(nw) 71 72 // Some versions of Windows (Windows 10 1803) do not set 73 // file position after TransmitFile completes. 74 // So just use Seek to set file position. 75 if _, err = syscall.Seek(o.handle, curpos, io.SeekStart); err != nil { 76 return written, err 77 } 78 79 n -= int64(nw) 80 written += int64(nw) 81 } 82 83 return 84 }