Source file
src/os/file_plan9.go
1
2
3
4
5 package os
6
7 import (
8 "internal/bytealg"
9 "internal/poll"
10 "internal/stringslite"
11 "io"
12 "runtime"
13 "sync"
14 "sync/atomic"
15 "syscall"
16 "time"
17 )
18
19
20 func fixLongPath(path string) string {
21 return path
22 }
23
24
25
26
27
28 type file struct {
29 fdmu poll.FDMutex
30 sysfd int
31 name string
32 dirinfo atomic.Pointer[dirInfo]
33 appendMode bool
34 }
35
36
37 func (f *File) fd() uintptr {
38 if f == nil {
39 return ^(uintptr(0))
40 }
41 return uintptr(f.sysfd)
42 }
43
44
45 func newFileFromNewFile(fd uintptr, name string) *File {
46 fdi := int(fd)
47 if fdi < 0 {
48 return nil
49 }
50 f := &File{&file{sysfd: fdi, name: name}}
51 runtime.SetFinalizer(f.file, (*file).close)
52 return f
53 }
54
55
56 type dirInfo struct {
57 mu sync.Mutex
58 buf [syscall.STATMAX]byte
59 nbuf int
60 bufp int
61 }
62
63 func epipecheck(file *File, e error) {
64 }
65
66
67
68 const DevNull = "/dev/null"
69
70
71 func syscallMode(i FileMode) (o uint32) {
72 o |= uint32(i.Perm())
73 if i&ModeAppend != 0 {
74 o |= syscall.DMAPPEND
75 }
76 if i&ModeExclusive != 0 {
77 o |= syscall.DMEXCL
78 }
79 if i&ModeTemporary != 0 {
80 o |= syscall.DMTMP
81 }
82 return
83 }
84
85
86 func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
87 var (
88 fd int
89 e error
90 create bool
91 excl bool
92 trunc bool
93 append bool
94 )
95
96 if flag&O_CREATE == O_CREATE {
97 flag = flag & ^O_CREATE
98 create = true
99 }
100 if flag&O_EXCL == O_EXCL {
101 excl = true
102 }
103 if flag&O_TRUNC == O_TRUNC {
104 trunc = true
105 }
106
107 if flag&O_APPEND == O_APPEND {
108 flag = flag &^ O_APPEND
109 append = true
110 }
111
112 if (create && trunc) || excl {
113 fd, e = syscall.Create(name, flag, syscallMode(perm))
114 } else {
115 fd, e = syscall.Open(name, flag)
116 if IsNotExist(e) && create {
117 fd, e = syscall.Create(name, flag, syscallMode(perm))
118 if e != nil {
119 return nil, &PathError{Op: "create", Path: name, Err: e}
120 }
121 }
122 }
123
124 if e != nil {
125 return nil, &PathError{Op: "open", Path: name, Err: e}
126 }
127
128 if append {
129 if _, e = syscall.Seek(fd, 0, io.SeekEnd); e != nil {
130 return nil, &PathError{Op: "seek", Path: name, Err: e}
131 }
132 }
133
134 return NewFile(uintptr(fd), name), nil
135 }
136
137 func openDirNolog(name string) (*File, error) {
138 return openFileNolog(name, O_RDONLY, 0)
139 }
140
141
142
143
144
145 func (f *File) Close() error {
146 if f == nil {
147 return ErrInvalid
148 }
149 return f.file.close()
150 }
151
152 func (file *file) close() error {
153 if !file.fdmu.IncrefAndClose() {
154 return &PathError{Op: "close", Path: file.name, Err: ErrClosed}
155 }
156
157
158
159
160 err := file.decref()
161
162
163 runtime.SetFinalizer(file, nil)
164 return err
165 }
166
167
168
169
170 func (file *file) destroy() error {
171 var err error
172 if e := syscall.Close(file.sysfd); e != nil {
173 err = &PathError{Op: "close", Path: file.name, Err: e}
174 }
175 return err
176 }
177
178
179
180 func (f *File) Stat() (FileInfo, error) {
181 if f == nil {
182 return nil, ErrInvalid
183 }
184 d, err := dirstat(f)
185 if err != nil {
186 return nil, err
187 }
188 return fileInfoFromStat(d), nil
189 }
190
191
192
193
194 func (f *File) Truncate(size int64) error {
195 if f == nil {
196 return ErrInvalid
197 }
198
199 var d syscall.Dir
200 d.Null()
201 d.Length = size
202
203 var buf [syscall.STATFIXLEN]byte
204 n, err := d.Marshal(buf[:])
205 if err != nil {
206 return &PathError{Op: "truncate", Path: f.name, Err: err}
207 }
208
209 if err := f.incref("truncate"); err != nil {
210 return err
211 }
212 defer f.decref()
213
214 if err = syscall.Fwstat(f.sysfd, buf[:n]); err != nil {
215 return &PathError{Op: "truncate", Path: f.name, Err: err}
216 }
217 return nil
218 }
219
220 const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm)
221
222 func (f *File) chmod(mode FileMode) error {
223 if f == nil {
224 return ErrInvalid
225 }
226 var d syscall.Dir
227
228 odir, e := dirstat(f)
229 if e != nil {
230 return &PathError{Op: "chmod", Path: f.name, Err: e}
231 }
232 d.Null()
233 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
234
235 var buf [syscall.STATFIXLEN]byte
236 n, err := d.Marshal(buf[:])
237 if err != nil {
238 return &PathError{Op: "chmod", Path: f.name, Err: err}
239 }
240
241 if err := f.incref("chmod"); err != nil {
242 return err
243 }
244 defer f.decref()
245
246 if err = syscall.Fwstat(f.sysfd, buf[:n]); err != nil {
247 return &PathError{Op: "chmod", Path: f.name, Err: err}
248 }
249 return nil
250 }
251
252
253
254
255 func (f *File) Sync() error {
256 if f == nil {
257 return ErrInvalid
258 }
259 var d syscall.Dir
260 d.Null()
261
262 var buf [syscall.STATFIXLEN]byte
263 n, err := d.Marshal(buf[:])
264 if err != nil {
265 return &PathError{Op: "sync", Path: f.name, Err: err}
266 }
267
268 if err := f.incref("sync"); err != nil {
269 return err
270 }
271 defer f.decref()
272
273 if err = syscall.Fwstat(f.sysfd, buf[:n]); err != nil {
274 return &PathError{Op: "sync", Path: f.name, Err: err}
275 }
276 return nil
277 }
278
279
280
281 func (f *File) read(b []byte) (n int, err error) {
282 if err := f.readLock(); err != nil {
283 return 0, err
284 }
285 defer f.readUnlock()
286 n, e := fixCount(syscall.Read(f.sysfd, b))
287 if n == 0 && len(b) > 0 && e == nil {
288 return 0, io.EOF
289 }
290 return n, e
291 }
292
293
294
295
296 func (f *File) pread(b []byte, off int64) (n int, err error) {
297 if err := f.readLock(); err != nil {
298 return 0, err
299 }
300 defer f.readUnlock()
301 n, e := fixCount(syscall.Pread(f.sysfd, b, off))
302 if n == 0 && len(b) > 0 && e == nil {
303 return 0, io.EOF
304 }
305 return n, e
306 }
307
308
309
310
311
312 func (f *File) write(b []byte) (n int, err error) {
313 if err := f.writeLock(); err != nil {
314 return 0, err
315 }
316 defer f.writeUnlock()
317 if len(b) == 0 {
318 return 0, nil
319 }
320 return fixCount(syscall.Write(f.sysfd, b))
321 }
322
323
324
325
326
327 func (f *File) pwrite(b []byte, off int64) (n int, err error) {
328 if err := f.writeLock(); err != nil {
329 return 0, err
330 }
331 defer f.writeUnlock()
332 if len(b) == 0 {
333 return 0, nil
334 }
335 return fixCount(syscall.Pwrite(f.sysfd, b, off))
336 }
337
338
339
340
341
342 func (f *File) seek(offset int64, whence int) (ret int64, err error) {
343 if err := f.incref(""); err != nil {
344 return 0, err
345 }
346 defer f.decref()
347
348
349 f.dirinfo.Store(nil)
350 return syscall.Seek(f.sysfd, offset, whence)
351 }
352
353
354
355
356 func Truncate(name string, size int64) error {
357 var d syscall.Dir
358
359 d.Null()
360 d.Length = size
361
362 var buf [syscall.STATFIXLEN]byte
363 n, err := d.Marshal(buf[:])
364 if err != nil {
365 return &PathError{Op: "truncate", Path: name, Err: err}
366 }
367 if err = syscall.Wstat(name, buf[:n]); err != nil {
368 return &PathError{Op: "truncate", Path: name, Err: err}
369 }
370 return nil
371 }
372
373
374
375 func Remove(name string) error {
376 if e := syscall.Remove(name); e != nil {
377 return &PathError{Op: "remove", Path: name, Err: e}
378 }
379 return nil
380 }
381
382 func rename(oldname, newname string) error {
383 dirname := oldname[:bytealg.LastIndexByteString(oldname, '/')+1]
384 if stringslite.HasPrefix(newname, dirname) {
385 newname = newname[len(dirname):]
386 } else {
387 return &LinkError{"rename", oldname, newname, ErrInvalid}
388 }
389
390
391
392 if bytealg.LastIndexByteString(newname, '/') >= 0 {
393 return &LinkError{"rename", oldname, newname, ErrInvalid}
394 }
395
396 var d syscall.Dir
397
398 d.Null()
399 d.Name = newname
400
401 buf := make([]byte, syscall.STATFIXLEN+len(d.Name))
402 n, err := d.Marshal(buf[:])
403 if err != nil {
404 return &LinkError{"rename", oldname, newname, err}
405 }
406
407
408 f, err := Stat(dirname + newname)
409 if err == nil && !f.IsDir() {
410 Remove(dirname + newname)
411 }
412
413 if err = syscall.Wstat(oldname, buf[:n]); err != nil {
414 return &LinkError{"rename", oldname, newname, err}
415 }
416 return nil
417 }
418
419
420 func chmod(name string, mode FileMode) error {
421 var d syscall.Dir
422
423 odir, e := dirstat(name)
424 if e != nil {
425 return &PathError{Op: "chmod", Path: name, Err: e}
426 }
427 d.Null()
428 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
429
430 var buf [syscall.STATFIXLEN]byte
431 n, err := d.Marshal(buf[:])
432 if err != nil {
433 return &PathError{Op: "chmod", Path: name, Err: err}
434 }
435 if err = syscall.Wstat(name, buf[:n]); err != nil {
436 return &PathError{Op: "chmod", Path: name, Err: err}
437 }
438 return nil
439 }
440
441
442
443
444
445
446
447
448 func Chtimes(name string, atime time.Time, mtime time.Time) error {
449 var d syscall.Dir
450
451 d.Null()
452 d.Atime = uint32(atime.Unix())
453 d.Mtime = uint32(mtime.Unix())
454 if atime.IsZero() {
455 d.Atime = 0xFFFFFFFF
456 }
457 if mtime.IsZero() {
458 d.Mtime = 0xFFFFFFFF
459 }
460
461 var buf [syscall.STATFIXLEN]byte
462 n, err := d.Marshal(buf[:])
463 if err != nil {
464 return &PathError{Op: "chtimes", Path: name, Err: err}
465 }
466 if err = syscall.Wstat(name, buf[:n]); err != nil {
467 return &PathError{Op: "chtimes", Path: name, Err: err}
468 }
469 return nil
470 }
471
472
473
474 func Pipe() (r *File, w *File, err error) {
475 var p [2]int
476
477 if e := syscall.Pipe(p[0:]); e != nil {
478 return nil, nil, NewSyscallError("pipe", e)
479 }
480
481 return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
482 }
483
484
485
486
487
488 func Link(oldname, newname string) error {
489 return &LinkError{"link", oldname, newname, syscall.EPLAN9}
490 }
491
492
493
494
495
496 func Symlink(oldname, newname string) error {
497 return &LinkError{"symlink", oldname, newname, syscall.EPLAN9}
498 }
499
500 func readlink(name string) (string, error) {
501 return "", &PathError{Op: "readlink", Path: name, Err: syscall.EPLAN9}
502 }
503
504
505
506
507
508
509
510
511 func Chown(name string, uid, gid int) error {
512 return &PathError{Op: "chown", Path: name, Err: syscall.EPLAN9}
513 }
514
515
516
517
518 func Lchown(name string, uid, gid int) error {
519 return &PathError{Op: "lchown", Path: name, Err: syscall.EPLAN9}
520 }
521
522
523
524 func (f *File) Chown(uid, gid int) error {
525 if f == nil {
526 return ErrInvalid
527 }
528 return &PathError{Op: "chown", Path: f.name, Err: syscall.EPLAN9}
529 }
530
531 func tempDir() string {
532 dir := Getenv("TMPDIR")
533 if dir == "" {
534 dir = "/tmp"
535 }
536 return dir
537 }
538
539
540
541
542 func (f *File) Chdir() error {
543 if err := f.incref("chdir"); err != nil {
544 return err
545 }
546 defer f.decref()
547 if e := syscall.Fchdir(f.sysfd); e != nil {
548 return &PathError{Op: "chdir", Path: f.name, Err: e}
549 }
550 return nil
551 }
552
553
554 func (f *File) setDeadline(time.Time) error {
555 if err := f.checkValid("SetDeadline"); err != nil {
556 return err
557 }
558 return poll.ErrNoDeadline
559 }
560
561
562 func (f *File) setReadDeadline(time.Time) error {
563 if err := f.checkValid("SetReadDeadline"); err != nil {
564 return err
565 }
566 return poll.ErrNoDeadline
567 }
568
569
570 func (f *File) setWriteDeadline(time.Time) error {
571 if err := f.checkValid("SetWriteDeadline"); err != nil {
572 return err
573 }
574 return poll.ErrNoDeadline
575 }
576
577
578
579
580 func (f *File) checkValid(op string) error {
581 if f == nil {
582 return ErrInvalid
583 }
584 if err := f.incref(op); err != nil {
585 return err
586 }
587 return f.decref()
588 }
589
590 type rawConn struct{}
591
592 func (c *rawConn) Control(f func(uintptr)) error {
593 return syscall.EPLAN9
594 }
595
596 func (c *rawConn) Read(f func(uintptr) bool) error {
597 return syscall.EPLAN9
598 }
599
600 func (c *rawConn) Write(f func(uintptr) bool) error {
601 return syscall.EPLAN9
602 }
603
604 func newRawConn(file *File) (*rawConn, error) {
605 return nil, syscall.EPLAN9
606 }
607
608 func ignoringEINTR(fn func() error) error {
609 return fn()
610 }
611
612 func ignoringEINTR2[T any](fn func() (T, error)) (T, error) {
613 return fn()
614 }
615
View as plain text