Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 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 | |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 7 | import ( |
| 8 | "syscall" |
| 9 | "time" |
| 10 | ) |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 11 | |
David du Colombier | 2a74f43 | 2015-01-25 02:19:39 +0100 | [diff] [blame] | 12 | const _BIT16SZ = 2 |
| 13 | |
Alex Brainman | bd75468 | 2013-01-31 17:17:37 +1100 | [diff] [blame] | 14 | func sameFile(fs1, fs2 *fileStat) bool { |
| 15 | a := fs1.sys.(*syscall.Dir) |
| 16 | b := fs2.sys.(*syscall.Dir) |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 17 | return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev |
| 18 | } |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 19 | |
Anthony Martin | 4ce3df5 | 2012-11-26 15:26:46 -0800 | [diff] [blame] | 20 | func fileInfoFromStat(d *syscall.Dir) FileInfo { |
Gustavo Niemeyer | 20f4385 | 2012-02-03 00:16:18 -0200 | [diff] [blame] | 21 | fs := &fileStat{ |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 22 | name: d.Name, |
| 23 | size: int64(d.Length), |
| 24 | modTime: time.Unix(int64(d.Mtime), 0), |
Gustavo Niemeyer | 20f4385 | 2012-02-03 00:16:18 -0200 | [diff] [blame] | 25 | sys: d, |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 26 | } |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 27 | fs.mode = FileMode(d.Mode & 0777) |
| 28 | if d.Mode&syscall.DMDIR != 0 { |
| 29 | fs.mode |= ModeDir |
| 30 | } |
| 31 | if d.Mode&syscall.DMAPPEND != 0 { |
| 32 | fs.mode |= ModeAppend |
| 33 | } |
| 34 | if d.Mode&syscall.DMEXCL != 0 { |
| 35 | fs.mode |= ModeExclusive |
| 36 | } |
| 37 | if d.Mode&syscall.DMTMP != 0 { |
| 38 | fs.mode |= ModeTemporary |
| 39 | } |
| 40 | return fs |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 41 | } |
| 42 | |
Robert Griesemer | 465b9c3 | 2012-10-30 13:38:01 -0700 | [diff] [blame] | 43 | // arg is an open *File or a path string. |
Anthony Martin | 4ce3df5 | 2012-11-26 15:26:46 -0800 | [diff] [blame] | 44 | func dirstat(arg interface{}) (*syscall.Dir, error) { |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 45 | var name string |
David du Colombier | 2a74f43 | 2015-01-25 02:19:39 +0100 | [diff] [blame] | 46 | var err error |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 47 | |
David du Colombier | 2a74f43 | 2015-01-25 02:19:39 +0100 | [diff] [blame] | 48 | size := syscall.STATFIXLEN + 16*4 |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 49 | |
| 50 | for i := 0; i < 2; i++ { |
David du Colombier | 2a74f43 | 2015-01-25 02:19:39 +0100 | [diff] [blame] | 51 | buf := make([]byte, _BIT16SZ+size) |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 52 | |
| 53 | var n int |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 54 | switch a := arg.(type) { |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 55 | case *File: |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 56 | name = a.name |
| 57 | n, err = syscall.Fstat(a.fd, buf) |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 58 | case string: |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 59 | name = a |
Anthony Martin | 4ce3df5 | 2012-11-26 15:26:46 -0800 | [diff] [blame] | 60 | n, err = syscall.Stat(a, buf) |
| 61 | default: |
| 62 | panic("phase error in dirstat") |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 63 | } |
David du Colombier | 2a74f43 | 2015-01-25 02:19:39 +0100 | [diff] [blame] | 64 | |
| 65 | if n < _BIT16SZ { |
David du Colombier | bd8e3d0 | 2015-06-10 22:32:14 +0200 | [diff] [blame] | 66 | return nil, &PathError{"stat", name, err} |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 67 | } |
| 68 | |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 69 | // Pull the real size out of the stat message. |
Anthony Martin | 4ce3df5 | 2012-11-26 15:26:46 -0800 | [diff] [blame] | 70 | size = int(uint16(buf[0]) | uint16(buf[1])<<8) |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 71 | |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 72 | // If the stat message is larger than our buffer we will |
| 73 | // go around the loop and allocate one that is big enough. |
David du Colombier | 2a74f43 | 2015-01-25 02:19:39 +0100 | [diff] [blame] | 74 | if size <= n { |
| 75 | d, err := syscall.UnmarshalDir(buf[:n]) |
| 76 | if err != nil { |
| 77 | return nil, &PathError{"stat", name, err} |
| 78 | } |
| 79 | return d, nil |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 80 | } |
Anthony Martin | 4ce3df5 | 2012-11-26 15:26:46 -0800 | [diff] [blame] | 81 | |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 82 | } |
David du Colombier | 2a74f43 | 2015-01-25 02:19:39 +0100 | [diff] [blame] | 83 | |
| 84 | if err == nil { |
| 85 | err = syscall.ErrBadStat |
| 86 | } |
| 87 | |
| 88 | return nil, &PathError{"stat", name, err} |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 89 | } |
| 90 | |
Anthony Martin | 9062686 | 2012-05-01 22:44:38 -0700 | [diff] [blame] | 91 | // Stat returns a FileInfo describing the named file. |
Rob Pike | be0f6fe | 2012-02-09 16:55:36 +1100 | [diff] [blame] | 92 | // If there is an error, it will be of type *PathError. |
Brad Fitzpatrick | 90c668d | 2015-07-17 08:26:29 -0700 | [diff] [blame] | 93 | func Stat(name string) (FileInfo, error) { |
Yuval Pavel Zholkover | 1811243 | 2011-06-14 11:20:34 -0400 | [diff] [blame] | 94 | d, err := dirstat(name) |
Russ Cox | c017a82 | 2011-11-13 22:44:52 -0500 | [diff] [blame] | 95 | if err != nil { |
Yuval Pavel Zholkover | 1811243 | 2011-06-14 11:20:34 -0400 | [diff] [blame] | 96 | return nil, err |
| 97 | } |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 98 | return fileInfoFromStat(d), nil |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 99 | } |
| 100 | |
Anthony Martin | 9062686 | 2012-05-01 22:44:38 -0700 | [diff] [blame] | 101 | // Lstat returns a FileInfo describing the named file. |
| 102 | // If the file is a symbolic link, the returned FileInfo |
| 103 | // describes the symbolic link. Lstat makes no attempt to follow the link. |
Rob Pike | be0f6fe | 2012-02-09 16:55:36 +1100 | [diff] [blame] | 104 | // If there is an error, it will be of type *PathError. |
Brad Fitzpatrick | 90c668d | 2015-07-17 08:26:29 -0700 | [diff] [blame] | 105 | func Lstat(name string) (FileInfo, error) { |
Anthony Martin | 2c2a582 | 2011-12-12 16:14:00 -0500 | [diff] [blame] | 106 | return Stat(name) |
Yuval Pavel Zholkover | c256f0a | 2011-04-02 14:28:58 -0700 | [diff] [blame] | 107 | } |
Fazlul Shahriar | c93ca60 | 2012-01-25 00:15:44 -0800 | [diff] [blame] | 108 | |
| 109 | // For testing. |
| 110 | func atime(fi FileInfo) time.Time { |
Anthony Martin | 4ce3df5 | 2012-11-26 15:26:46 -0800 | [diff] [blame] | 111 | return time.Unix(int64(fi.Sys().(*syscall.Dir).Atime), 0) |
Fazlul Shahriar | c93ca60 | 2012-01-25 00:15:44 -0800 | [diff] [blame] | 112 | } |