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