1
2
3
4
5 package poll
6
7 import (
8 "sync/atomic"
9 "syscall"
10 "unsafe"
11 )
12
13 type SysFile struct {
14
15
16
17
18
19
20 RefCountPtr *int32
21
22
23
24 RefCount int32
25
26
27 Filetype uint32
28
29
30
31 Dircookie uint64
32
33
34
35
36 Path string
37
38
39
40
41
42 }
43
44 func (s *SysFile) init() {
45 if s.RefCountPtr == nil {
46 s.RefCount = 1
47 s.RefCountPtr = &s.RefCount
48 }
49 }
50
51 func (s *SysFile) ref() SysFile {
52 atomic.AddInt32(s.RefCountPtr, +1)
53 return SysFile{RefCountPtr: s.RefCountPtr}
54 }
55
56 func (s *SysFile) destroy(fd int) error {
57 if s.RefCountPtr != nil && atomic.AddInt32(s.RefCountPtr, -1) > 0 {
58 return nil
59 }
60
61
62
63
64
65
66 return CloseFunc(fd)
67 }
68
69
70
71
72
73
74 func (fd *FD) Copy() FD {
75 return FD{
76 Sysfd: fd.Sysfd,
77 SysFile: fd.SysFile.ref(),
78 IsStream: fd.IsStream,
79 ZeroReadIsEOF: fd.ZeroReadIsEOF,
80 isBlocking: fd.isBlocking,
81 isFile: fd.isFile,
82 }
83 }
84
85
86
87 func dupCloseOnExecOld(fd int) (int, string, error) {
88 return -1, "dup", syscall.ENOSYS
89 }
90
91
92 func (fd *FD) Fchdir() error {
93 if err := fd.incref(); err != nil {
94 return err
95 }
96 defer fd.decref()
97 return syscall.Chdir(fd.Path)
98 }
99
100
101
102
103 func (fd *FD) ReadDir(buf []byte, cookie syscall.Dircookie) (int, error) {
104 if err := fd.incref(); err != nil {
105 return 0, err
106 }
107 defer fd.decref()
108 for {
109 n, err := syscall.ReadDir(fd.Sysfd, buf, cookie)
110 if err != nil {
111 n = 0
112 if err == syscall.EAGAIN && fd.pd.pollable() {
113 if err = fd.pd.waitRead(fd.isFile); err == nil {
114 continue
115 }
116 }
117 }
118
119 return n, err
120 }
121 }
122
123 func (fd *FD) ReadDirent(buf []byte) (int, error) {
124 n, err := fd.ReadDir(buf, fd.Dircookie)
125 if err != nil {
126 return 0, err
127 }
128 if n <= 0 {
129 return n, nil
130 }
131
132
133
134
135 b := buf[:n]
136
137 for len(b) > 0 {
138 next, ok := direntNext(b)
139 if !ok {
140 break
141 }
142 size, ok := direntReclen(b)
143 if !ok {
144 break
145 }
146 if size > uint64(len(b)) {
147 break
148 }
149 fd.Dircookie = syscall.Dircookie(next)
150 b = b[size:]
151 }
152
153
154
155
156
157
158
159
160 return n - len(b), nil
161 }
162
163
164 func (fd *FD) Seek(offset int64, whence int) (int64, error) {
165 if err := fd.incref(); err != nil {
166 return 0, err
167 }
168 defer fd.decref()
169
170
171
172 fileType := syscall.Filetype(atomic.LoadUint32(&fd.Filetype))
173
174 if fileType == syscall.FILETYPE_UNKNOWN {
175 var stat syscall.Stat_t
176 if err := fd.Fstat(&stat); err != nil {
177 return 0, err
178 }
179 fileType = stat.Filetype
180 atomic.StoreUint32(&fd.Filetype, uint32(fileType))
181 }
182
183 if fileType == syscall.FILETYPE_DIRECTORY {
184
185
186
187 if offset == 0 && whence == 0 {
188 fd.Dircookie = 0
189 return 0, nil
190 } else {
191 return 0, syscall.EINVAL
192 }
193 }
194
195 return syscall.Seek(fd.Sysfd, offset, whence)
196 }
197
198
199 const sizeOfDirent = 24
200
201 func direntReclen(buf []byte) (uint64, bool) {
202 namelen, ok := direntNamlen(buf)
203 return sizeOfDirent + namelen, ok
204 }
205
206 func direntNamlen(buf []byte) (uint64, bool) {
207 return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Namlen), unsafe.Sizeof(syscall.Dirent{}.Namlen))
208 }
209
210 func direntNext(buf []byte) (uint64, bool) {
211 return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Next), unsafe.Sizeof(syscall.Dirent{}.Next))
212 }
213
214
215 func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
216 if len(b) < int(off+size) {
217 return 0, false
218 }
219 return readIntLE(b[off:], size), true
220 }
221
222 func readIntLE(b []byte, size uintptr) uint64 {
223 switch size {
224 case 1:
225 return uint64(b[0])
226 case 2:
227 _ = b[1]
228 return uint64(b[0]) | uint64(b[1])<<8
229 case 4:
230 _ = b[3]
231 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
232 case 8:
233 _ = b[7]
234 return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
235 uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
236 default:
237 panic("internal/poll: readInt with unsupported size")
238 }
239 }
240
View as plain text