blob: fa4bd83aefb25d48e7cdbea5d67de985206a851e [file] [log] [blame]
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -07001// 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
5package os
6
Anthony Martin2c2a5822011-12-12 16:14:00 -05007import (
8 "syscall"
9 "time"
10)
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070011
David du Colombier2a74f432015-01-25 02:19:39 +010012const _BIT16SZ = 2
13
Alex Brainmanbd754682013-01-31 17:17:37 +110014func sameFile(fs1, fs2 *fileStat) bool {
15 a := fs1.sys.(*syscall.Dir)
16 b := fs2.sys.(*syscall.Dir)
Anthony Martin2c2a5822011-12-12 16:14:00 -050017 return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
18}
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070019
Anthony Martin4ce3df52012-11-26 15:26:46 -080020func fileInfoFromStat(d *syscall.Dir) FileInfo {
Gustavo Niemeyer20f43852012-02-03 00:16:18 -020021 fs := &fileStat{
Anthony Martin2c2a5822011-12-12 16:14:00 -050022 name: d.Name,
23 size: int64(d.Length),
24 modTime: time.Unix(int64(d.Mtime), 0),
Gustavo Niemeyer20f43852012-02-03 00:16:18 -020025 sys: d,
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070026 }
Anthony Martin2c2a5822011-12-12 16:14:00 -050027 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 Zholkoverc256f0a2011-04-02 14:28:58 -070041}
42
Robert Griesemer465b9c32012-10-30 13:38:01 -070043// arg is an open *File or a path string.
Anthony Martin4ce3df52012-11-26 15:26:46 -080044func dirstat(arg interface{}) (*syscall.Dir, error) {
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070045 var name string
David du Colombier2a74f432015-01-25 02:19:39 +010046 var err error
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070047
David du Colombier2a74f432015-01-25 02:19:39 +010048 size := syscall.STATFIXLEN + 16*4
Anthony Martin2c2a5822011-12-12 16:14:00 -050049
50 for i := 0; i < 2; i++ {
David du Colombier2a74f432015-01-25 02:19:39 +010051 buf := make([]byte, _BIT16SZ+size)
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070052
53 var n int
Anthony Martin2c2a5822011-12-12 16:14:00 -050054 switch a := arg.(type) {
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070055 case *File:
Anthony Martin2c2a5822011-12-12 16:14:00 -050056 name = a.name
57 n, err = syscall.Fstat(a.fd, buf)
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070058 case string:
Anthony Martin2c2a5822011-12-12 16:14:00 -050059 name = a
Anthony Martin4ce3df52012-11-26 15:26:46 -080060 n, err = syscall.Stat(a, buf)
61 default:
62 panic("phase error in dirstat")
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070063 }
David du Colombier2a74f432015-01-25 02:19:39 +010064
65 if n < _BIT16SZ {
David du Colombierbd8e3d02015-06-10 22:32:14 +020066 return nil, &PathError{"stat", name, err}
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070067 }
68
Anthony Martin2c2a5822011-12-12 16:14:00 -050069 // Pull the real size out of the stat message.
Anthony Martin4ce3df52012-11-26 15:26:46 -080070 size = int(uint16(buf[0]) | uint16(buf[1])<<8)
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070071
Anthony Martin2c2a5822011-12-12 16:14:00 -050072 // 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 Colombier2a74f432015-01-25 02:19:39 +010074 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 Zholkoverc256f0a2011-04-02 14:28:58 -070080 }
Anthony Martin4ce3df52012-11-26 15:26:46 -080081
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070082 }
David du Colombier2a74f432015-01-25 02:19:39 +010083
84 if err == nil {
85 err = syscall.ErrBadStat
86 }
87
88 return nil, &PathError{"stat", name, err}
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070089}
90
Anthony Martin90626862012-05-01 22:44:38 -070091// Stat returns a FileInfo describing the named file.
Rob Pikebe0f6fe2012-02-09 16:55:36 +110092// If there is an error, it will be of type *PathError.
Brad Fitzpatrick90c668d2015-07-17 08:26:29 -070093func Stat(name string) (FileInfo, error) {
Yuval Pavel Zholkover18112432011-06-14 11:20:34 -040094 d, err := dirstat(name)
Russ Coxc017a822011-11-13 22:44:52 -050095 if err != nil {
Yuval Pavel Zholkover18112432011-06-14 11:20:34 -040096 return nil, err
97 }
Anthony Martin2c2a5822011-12-12 16:14:00 -050098 return fileInfoFromStat(d), nil
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -070099}
100
Anthony Martin90626862012-05-01 22:44:38 -0700101// 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 Pikebe0f6fe2012-02-09 16:55:36 +1100104// If there is an error, it will be of type *PathError.
Brad Fitzpatrick90c668d2015-07-17 08:26:29 -0700105func Lstat(name string) (FileInfo, error) {
Anthony Martin2c2a5822011-12-12 16:14:00 -0500106 return Stat(name)
Yuval Pavel Zholkoverc256f0a2011-04-02 14:28:58 -0700107}
Fazlul Shahriarc93ca602012-01-25 00:15:44 -0800108
109// For testing.
110func atime(fi FileInfo) time.Time {
Anthony Martin4ce3df52012-11-26 15:26:46 -0800111 return time.Unix(int64(fi.Sys().(*syscall.Dir).Atime), 0)
Fazlul Shahriarc93ca602012-01-25 00:15:44 -0800112}