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