1 package sysfs
2
3 import (
4 "io"
5 "io/fs"
6 "os"
7 "runtime"
8
9 experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
10 "github.com/tetratelabs/wazero/internal/fsapi"
11 "github.com/tetratelabs/wazero/sys"
12 )
13
14 func newOsFile(path string, flag experimentalsys.Oflag, perm fs.FileMode, f *os.File) fsapi.File {
15
16
17
18 reopenDir := runtime.GOOS == "windows"
19 return &osFile{path: path, flag: flag, perm: perm, reopenDir: reopenDir, file: f, fd: f.Fd()}
20 }
21
22
23
24 type osFile struct {
25 path string
26 flag experimentalsys.Oflag
27 perm fs.FileMode
28 file *os.File
29 fd uintptr
30
31
32
33
34
35 reopenDir bool
36
37
38 closed bool
39
40
41 cachedSt *cachedStat
42 }
43
44
45
46 func (f *osFile) cachedStat() (dev uint64, ino sys.Inode, isDir bool, errno experimentalsys.Errno) {
47 if f.cachedSt == nil {
48 if _, errno = f.Stat(); errno != 0 {
49 return
50 }
51 }
52 return f.cachedSt.dev, f.cachedSt.ino, f.cachedSt.isDir, 0
53 }
54
55
56 func (f *osFile) Dev() (uint64, experimentalsys.Errno) {
57 dev, _, _, errno := f.cachedStat()
58 return dev, errno
59 }
60
61
62 func (f *osFile) Ino() (sys.Inode, experimentalsys.Errno) {
63 _, ino, _, errno := f.cachedStat()
64 return ino, errno
65 }
66
67
68 func (f *osFile) IsDir() (bool, experimentalsys.Errno) {
69 _, _, isDir, errno := f.cachedStat()
70 return isDir, errno
71 }
72
73
74 func (f *osFile) IsAppend() bool {
75 return f.flag&experimentalsys.O_APPEND == experimentalsys.O_APPEND
76 }
77
78
79 func (f *osFile) SetAppend(enable bool) (errno experimentalsys.Errno) {
80 if enable {
81 f.flag |= experimentalsys.O_APPEND
82 } else {
83 f.flag &= ^experimentalsys.O_APPEND
84 }
85
86
87 f.flag &= ^(experimentalsys.O_CREAT | experimentalsys.O_TRUNC)
88
89
90
91 return fileError(f, f.closed, f.reopen())
92 }
93
94
95 var _ reopenFile = (*fsFile)(nil).reopen
96
97 func (f *osFile) reopen() (errno experimentalsys.Errno) {
98
99 f.flag &= ^experimentalsys.O_CREAT
100
101 var (
102 isDir bool
103 offset int64
104 err error
105 )
106
107 isDir, errno = f.IsDir()
108 if errno != 0 {
109 return errno
110 }
111
112 if !isDir {
113 offset, err = f.file.Seek(0, io.SeekCurrent)
114 if err != nil {
115 return experimentalsys.UnwrapOSError(err)
116 }
117 }
118
119 _ = f.close()
120 f.file, errno = OpenFile(f.path, f.flag, f.perm)
121 if errno != 0 {
122 return errno
123 }
124
125 if !isDir {
126 _, err = f.file.Seek(offset, io.SeekStart)
127 if err != nil {
128 return experimentalsys.UnwrapOSError(err)
129 }
130 }
131
132 return 0
133 }
134
135
136 func (f *osFile) IsNonblock() bool {
137 return isNonblock(f)
138 }
139
140
141 func (f *osFile) SetNonblock(enable bool) (errno experimentalsys.Errno) {
142 if enable {
143 f.flag |= experimentalsys.O_NONBLOCK
144 } else {
145 f.flag &= ^experimentalsys.O_NONBLOCK
146 }
147 if errno = setNonblock(f.fd, enable); errno != 0 {
148 return fileError(f, f.closed, errno)
149 }
150 return 0
151 }
152
153
154 func (f *osFile) Stat() (sys.Stat_t, experimentalsys.Errno) {
155 if f.closed {
156 return sys.Stat_t{}, experimentalsys.EBADF
157 }
158
159 st, errno := statFile(f.file)
160 switch errno {
161 case 0:
162 f.cachedSt = &cachedStat{dev: st.Dev, ino: st.Ino, isDir: st.Mode&fs.ModeDir == fs.ModeDir}
163 case experimentalsys.EIO:
164 errno = experimentalsys.EBADF
165 }
166 return st, errno
167 }
168
169
170 func (f *osFile) Read(buf []byte) (n int, errno experimentalsys.Errno) {
171 if len(buf) == 0 {
172 return 0, 0
173 }
174 if nonBlockingFileReadSupported && f.IsNonblock() {
175 n, errno = readFd(f.fd, buf)
176 } else {
177 n, errno = read(f.file, buf)
178 }
179 if errno != 0 {
180
181 errno = fileError(f, f.closed, errno)
182 }
183 return
184 }
185
186
187 func (f *osFile) Pread(buf []byte, off int64) (n int, errno experimentalsys.Errno) {
188 if n, errno = pread(f.file, buf, off); errno != 0 {
189
190 errno = fileError(f, f.closed, errno)
191 }
192 return
193 }
194
195
196 func (f *osFile) Seek(offset int64, whence int) (newOffset int64, errno experimentalsys.Errno) {
197 if newOffset, errno = seek(f.file, offset, whence); errno != 0 {
198
199 errno = fileError(f, f.closed, errno)
200
201
202
203 if errno == experimentalsys.EISDIR && offset == 0 && whence == io.SeekStart {
204 errno = 0
205 f.reopenDir = true
206 }
207 }
208 return
209 }
210
211
212 func (f *osFile) Poll(flag fsapi.Pflag, timeoutMillis int32) (ready bool, errno experimentalsys.Errno) {
213 return poll(f.fd, flag, timeoutMillis)
214 }
215
216
217
218 func (f *osFile) Readdir(n int) (dirents []experimentalsys.Dirent, errno experimentalsys.Errno) {
219 if f.reopenDir {
220 f.reopenDir = false
221 if errno = adjustReaddirErr(f, f.closed, f.reopen()); errno != 0 {
222 return
223 }
224 }
225
226 if dirents, errno = readdir(f.file, f.path, n); errno != 0 {
227 errno = adjustReaddirErr(f, f.closed, errno)
228 }
229 return
230 }
231
232
233 func (f *osFile) Write(buf []byte) (n int, errno experimentalsys.Errno) {
234 if len(buf) == 0 {
235 return 0, 0
236 }
237 if nonBlockingFileWriteSupported && f.IsNonblock() {
238 n, errno = writeFd(f.fd, buf)
239 } else if n, errno = write(f.file, buf); errno != 0 {
240
241 errno = fileError(f, f.closed, errno)
242 }
243 return
244 }
245
246
247 func (f *osFile) Pwrite(buf []byte, off int64) (n int, errno experimentalsys.Errno) {
248 if n, errno = pwrite(f.file, buf, off); errno != 0 {
249
250 errno = fileError(f, f.closed, errno)
251 }
252 return
253 }
254
255
256 func (f *osFile) Truncate(size int64) (errno experimentalsys.Errno) {
257 if errno = experimentalsys.UnwrapOSError(f.file.Truncate(size)); errno != 0 {
258
259 errno = fileError(f, f.closed, errno)
260 }
261 return
262 }
263
264
265 func (f *osFile) Sync() experimentalsys.Errno {
266 return fsync(f.file)
267 }
268
269
270 func (f *osFile) Datasync() experimentalsys.Errno {
271 return datasync(f.file)
272 }
273
274
275 func (f *osFile) Utimens(atim, mtim int64) experimentalsys.Errno {
276 if f.closed {
277 return experimentalsys.EBADF
278 }
279
280 err := futimens(f.fd, atim, mtim)
281 return experimentalsys.UnwrapOSError(err)
282 }
283
284
285 func (f *osFile) Close() experimentalsys.Errno {
286 if f.closed {
287 return 0
288 }
289 f.closed = true
290 return f.close()
291 }
292
293 func (f *osFile) close() experimentalsys.Errno {
294 return experimentalsys.UnwrapOSError(f.file.Close())
295 }
296
View as plain text