func (fi *fileInfo) Size() int64 { return fi.size }
func (fi *fileInfo) ModTime() time.Time { return fi.mtime }
func (fi *fileInfo) IsDir() bool { return fi.mode.IsDir() }
+func (fi *fileInfo) Sys() interface{} { return nil }
// httpZipFile is the zip-file based implementation of http.File
type httpZipFile struct {
return fi.file == nil
}
+func (fi zipFI) Sys() interface{} {
+ return nil
+}
+
// zipFS is the zip-file based implementation of FileSystem
type zipFS struct {
*zip.ReadCloser
func (fi headerFileInfo) IsDir() bool { return fi.Mode().IsDir() }
func (fi headerFileInfo) ModTime() time.Time { return fi.fh.ModTime() }
func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
+func (fi headerFileInfo) Sys() interface{} { return fi.fh }
// FileInfoHeader creates a partially-populated FileHeader from an
// os.FileInfo.
if !reflect.DeepEqual(fh, fh2) {
t.Errorf("mismatch\n input=%#v\noutput=%#v\nerr=%v", fh, fh2, err)
}
+ if sysfh, ok := fi.Sys().(*FileHeader); !ok && sysfh != fh {
+ t.Errorf("Sys didn't return original *FileHeader")
+ }
}
if err != nil {
t.Fatalf("stat of %s: %v", name, err)
}
- if !gfi.(*os.FileStat).SameFile(wfi.(*os.FileStat)) {
+ if !os.SameFile(gfi, wfi) {
t.Errorf("%s got different file", name)
}
}
if err == nil {
fi[i] = fip
} else {
- fi[i] = &FileStat{name: filename}
+ fi[i] = &fileStat{name: filename}
}
}
return fi, err
pwd = Getenv("PWD")
if len(pwd) > 0 && pwd[0] == '/' {
d, err := Stat(pwd)
- if err == nil && dot.(*FileStat).SameFile(d.(*FileStat)) {
+ if err == nil && SameFile(dot, d) {
return pwd, nil
}
}
// Can't stat root - no hope.
return "", err
}
- if root.(*FileStat).SameFile(dot.(*FileStat)) {
+ if SameFile(root, dot) {
return "/", nil
}
}
for _, name := range names {
d, _ := Lstat(parent + "/" + name)
- if d.(*FileStat).SameFile(dot.(*FileStat)) {
+ if SameFile(d, dot) {
pwd = "/" + name + pwd
goto Found
}
return "", err
}
fd.Close()
- if pd.(*FileStat).SameFile(root.(*FileStat)) {
+ if SameFile(pd, root) {
break
}
// Set up for next round.
if err != nil {
t.Fatalf("stat %q failed: %v", from, err)
}
- if !tostat.(*FileStat).SameFile(fromstat.(*FileStat)) {
+ if !SameFile(tostat, fromstat) {
t.Errorf("link %q, %q did not create hard link", to, from)
}
}
if err != nil {
t.Fatalf("stat %q failed: %v", from, err)
}
- if !tostat.(*FileStat).SameFile(fromstat.(*FileStat)) {
+ if !SameFile(tostat, fromstat) {
t.Errorf("symlink %q, %q did not create symlink", to, from)
}
fromstat, err = Lstat(from)
if err != nil {
t.Fatalf("Stat %s: %s", f.Name(), err)
}
- preStat := st.(*FileStat)
+ preStat := st
// Move access and modification time back a second
at := Atime(preStat)
if err != nil {
t.Fatalf("second Stat %s: %s", f.Name(), err)
}
- postStat := st.(*FileStat)
+ postStat := st
/* Plan 9:
Mtime is the time of the last change of content. Similarly, atime is set whenever the
if err != nil {
t.Fatalf("Stat %q (looking for uid/gid %d/%d): %s", path, uid, gid, err)
}
- sys := dir.(*FileStat).Sys.(*syscall.Stat_t)
+ sys := dir.Sys().(*syscall.Stat_t)
if int(sys.Uid) != uid {
t.Errorf("Stat %q: uid %d want %d", path, sys.Uid, uid)
}
if err = Chown(f.Name(), -1, gid); err != nil {
t.Fatalf("chown %s -1 %d: %s", f.Name(), gid, err)
}
- sys := dir.(*FileStat).Sys.(*syscall.Stat_t)
+ sys := dir.Sys().(*syscall.Stat_t)
checkUidGid(t, f.Name(), int(sys.Uid), gid)
// Then try all the auxiliary groups.
"time"
)
-func sameFile(fs1, fs2 *FileStat) bool {
- sys1 := fs1.Sys.(*syscall.Stat_t)
- sys2 := fs2.Sys.(*syscall.Stat_t)
- return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
- fs := &FileStat{
+ fs := &fileStat{
name: basename(name),
size: int64(st.Size),
modTime: timespecToTime(st.Mtimespec),
- Sys: st,
+ sys: st,
}
fs.mode = FileMode(st.Mode & 0777)
switch st.Mode & syscall.S_IFMT {
// For testing.
func atime(fi FileInfo) time.Time {
- return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atimespec)
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atimespec)
}
"time"
)
-func sameFile(fs1, fs2 *FileStat) bool {
- sys1 := fs1.Sys.(*syscall.Stat_t)
- sys2 := fs2.Sys.(*syscall.Stat_t)
- return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
- fs := &FileStat{
+ fs := &fileStat{
name: basename(name),
size: int64(st.Size),
modTime: timespecToTime(st.Mtimespec),
- Sys: st,
+ sys: st,
}
fs.mode = FileMode(st.Mode & 0777)
switch st.Mode & syscall.S_IFMT {
// For testing.
func atime(fi FileInfo) time.Time {
- return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atimespec)
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atimespec)
}
"time"
)
-func sameFile(fs1, fs2 *FileStat) bool {
- sys1 := fs1.Sys.(*syscall.Stat_t)
- sys2 := fs2.Sys.(*syscall.Stat_t)
- return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
- fs := &FileStat{
+ fs := &fileStat{
name: basename(name),
size: int64(st.Size),
modTime: timespecToTime(st.Mtim),
- Sys: st,
+ sys: st,
}
fs.mode = FileMode(st.Mode & 0777)
switch st.Mode & syscall.S_IFMT {
// For testing.
func atime(fi FileInfo) time.Time {
- return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atim)
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
}
"time"
)
-func sameFile(fs1, fs2 *FileStat) bool {
- sys1 := fs1.Sys.(*syscall.Stat_t)
- sys2 := fs2.Sys.(*syscall.Stat_t)
- return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
- fs := &FileStat{
+ fs := &fileStat{
name: basename(name),
size: int64(st.Size),
modTime: timespecToTime(st.Mtim),
// For testing.
func atime(fi FileInfo) time.Time {
- return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atim)
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
}
"time"
)
-func sameFile(fs1, fs2 *FileStat) bool {
- sys1 := fs1.Sys.(*syscall.Stat_t)
- sys2 := fs2.Sys.(*syscall.Stat_t)
- return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
+func sameFile(sys1, sys2 interface{}) bool {
+ stat1 := sys1.(*syscall.Stat_t)
+ stat2 := sys2.(*syscall.Stat_t)
+ return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
}
func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
- fs := &FileStat{
+ fs := &fileStat{
name: basename(name),
size: int64(st.Size),
modTime: timespecToTime(st.Mtim),
- Sys: st,
+ sys: st,
}
fs.mode = FileMode(st.Mode & 0777)
switch st.Mode & syscall.S_IFMT {
// For testing.
func atime(fi FileInfo) time.Time {
- return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atim)
+ return timespecToTime(fi.Sys().(*syscall.Stat_t).Atim)
}
"time"
)
-func sameFile(fs1, fs2 *FileStat) bool {
- a := fs1.Sys.(*Dir)
- b := fs2.Sys.(*Dir)
+func sameFile(sys1, sys2 interface{}) bool {
+ a := sys1.(*Dir)
+ b := sys2.(*Dir)
return a.Qid.Path == b.Qid.Path && a.Type == b.Type && a.Dev == b.Dev
}
func fileInfoFromStat(d *Dir) FileInfo {
- fs := &FileStat{
+ fs := &fileStat{
name: d.Name,
size: int64(d.Length),
modTime: time.Unix(int64(d.Mtime), 0),
- Sys: d,
+ sys: d,
}
fs.mode = FileMode(d.Mode & 0777)
if d.Mode&syscall.DMDIR != 0 {
// For testing.
func atime(fi FileInfo) time.Time {
- return time.Unix(int64(fi.(*FileStat).Sys.(*Dir).Atime), 0)
+ return time.Unix(int64(fi.Sys().(*Dir).Atime), 0)
}
}
func toFileInfo(name string, fa, sizehi, sizelo uint32, ctime, atime, mtime syscall.Filetime) FileInfo {
- fs := new(FileStat)
- fs.mode = 0
+ fs := &fileStat{
+ name: name,
+ size: int64(sizehi)<<32 + int64(sizelo),
+ modTime: time.Unix(0, mtime.Nanoseconds()),
+ sys: &winTimes{atime, ctime},
+ }
if fa&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
fs.mode |= ModeDir
}
} else {
fs.mode |= 0666
}
- fs.size = int64(sizehi)<<32 + int64(sizelo)
- fs.name = name
- fs.modTime = time.Unix(0, mtime.Nanoseconds())
- fs.Sys = &winTimes{atime, ctime}
return fs
}
-func sameFile(fs1, fs2 *FileStat) bool {
+func sameFile(sys1, sys2 interface{}) bool {
// TODO(rsc): Do better than this, but this matches what
// used to happen when code compared .Dev and .Ino,
// which were both always zero. Obviously not all files
// For testing.
func atime(fi FileInfo) time.Time {
- return time.Unix(0, fi.(*FileStat).Sys.(*winTimes).atime.Nanoseconds())
+ return time.Unix(0, fi.Sys().(*winTimes).atime.Nanoseconds())
}
Mode() FileMode // file mode bits
ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
+ Sys() interface{} // underlying data source (can return nil)
}
// A FileMode represents a file's mode and permission bits.
return m & ModePerm
}
-// A FileStat is the implementation of FileInfo returned by Stat and Lstat.
-// Clients that need access to the underlying system-specific stat information
-// can test for *os.FileStat and then consult the Sys field.
-type FileStat struct {
+// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
+type fileStat struct {
name string
size int64
mode FileMode
modTime time.Time
-
- Sys interface{}
+ sys interface{}
}
-func (fs *FileStat) Name() string { return fs.name }
-func (fs *FileStat) Size() int64 { return fs.size }
-func (fs *FileStat) Mode() FileMode { return fs.mode }
-func (fs *FileStat) ModTime() time.Time { return fs.modTime }
-func (fs *FileStat) IsDir() bool { return fs.mode.IsDir() }
+func (fs *fileStat) Name() string { return fs.name }
+func (fs *fileStat) Size() int64 { return fs.size }
+func (fs *fileStat) Mode() FileMode { return fs.mode }
+func (fs *fileStat) ModTime() time.Time { return fs.modTime }
+func (fs *fileStat) IsDir() bool { return fs.mode.IsDir() }
+func (fs *fileStat) Sys() interface{} { return fs.sys }
-// SameFile reports whether fs and other describe the same file.
+// SameFile reports whether fi1 and fi2 describe the same file.
// For example, on Unix this means that the device and inode fields
// of the two underlying structures are identical; on other systems
// the decision may be based on the path names.
-func (fs *FileStat) SameFile(other *FileStat) bool {
- return sameFile(fs, other)
+// SameFile only applies to results returned by this package's Stat.
+// It returns false in other cases.
+func SameFile(fi1, fi2 FileInfo) bool {
+ fs1, ok1 := fi1.(*fileStat)
+ fs2, ok2 := fi2.(*fileStat)
+ if !ok1 || !ok2 {
+ return false
+ }
+ return sameFile(fs1.sys, fs2.sys)
}
continue
}
absinfo, err := os.Stat(abspath)
- if err != nil || !absinfo.(*os.FileStat).SameFile(info.(*os.FileStat)) {
+ if err != nil || !os.SameFile(absinfo, info) {
t.Errorf("Abs(%q)=%q, not the same file", path, abspath)
}
if !filepath.IsAbs(abspath) {