stat_plan9.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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. func sameFile(fs1, fs2 *fileStat) bool {
  10. a := fs1.sys.(*syscall.Dir)
  11. b := fs2.sys.(*syscall.Dir)
  12. return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
  13. }
  14. func fileInfoFromStat(d *syscall.Dir) FileInfo {
  15. fs := &fileStat{
  16. name: d.Name,
  17. size: int64(d.Length),
  18. modTime: time.Unix(int64(d.Mtime), 0),
  19. sys: d,
  20. }
  21. fs.mode = FileMode(d.Mode & 0777)
  22. if d.Mode&syscall.DMDIR != 0 {
  23. fs.mode |= ModeDir
  24. }
  25. if d.Mode&syscall.DMAPPEND != 0 {
  26. fs.mode |= ModeAppend
  27. }
  28. if d.Mode&syscall.DMEXCL != 0 {
  29. fs.mode |= ModeExclusive
  30. }
  31. if d.Mode&syscall.DMTMP != 0 {
  32. fs.mode |= ModeTemporary
  33. }
  34. return fs
  35. }
  36. // arg is an open *File or a path string.
  37. func dirstat(arg interface{}) (*syscall.Dir, error) {
  38. var name string
  39. // This is big enough for most stat messages
  40. // and rounded to a multiple of 128 bytes.
  41. size := (syscall.STATFIXLEN + 16*4 + 128) &^ 128
  42. for i := 0; i < 2; i++ {
  43. buf := make([]byte, size)
  44. var n int
  45. var err error
  46. switch a := arg.(type) {
  47. case *File:
  48. name = a.name
  49. n, err = syscall.Fstat(a.fd, buf)
  50. case string:
  51. name = a
  52. n, err = syscall.Stat(a, buf)
  53. default:
  54. panic("phase error in dirstat")
  55. }
  56. if err != nil {
  57. return nil, &PathError{"stat", name, err}
  58. }
  59. if n < syscall.STATFIXLEN {
  60. return nil, &PathError{"stat", name, syscall.ErrShortStat}
  61. }
  62. // Pull the real size out of the stat message.
  63. size = int(uint16(buf[0]) | uint16(buf[1])<<8)
  64. // If the stat message is larger than our buffer we will
  65. // go around the loop and allocate one that is big enough.
  66. if size > n {
  67. continue
  68. }
  69. d, err := syscall.UnmarshalDir(buf[:n])
  70. if err != nil {
  71. return nil, &PathError{"stat", name, err}
  72. }
  73. return d, nil
  74. }
  75. return nil, &PathError{"stat", name, syscall.ErrBadStat}
  76. }
  77. // Stat returns a FileInfo describing the named file.
  78. // If there is an error, it will be of type *PathError.
  79. func Stat(name string) (fi FileInfo, err error) {
  80. d, err := dirstat(name)
  81. if err != nil {
  82. return nil, err
  83. }
  84. return fileInfoFromStat(d), nil
  85. }
  86. // Lstat returns a FileInfo describing the named file.
  87. // If the file is a symbolic link, the returned FileInfo
  88. // describes the symbolic link. Lstat makes no attempt to follow the link.
  89. // If there is an error, it will be of type *PathError.
  90. func Lstat(name string) (fi FileInfo, err error) {
  91. return Stat(name)
  92. }
  93. // For testing.
  94. func atime(fi FileInfo) time.Time {
  95. return time.Unix(int64(fi.Sys().(*syscall.Dir).Atime), 0)
  96. }