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