1// Copyright 2009 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 7import ( 8 "sync" 9 "syscall" 10 "time" 11) 12 13// A fileStat is the implementation of FileInfo returned by Stat and Lstat. 14type fileStat struct { 15 name string 16 sys syscall.Win32FileAttributeData 17 18 // used to implement SameFile 19 sync.Mutex 20 path string 21 vol uint32 22 idxhi uint32 23 idxlo uint32 24} 25 26func (fs *fileStat) Size() int64 { 27 return int64(fs.sys.FileSizeHigh)<<32 + int64(fs.sys.FileSizeLow) 28} 29 30func (fs *fileStat) Mode() (m FileMode) { 31 if fs == &devNullStat { 32 return ModeDevice | ModeCharDevice | 0666 33 } 34 if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 { 35 m |= ModeDir | 0111 36 } 37 if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 { 38 m |= 0444 39 } else { 40 m |= 0666 41 } 42 if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 { 43 m |= ModeSymlink 44 } 45 return m 46} 47 48func (fs *fileStat) ModTime() time.Time { 49 return time.Unix(0, fs.sys.LastWriteTime.Nanoseconds()) 50} 51 52// Sys returns syscall.Win32FileAttributeData for file fs. 53func (fs *fileStat) Sys() interface{} { return &fs.sys } 54 55func (fs *fileStat) loadFileId() error { 56 fs.Lock() 57 defer fs.Unlock() 58 if fs.path == "" { 59 // already done 60 return nil 61 } 62 pathp, err := syscall.UTF16PtrFromString(fs.path) 63 if err != nil { 64 return err 65 } 66 h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) 67 if err != nil { 68 return err 69 } 70 defer syscall.CloseHandle(h) 71 var i syscall.ByHandleFileInformation 72 err = syscall.GetFileInformationByHandle(syscall.Handle(h), &i) 73 if err != nil { 74 return err 75 } 76 fs.path = "" 77 fs.vol = i.VolumeSerialNumber 78 fs.idxhi = i.FileIndexHigh 79 fs.idxlo = i.FileIndexLow 80 return nil 81} 82 83// devNullStat is fileStat structure describing DevNull file ("NUL"). 84var devNullStat = fileStat{ 85 name: DevNull, 86 // hopefully this will work for SameFile 87 vol: 0, 88 idxhi: 0, 89 idxlo: 0, 90} 91 92func sameFile(fs1, fs2 *fileStat) bool { 93 e := fs1.loadFileId() 94 if e != nil { 95 return false 96 } 97 e = fs2.loadFileId() 98 if e != nil { 99 return false 100 } 101 return fs1.vol == fs2.vol && fs1.idxhi == fs2.idxhi && fs1.idxlo == fs2.idxlo 102} 103 104// For testing. 105func atime(fi FileInfo) time.Time { 106 return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds()) 107} 108