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