lin
2025-06-05 ed3dd9d3e7519a82bb871d5eedb24a2fa0c91f47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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) FileInfo {
   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 interface{}) (*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{"stat", name, 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{"stat", name, err}
           }
           return d, nil
       }
 
   }
 
   if err == nil {
       err = syscall.ErrBadStat
   }
 
   return nil, &PathError{"stat", name, 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)
}