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