diff options
Diffstat (limited to 'src/os/stat_plan9.go')
-rw-r--r-- | src/os/stat_plan9.go | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/src/os/stat_plan9.go b/src/os/stat_plan9.go new file mode 100644 index 0000000..e20accf --- /dev/null +++ b/src/os/stat_plan9.go @@ -0,0 +1,110 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package os + +import ( + "syscall" + "time" +) + +const bitSize16 = 2 + +func fileInfoFromStat(d *syscall.Dir) *fileStat { + fs := &fileStat{ + name: d.Name, + size: d.Length, + modTime: time.Unix(int64(d.Mtime), 0), + sys: d, + } + fs.mode = FileMode(d.Mode & 0777) + if d.Mode&syscall.DMDIR != 0 { + fs.mode |= ModeDir + } + if d.Mode&syscall.DMAPPEND != 0 { + fs.mode |= ModeAppend + } + if d.Mode&syscall.DMEXCL != 0 { + fs.mode |= ModeExclusive + } + if d.Mode&syscall.DMTMP != 0 { + fs.mode |= ModeTemporary + } + // Consider all files not served by #M as device files. + if d.Type != 'M' { + fs.mode |= ModeDevice + } + // Consider all files served by #c as character device files. + if d.Type == 'c' { + fs.mode |= ModeCharDevice + } + return fs +} + +// arg is an open *File or a path string. +func dirstat(arg any) (*syscall.Dir, error) { + var name string + var err error + + size := syscall.STATFIXLEN + 16*4 + + for i := 0; i < 2; i++ { + buf := make([]byte, bitSize16+size) + + var n int + switch a := arg.(type) { + case *File: + name = a.name + n, err = syscall.Fstat(a.fd, buf) + case string: + name = a + n, err = syscall.Stat(a, buf) + default: + panic("phase error in dirstat") + } + + if n < bitSize16 { + return nil, &PathError{Op: "stat", Path: name, Err: err} + } + + // Pull the real size out of the stat message. + size = int(uint16(buf[0]) | uint16(buf[1])<<8) + + // If the stat message is larger than our buffer we will + // go around the loop and allocate one that is big enough. + if size <= n { + d, err := syscall.UnmarshalDir(buf[:n]) + if err != nil { + return nil, &PathError{Op: "stat", Path: name, Err: err} + } + return d, nil + } + + } + + if err == nil { + err = syscall.ErrBadStat + } + + return nil, &PathError{Op: "stat", Path: name, Err: err} +} + +// statNolog implements Stat for Plan 9. +func statNolog(name string) (FileInfo, error) { + d, err := dirstat(name) + if err != nil { + return nil, err + } + return fileInfoFromStat(d), nil +} + +// lstatNolog implements Lstat for Plan 9. +func lstatNolog(name string) (FileInfo, error) { + return statNolog(name) +} + +// For testing. +func atime(fi FileInfo) time.Time { + return time.Unix(int64(fi.Sys().(*syscall.Dir).Atime), 0) +} |