// Copyright 2009 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 ( "sync" "syscall" "time" ) // A fileStat is the implementation of FileInfo returned by Stat and Lstat. type fileStat struct { name string sys syscall.Win32FileAttributeData // used to implement SameFile sync.Mutex path string vol uint32 idxhi uint32 idxlo uint32 } func (fs *fileStat) Size() int64 { return int64(fs.sys.FileSizeHigh)<<32 + int64(fs.sys.FileSizeLow) } func (fs *fileStat) Mode() (m FileMode) { if fs == &devNullStat { return ModeDevice | ModeCharDevice | 0666 } if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { m |= ModeDir | 0111 } if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 { m |= 0444 } else { m |= 0666 } if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { m |= ModeSymlink } return m } func (fs *fileStat) ModTime() time.Time { return time.Unix(0, fs.sys.LastWriteTime.Nanoseconds()) } // Sys returns syscall.Win32FileAttributeData for file fs. func (fs *fileStat) Sys() interface{} { return &fs.sys } func (fs *fileStat) loadFileId() error { fs.Lock() defer fs.Unlock() if fs.path == "" { // already done return nil } pathp, err := syscall.UTF16PtrFromString(fs.path) if err != nil { return err } h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) if err != nil { return err } defer syscall.CloseHandle(h) var i syscall.ByHandleFileInformation err = syscall.GetFileInformationByHandle(syscall.Handle(h), &i) if err != nil { return err } fs.path = "" fs.vol = i.VolumeSerialNumber fs.idxhi = i.FileIndexHigh fs.idxlo = i.FileIndexLow return nil } // devNullStat is fileStat structure describing DevNull file ("NUL"). var devNullStat = fileStat{ name: DevNull, // hopefully this will work for SameFile vol: 0, idxhi: 0, idxlo: 0, } func sameFile(fs1, fs2 *fileStat) bool { e := fs1.loadFileId() if e != nil { return false } e = fs2.loadFileId() if e != nil { return false } return fs1.vol == fs2.vol && fs1.idxhi == fs2.idxhi && fs1.idxlo == fs2.idxlo } // For testing. func atime(fi FileInfo) time.Time { return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) }