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