stat_plan9.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // Copyright 2011 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package os
  5. import (
  6. "syscall"
  7. "time"
  8. )
  9. const bitSize16 = 2
  10. func fileInfoFromStat(d *syscall.Dir) *fileStat {
  11. fs := &fileStat{
  12. name: d.Name,
  13. size: d.Length,
  14. modTime: time.Unix(int64(d.Mtime), 0),
  15. sys: d,
  16. }
  17. fs.mode = FileMode(d.Mode & 0777)
  18. if d.Mode&syscall.DMDIR != 0 {
  19. fs.mode |= ModeDir
  20. }
  21. if d.Mode&syscall.DMAPPEND != 0 {
  22. fs.mode |= ModeAppend
  23. }
  24. if d.Mode&syscall.DMEXCL != 0 {
  25. fs.mode |= ModeExclusive
  26. }
  27. if d.Mode&syscall.DMTMP != 0 {
  28. fs.mode |= ModeTemporary
  29. }
  30. // Consider all files not served by #M as device files.
  31. if d.Type != 'M' {
  32. fs.mode |= ModeDevice
  33. }
  34. // Consider all files served by #c as character device files.
  35. if d.Type == 'c' {
  36. fs.mode |= ModeCharDevice
  37. }
  38. return fs
  39. }
  40. // arg is an open *File or a path string.
  41. func dirstat(arg any) (*syscall.Dir, error) {
  42. var name string
  43. var err error
  44. size := syscall.STATFIXLEN + 16*4
  45. for i := 0; i < 2; i++ {
  46. buf := make([]byte, bitSize16+size)
  47. var n int
  48. switch a := arg.(type) {
  49. case *File:
  50. name = a.name
  51. n, err = syscall.Fstat(a.fd, buf)
  52. case string:
  53. name = a
  54. n, err = syscall.Stat(a, buf)
  55. default:
  56. panic("phase error in dirstat")
  57. }
  58. if n < bitSize16 {
  59. return nil, &PathError{Op: "stat", Path: name, Err: err}
  60. }
  61. // Pull the real size out of the stat message.
  62. size = int(uint16(buf[0]) | uint16(buf[1])<<8)
  63. // If the stat message is larger than our buffer we will
  64. // go around the loop and allocate one that is big enough.
  65. if size <= n {
  66. d, err := syscall.UnmarshalDir(buf[:n])
  67. if err != nil {
  68. return nil, &PathError{Op: "stat", Path: name, Err: err}
  69. }
  70. return d, nil
  71. }
  72. }
  73. if err == nil {
  74. err = syscall.ErrBadStat
  75. }
  76. return nil, &PathError{Op: "stat", Path: name, Err: err}
  77. }
  78. // statNolog implements Stat for Plan 9.
  79. func statNolog(name string) (FileInfo, error) {
  80. d, err := dirstat(name)
  81. if err != nil {
  82. return nil, err
  83. }
  84. return fileInfoFromStat(d), nil
  85. }
  86. // lstatNolog implements Lstat for Plan 9.
  87. func lstatNolog(name string) (FileInfo, error) {
  88. return statNolog(name)
  89. }
  90. // For testing.
  91. func atime(fi FileInfo) time.Time {
  92. return time.Unix(int64(fi.Sys().(*syscall.Dir).Atime), 0)
  93. }