Source file
src/internal/poll/sendfile_windows.go
1
2
3
4
5 package poll
6
7 import (
8 "io"
9 "syscall"
10 )
11
12
13 func SendFile(fd *FD, src uintptr, size int64) (written int64, err error, handled bool) {
14 defer func() {
15 TestHookDidSendFile(fd, 0, written, err, written > 0)
16 }()
17 if fd.kind == kindPipe {
18
19 return 0, syscall.ESPIPE, false
20 }
21 hsrc := syscall.Handle(src)
22 if ft, _ := syscall.GetFileType(hsrc); ft == syscall.FILE_TYPE_PIPE {
23 return 0, syscall.ESPIPE, false
24 }
25
26 if err := fd.writeLock(); err != nil {
27 return 0, err, false
28 }
29 defer fd.writeUnlock()
30
31
32 var fi syscall.ByHandleFileInformation
33 if err := syscall.GetFileInformationByHandle(hsrc, &fi); err != nil {
34 return 0, err, false
35 }
36 fileSize := int64(fi.FileSizeHigh)<<32 + int64(fi.FileSizeLow)
37 startpos, err := syscall.Seek(hsrc, 0, io.SeekCurrent)
38 if err != nil {
39 return 0, err, false
40 }
41 maxSize := fileSize - startpos
42 if size <= 0 {
43 size = maxSize
44 } else {
45 size = min(size, maxSize)
46 }
47
48 defer func() {
49 if written > 0 {
50
51
52
53 _, serr := syscall.Seek(hsrc, startpos+written, io.SeekStart)
54 if err != nil {
55 err = serr
56 }
57 }
58 }()
59
60
61
62
63 const maxChunkSizePerCall = int64(0x7fffffff - 1)
64
65 o := &fd.wop
66 o.handle = hsrc
67 for size > 0 {
68 chunkSize := maxChunkSizePerCall
69 if chunkSize > size {
70 chunkSize = size
71 }
72
73 off := startpos + written
74 o.o.Offset = uint32(off)
75 o.o.OffsetHigh = uint32(off >> 32)
76
77 n, err := execIO(o, func(o *operation) error {
78 o.qty = uint32(chunkSize)
79 return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
80 })
81 if err != nil {
82 return written, err, written > 0
83 }
84
85 size -= int64(n)
86 written += int64(n)
87 }
88
89 return written, nil, written > 0
90 }
91
View as plain text