Fix "PR c++/92804 ICE trying to use concept as a nested-name-specifier"
[official-gcc.git] / libgo / go / os / types_windows.go
blob3d1a6674b145881014d1b7a07cb41fe9935a3ea7
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.
5 package os
7 import (
8 "internal/syscall/windows"
9 "sync"
10 "syscall"
11 "time"
12 "unsafe"
15 // A fileStat is the implementation of FileInfo returned by Stat and Lstat.
16 type fileStat struct {
17 name string
19 // from ByHandleFileInformation, Win32FileAttributeData and Win32finddata
20 FileAttributes uint32
21 CreationTime syscall.Filetime
22 LastAccessTime syscall.Filetime
23 LastWriteTime syscall.Filetime
24 FileSizeHigh uint32
25 FileSizeLow uint32
27 // from Win32finddata
28 Reserved0 uint32
30 // what syscall.GetFileType returns
31 filetype uint32
33 // used to implement SameFile
34 sync.Mutex
35 path string
36 vol uint32
37 idxhi uint32
38 idxlo uint32
39 appendNameToPath bool
42 // newFileStatFromGetFileInformationByHandle calls GetFileInformationByHandle
43 // to gather all required information about the file handle h.
44 func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (fs *fileStat, err error) {
45 var d syscall.ByHandleFileInformation
46 err = syscall.GetFileInformationByHandle(h, &d)
47 if err != nil {
48 return nil, &PathError{"GetFileInformationByHandle", path, err}
51 var ti windows.FILE_ATTRIBUTE_TAG_INFO
52 err = windows.GetFileInformationByHandleEx(h, windows.FileAttributeTagInfo, (*byte)(unsafe.Pointer(&ti)), uint32(unsafe.Sizeof(ti)))
53 if err != nil {
54 if errno, ok := err.(syscall.Errno); ok && errno == windows.ERROR_INVALID_PARAMETER {
55 // It appears calling GetFileInformationByHandleEx with
56 // FILE_ATTRIBUTE_TAG_INFO fails on FAT file system with
57 // ERROR_INVALID_PARAMETER. Clear ti.ReparseTag in that
58 // instance to indicate no symlinks are possible.
59 ti.ReparseTag = 0
60 } else {
61 return nil, &PathError{"GetFileInformationByHandleEx", path, err}
65 return &fileStat{
66 name: basename(path),
67 FileAttributes: d.FileAttributes,
68 CreationTime: d.CreationTime,
69 LastAccessTime: d.LastAccessTime,
70 LastWriteTime: d.LastWriteTime,
71 FileSizeHigh: d.FileSizeHigh,
72 FileSizeLow: d.FileSizeLow,
73 vol: d.VolumeSerialNumber,
74 idxhi: d.FileIndexHigh,
75 idxlo: d.FileIndexLow,
76 Reserved0: ti.ReparseTag,
77 // fileStat.path is used by os.SameFile to decide if it needs
78 // to fetch vol, idxhi and idxlo. But these are already set,
79 // so set fileStat.path to "" to prevent os.SameFile doing it again.
80 }, nil
83 // newFileStatFromWin32finddata copies all required information
84 // from syscall.Win32finddata d into the newly created fileStat.
85 func newFileStatFromWin32finddata(d *syscall.Win32finddata) *fileStat {
86 return &fileStat{
87 FileAttributes: d.FileAttributes,
88 CreationTime: d.CreationTime,
89 LastAccessTime: d.LastAccessTime,
90 LastWriteTime: d.LastWriteTime,
91 FileSizeHigh: d.FileSizeHigh,
92 FileSizeLow: d.FileSizeLow,
93 Reserved0: d.Reserved0,
97 func (fs *fileStat) isSymlink() bool {
98 // Use instructions described at
99 // https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/
100 // to recognize whether it's a symlink.
101 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
102 return false
104 return fs.Reserved0 == syscall.IO_REPARSE_TAG_SYMLINK ||
105 fs.Reserved0 == windows.IO_REPARSE_TAG_MOUNT_POINT
108 func (fs *fileStat) Size() int64 {
109 return int64(fs.FileSizeHigh)<<32 + int64(fs.FileSizeLow)
112 func (fs *fileStat) Mode() (m FileMode) {
113 if fs == &devNullStat {
114 return ModeDevice | ModeCharDevice | 0666
116 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
117 m |= 0444
118 } else {
119 m |= 0666
121 if fs.isSymlink() {
122 return m | ModeSymlink
124 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
125 m |= ModeDir | 0111
127 switch fs.filetype {
128 case syscall.FILE_TYPE_PIPE:
129 m |= ModeNamedPipe
130 case syscall.FILE_TYPE_CHAR:
131 m |= ModeDevice | ModeCharDevice
133 return m
136 func (fs *fileStat) ModTime() time.Time {
137 return time.Unix(0, fs.LastWriteTime.Nanoseconds())
140 // Sys returns syscall.Win32FileAttributeData for file fs.
141 func (fs *fileStat) Sys() interface{} {
142 return &syscall.Win32FileAttributeData{
143 FileAttributes: fs.FileAttributes,
144 CreationTime: fs.CreationTime,
145 LastAccessTime: fs.LastAccessTime,
146 LastWriteTime: fs.LastWriteTime,
147 FileSizeHigh: fs.FileSizeHigh,
148 FileSizeLow: fs.FileSizeLow,
152 func (fs *fileStat) loadFileId() error {
153 fs.Lock()
154 defer fs.Unlock()
155 if fs.path == "" {
156 // already done
157 return nil
159 var path string
160 if fs.appendNameToPath {
161 path = fs.path + `\` + fs.name
162 } else {
163 path = fs.path
165 pathp, err := syscall.UTF16PtrFromString(path)
166 if err != nil {
167 return err
169 attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
170 if fs.isSymlink() {
171 // Use FILE_FLAG_OPEN_REPARSE_POINT, otherwise CreateFile will follow symlink.
172 // See https://docs.microsoft.com/en-us/windows/desktop/FileIO/symbolic-link-effects-on-file-systems-functions#createfile-and-createfiletransacted
173 attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT
175 h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0)
176 if err != nil {
177 return err
179 defer syscall.CloseHandle(h)
180 var i syscall.ByHandleFileInformation
181 err = syscall.GetFileInformationByHandle(h, &i)
182 if err != nil {
183 return err
185 fs.path = ""
186 fs.vol = i.VolumeSerialNumber
187 fs.idxhi = i.FileIndexHigh
188 fs.idxlo = i.FileIndexLow
189 return nil
192 // saveInfoFromPath saves full path of the file to be used by os.SameFile later,
193 // and set name from path.
194 func (fs *fileStat) saveInfoFromPath(path string) error {
195 fs.path = path
196 if !isAbs(fs.path) {
197 var err error
198 fs.path, err = syscall.FullPath(fs.path)
199 if err != nil {
200 return &PathError{"FullPath", path, err}
203 fs.name = basename(path)
204 return nil
207 // devNullStat is fileStat structure describing DevNull file ("NUL").
208 var devNullStat = fileStat{
209 name: DevNull,
210 // hopefully this will work for SameFile
211 vol: 0,
212 idxhi: 0,
213 idxlo: 0,
216 func sameFile(fs1, fs2 *fileStat) bool {
217 e := fs1.loadFileId()
218 if e != nil {
219 return false
221 e = fs2.loadFileId()
222 if e != nil {
223 return false
225 return fs1.vol == fs2.vol && fs1.idxhi == fs2.idxhi && fs1.idxlo == fs2.idxlo
228 // For testing.
229 func atime(fi FileInfo) time.Time {
230 return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())