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 return openFileNolog(name, O_RDONLY, 0)
140 }
141
142
143
144
145
146 func (f *File) Close() error {
147 if f == nil {
148 return ErrInvalid
149 }
150 return f.file.close()
151 }
152
153 func (file *file) close() error {
154 if !file.fdmu.IncrefAndClose() {
155 return &PathError{Op: "close", Path: file.name, Err: ErrClosed}
156 }
157
158
159
160
161 err := file.decref()
162
163
164 runtime.SetFinalizer(file, nil)
165 return err
166 }
167
168
169
170
171 func (file *file) destroy() error {
172 var err error
173 if e := syscall.Close(file.sysfd); e != nil {
174 err = &PathError{Op: "close", Path: file.name, Err: e}
175 }
176 return err
177 }
178
179
180
181 func (f *File) Stat() (FileInfo, error) {
182 if f == nil {
183 return nil, ErrInvalid
184 }
185 d, err := dirstat(f)
186 if err != nil {
187 return nil, err
188 }
189 return fileInfoFromStat(d), nil
190 }
191
192
193
194
195 func (f *File) Truncate(size int64) error {
196 if f == nil {
197 return ErrInvalid
198 }
199
200 var d syscall.Dir
201 d.Null()
202 d.Length = size
203
204 var buf [syscall.STATFIXLEN]byte
205 n, err := d.Marshal(buf[:])
206 if err != nil {
207 return &PathError{Op: "truncate", Path: f.name, Err: err}
208 }
209
210 if err := f.incref("truncate"); err != nil {
211 return err
212 }
213 defer f.decref()
214
215 if err = syscall.Fwstat(f.sysfd, buf[:n]); err != nil {
216 return &PathError{Op: "truncate", Path: f.name, Err: err}
217 }
218 return nil
219 }
220
221 const chmodMask = uint32(syscall.DMAPPEND | syscall.DMEXCL | syscall.DMTMP | ModePerm)
222
223 func (f *File) chmod(mode FileMode) error {
224 if f == nil {
225 return ErrInvalid
226 }
227 var d syscall.Dir
228
229 odir, e := dirstat(f)
230 if e != nil {
231 return &PathError{Op: "chmod", Path: f.name, Err: e}
232 }
233 d.Null()
234 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
235
236 var buf [syscall.STATFIXLEN]byte
237 n, err := d.Marshal(buf[:])
238 if err != nil {
239 return &PathError{Op: "chmod", Path: f.name, Err: err}
240 }
241
242 if err := f.incref("chmod"); err != nil {
243 return err
244 }
245 defer f.decref()
246
247 if err = syscall.Fwstat(f.sysfd, buf[:n]); err != nil {
248 return &PathError{Op: "chmod", Path: f.name, Err: err}
249 }
250 return nil
251 }
252
253
254
255
256 func (f *File) Sync() error {
257 if f == nil {
258 return ErrInvalid
259 }
260 var d syscall.Dir
261 d.Null()
262
263 var buf [syscall.STATFIXLEN]byte
264 n, err := d.Marshal(buf[:])
265 if err != nil {
266 return &PathError{Op: "sync", Path: f.name, Err: err}
267 }
268
269 if err := f.incref("sync"); err != nil {
270 return err
271 }
272 defer f.decref()
273
274 if err = syscall.Fwstat(f.sysfd, buf[:n]); err != nil {
275 return &PathError{Op: "sync", Path: f.name, Err: err}
276 }
277 return nil
278 }
279
280
281
282 func (f *File) read(b []byte) (n int, err error) {
283 if err := f.readLock(); err != nil {
284 return 0, err
285 }
286 defer f.readUnlock()
287 n, e := fixCount(syscall.Read(f.sysfd, b))
288 if n == 0 && len(b) > 0 && e == nil {
289 return 0, io.EOF
290 }
291 return n, e
292 }
293
294
295
296
297 func (f *File) pread(b []byte, off int64) (n int, err error) {
298 if err := f.readLock(); err != nil {
299 return 0, err
300 }
301 defer f.readUnlock()
302 n, e := fixCount(syscall.Pread(f.sysfd, b, off))
303 if n == 0 && len(b) > 0 && e == nil {
304 return 0, io.EOF
305 }
306 return n, e
307 }
308
309
310
311
312
313 func (f *File) write(b []byte) (n int, err error) {
314 if err := f.writeLock(); err != nil {
315 return 0, err
316 }
317 defer f.writeUnlock()
318 if len(b) == 0 {
319 return 0, nil
320 }
321 return fixCount(syscall.Write(f.sysfd, b))
322 }
323
324
325
326
327
328 func (f *File) pwrite(b []byte, off int64) (n int, err error) {
329 if err := f.writeLock(); err != nil {
330 return 0, err
331 }
332 defer f.writeUnlock()
333 if len(b) == 0 {
334 return 0, nil
335 }
336 return fixCount(syscall.Pwrite(f.sysfd, b, off))
337 }
338
339
340
341
342
343 func (f *File) seek(offset int64, whence int) (ret int64, err error) {
344 if err := f.incref(""); err != nil {
345 return 0, err
346 }
347 defer f.decref()
348
349
350 f.dirinfo.Store(nil)
351 return syscall.Seek(f.sysfd, offset, whence)
352 }
353
354
355
356
357 func Truncate(name string, size int64) error {
358 var d syscall.Dir
359
360 d.Null()
361 d.Length = size
362
363 var buf [syscall.STATFIXLEN]byte
364 n, err := d.Marshal(buf[:])
365 if err != nil {
366 return &PathError{Op: "truncate", Path: name, Err: err}
367 }
368 if err = syscall.Wstat(name, buf[:n]); err != nil {
369 return &PathError{Op: "truncate", Path: name, Err: err}
370 }
371 return nil
372 }
373
374
375
376 func Remove(name string) error {
377 if e := syscall.Remove(name); e != nil {
378 return &PathError{Op: "remove", Path: name, Err: e}
379 }
380 return nil
381 }
382
383 func rename(oldname, newname string) error {
384 dirname := oldname[:bytealg.LastIndexByteString(oldname, '/')+1]
385 if stringslite.HasPrefix(newname, dirname) {
386 newname = newname[len(dirname):]
387 } else {
388 return &LinkError{"rename", oldname, newname, ErrInvalid}
389 }
390
391
392
393 if bytealg.LastIndexByteString(newname, '/') >= 0 {
394 return &LinkError{"rename", oldname, newname, ErrInvalid}
395 }
396
397 var d syscall.Dir
398
399 d.Null()
400 d.Name = newname
401
402 buf := make([]byte, syscall.STATFIXLEN+len(d.Name))
403 n, err := d.Marshal(buf[:])
404 if err != nil {
405 return &LinkError{"rename", oldname, newname, err}
406 }
407
408
409 f, err := Stat(dirname + newname)
410 if err == nil && !f.IsDir() {
411 Remove(dirname + newname)
412 }
413
414 if err = syscall.Wstat(oldname, buf[:n]); err != nil {
415 return &LinkError{"rename", oldname, newname, err}
416 }
417 return nil
418 }
419
420
421 func chmod(name string, mode FileMode) error {
422 var d syscall.Dir
423
424 odir, e := dirstat(name)
425 if e != nil {
426 return &PathError{Op: "chmod", Path: name, Err: e}
427 }
428 d.Null()
429 d.Mode = odir.Mode&^chmodMask | syscallMode(mode)&chmodMask
430
431 var buf [syscall.STATFIXLEN]byte
432 n, err := d.Marshal(buf[:])
433 if err != nil {
434 return &PathError{Op: "chmod", Path: name, Err: err}
435 }
436 if err = syscall.Wstat(name, buf[:n]); err != nil {
437 return &PathError{Op: "chmod", Path: name, Err: err}
438 }
439 return nil
440 }
441
442
443
444
445
446
447
448
449 func Chtimes(name string, atime time.Time, mtime time.Time) error {
450 var d syscall.Dir
451
452 d.Null()
453 d.Atime = uint32(atime.Unix())
454 d.Mtime = uint32(mtime.Unix())
455 if atime.IsZero() {
456 d.Atime = 0xFFFFFFFF
457 }
458 if mtime.IsZero() {
459 d.Mtime = 0xFFFFFFFF
460 }
461
462 var buf [syscall.STATFIXLEN]byte
463 n, err := d.Marshal(buf[:])
464 if err != nil {
465 return &PathError{Op: "chtimes", Path: name, Err: err}
466 }
467 if err = syscall.Wstat(name, buf[:n]); err != nil {
468 return &PathError{Op: "chtimes", Path: name, Err: err}
469 }
470 return nil
471 }
472
473
474
475 func Pipe() (r *File, w *File, err error) {
476 var p [2]int
477
478 if e := syscall.Pipe(p[0:]); e != nil {
479 return nil, nil, NewSyscallError("pipe", e)
480 }
481
482 return NewFile(uintptr(p[0]), "|0"), NewFile(uintptr(p[1]), "|1"), nil
483 }
484
485
486
487
488
489 func Link(oldname, newname string) error {
490 return &LinkError{"link", oldname, newname, syscall.EPLAN9}
491 }
492
493
494
495
496
497 func Symlink(oldname, newname string) error {
498 return &LinkError{"symlink", oldname, newname, syscall.EPLAN9}
499 }
500
501 func readlink(name string) (string, error) {
502 return "", &PathError{Op: "readlink", Path: name, Err: syscall.EPLAN9}
503 }
504
505
506
507
508
509
510
511
512 func Chown(name string, uid, gid int) error {
513 return &PathError{Op: "chown", Path: name, Err: syscall.EPLAN9}
514 }
515
516
517
518
519 func Lchown(name string, uid, gid int) error {
520 return &PathError{Op: "lchown", Path: name, Err: syscall.EPLAN9}
521 }
522
523
524
525 func (f *File) Chown(uid, gid int) error {
526 if f == nil {
527 return ErrInvalid
528 }
529 return &PathError{Op: "chown", Path: f.name, Err: syscall.EPLAN9}
530 }
531
532 func tempDir() string {
533 dir := Getenv("TMPDIR")
534 if dir == "" {
535 dir = "/tmp"
536 }
537 return dir
538 }
539
540
541
542
543 func (f *File) Chdir() error {
544 if err := f.incref("chdir"); err != nil {
545 return err
546 }
547 defer f.decref()
548 if e := syscall.Fchdir(f.sysfd); e != nil {
549 return &PathError{Op: "chdir", Path: f.name, Err: e}
550 }
551 if log := testlog.Logger(); log != nil {
552 wd, err := Getwd()
553 if err == nil {
554 log.Chdir(wd)
555 }
556 }
557 return nil
558 }
559
560
561 func (f *File) setDeadline(time.Time) error {
562 if err := f.checkValid("SetDeadline"); err != nil {
563 return err
564 }
565 return poll.ErrNoDeadline
566 }
567
568
569 func (f *File) setReadDeadline(time.Time) error {
570 if err := f.checkValid("SetReadDeadline"); err != nil {
571 return err
572 }
573 return poll.ErrNoDeadline
574 }
575
576
577 func (f *File) setWriteDeadline(time.Time) error {
578 if err := f.checkValid("SetWriteDeadline"); err != nil {
579 return err
580 }
581 return poll.ErrNoDeadline
582 }
583
584
585
586
587 func (f *File) checkValid(op string) error {
588 if f == nil {
589 return ErrInvalid
590 }
591 if err := f.incref(op); err != nil {
592 return err
593 }
594 return f.decref()
595 }
596
597 type rawConn struct{}
598
599 func (c *rawConn) Control(f func(uintptr)) error {
600 return syscall.EPLAN9
601 }
602
603 func (c *rawConn) Read(f func(uintptr) bool) error {
604 return syscall.EPLAN9
605 }
606
607 func (c *rawConn) Write(f func(uintptr) bool) error {
608 return syscall.EPLAN9
609 }
610
611 func newRawConn(file *File) (*rawConn, error) {
612 return nil, syscall.EPLAN9
613 }
614
615 func ignoringEINTR(fn func() error) error {
616 return fn()
617 }
618
619 func ignoringEINTR2[T any](fn func() (T, error)) (T, error) {
620 return fn()
621 }
622
View as plain text