Source file
src/os/types_windows.go
1
2
3
4
5 package os
6
7 import (
8 "internal/godebug"
9 "internal/syscall/windows"
10 "sync"
11 "syscall"
12 "time"
13 "unsafe"
14 )
15
16
17 type fileStat struct {
18 name string
19
20
21 FileAttributes uint32
22 CreationTime syscall.Filetime
23 LastAccessTime syscall.Filetime
24 LastWriteTime syscall.Filetime
25 FileSizeHigh uint32
26 FileSizeLow uint32
27
28
29 ReparseTag uint32
30
31
32 filetype uint32
33
34
35 sync.Mutex
36 path string
37 vol uint32
38 idxhi uint32
39 idxlo uint32
40 appendNameToPath bool
41 }
42
43
44
45 func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (fs *fileStat, err error) {
46 var d syscall.ByHandleFileInformation
47 err = syscall.GetFileInformationByHandle(h, &d)
48 if err != nil {
49 return nil, &PathError{Op: "GetFileInformationByHandle", Path: path, Err: err}
50 }
51
52 var reparseTag uint32
53 if d.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
54 var ti windows.FILE_ATTRIBUTE_TAG_INFO
55 err = windows.GetFileInformationByHandleEx(h, windows.FileAttributeTagInfo, (*byte)(unsafe.Pointer(&ti)), uint32(unsafe.Sizeof(ti)))
56 if err != nil {
57 return nil, &PathError{Op: "GetFileInformationByHandleEx", Path: path, Err: err}
58 }
59 reparseTag = ti.ReparseTag
60 }
61
62 return &fileStat{
63 name: basename(path),
64 FileAttributes: d.FileAttributes,
65 CreationTime: d.CreationTime,
66 LastAccessTime: d.LastAccessTime,
67 LastWriteTime: d.LastWriteTime,
68 FileSizeHigh: d.FileSizeHigh,
69 FileSizeLow: d.FileSizeLow,
70 vol: d.VolumeSerialNumber,
71 idxhi: d.FileIndexHigh,
72 idxlo: d.FileIndexLow,
73 ReparseTag: reparseTag,
74
75
76
77 }, nil
78 }
79
80
81
82 func newFileStatFromWin32FileAttributeData(d *syscall.Win32FileAttributeData) *fileStat {
83 return &fileStat{
84 FileAttributes: d.FileAttributes,
85 CreationTime: d.CreationTime,
86 LastAccessTime: d.LastAccessTime,
87 LastWriteTime: d.LastWriteTime,
88 FileSizeHigh: d.FileSizeHigh,
89 FileSizeLow: d.FileSizeLow,
90 }
91 }
92
93
94
95 func newFileStatFromFileIDBothDirInfo(d *windows.FILE_ID_BOTH_DIR_INFO) *fileStat {
96
97
98
99
100 return &fileStat{
101 FileAttributes: d.FileAttributes,
102 CreationTime: d.CreationTime,
103 LastAccessTime: d.LastAccessTime,
104 LastWriteTime: d.LastWriteTime,
105 FileSizeHigh: uint32(d.EndOfFile >> 32),
106 FileSizeLow: uint32(d.EndOfFile),
107 ReparseTag: d.EaSize,
108 idxhi: uint32(d.FileID >> 32),
109 idxlo: uint32(d.FileID),
110 }
111 }
112
113
114
115 func newFileStatFromFileFullDirInfo(d *windows.FILE_FULL_DIR_INFO) *fileStat {
116 return &fileStat{
117 FileAttributes: d.FileAttributes,
118 CreationTime: d.CreationTime,
119 LastAccessTime: d.LastAccessTime,
120 LastWriteTime: d.LastWriteTime,
121 FileSizeHigh: uint32(d.EndOfFile >> 32),
122 FileSizeLow: uint32(d.EndOfFile),
123 ReparseTag: d.EaSize,
124 }
125 }
126
127
128
129 func newFileStatFromWin32finddata(d *syscall.Win32finddata) *fileStat {
130 fs := &fileStat{
131 FileAttributes: d.FileAttributes,
132 CreationTime: d.CreationTime,
133 LastAccessTime: d.LastAccessTime,
134 LastWriteTime: d.LastWriteTime,
135 FileSizeHigh: d.FileSizeHigh,
136 FileSizeLow: d.FileSizeLow,
137 }
138 if d.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
139
140
141
142
143 fs.ReparseTag = d.Reserved0
144 }
145 return fs
146 }
147
148
149
150
151
152
153 func (fs *fileStat) isReparseTagNameSurrogate() bool {
154
155 return fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 && fs.ReparseTag&0x20000000 != 0
156 }
157
158 func (fs *fileStat) Size() int64 {
159 return int64(fs.FileSizeHigh)<<32 + int64(fs.FileSizeLow)
160 }
161
162 var winsymlink = godebug.New("winsymlink")
163
164 func (fs *fileStat) Mode() FileMode {
165 m := fs.mode()
166 if winsymlink.Value() == "0" {
167 old := fs.modePreGo1_23()
168 if old != m {
169 winsymlink.IncNonDefault()
170 m = old
171 }
172 }
173 return m
174 }
175
176 func (fs *fileStat) mode() (m FileMode) {
177 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
178 m |= 0444
179 } else {
180 m |= 0666
181 }
182
183
184
185
186
187
188
189
190
191
192 if !fs.isReparseTagNameSurrogate() {
193 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
194 m |= ModeDir | 0111
195 }
196
197 switch fs.filetype {
198 case syscall.FILE_TYPE_PIPE:
199 m |= ModeNamedPipe
200 case syscall.FILE_TYPE_CHAR:
201 m |= ModeDevice | ModeCharDevice
202 }
203 }
204
205 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
206 switch fs.ReparseTag {
207 case syscall.IO_REPARSE_TAG_SYMLINK:
208 m |= ModeSymlink
209 case windows.IO_REPARSE_TAG_AF_UNIX:
210 m |= ModeSocket
211 case windows.IO_REPARSE_TAG_DEDUP:
212
213
214
215
216
217
218
219
220
221
222
223
224
225 default:
226 m |= ModeIrregular
227 }
228 }
229 return
230 }
231
232
233
234
235
236 func (fs *fileStat) modePreGo1_23() (m FileMode) {
237 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
238 m |= 0444
239 } else {
240 m |= 0666
241 }
242 if fs.ReparseTag == syscall.IO_REPARSE_TAG_SYMLINK ||
243 fs.ReparseTag == windows.IO_REPARSE_TAG_MOUNT_POINT {
244 return m | ModeSymlink
245 }
246 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
247 m |= ModeDir | 0111
248 }
249 switch fs.filetype {
250 case syscall.FILE_TYPE_PIPE:
251 m |= ModeNamedPipe
252 case syscall.FILE_TYPE_CHAR:
253 m |= ModeDevice | ModeCharDevice
254 }
255 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
256 if fs.ReparseTag == windows.IO_REPARSE_TAG_AF_UNIX {
257 m |= ModeSocket
258 }
259 if m&ModeType == 0 {
260 if fs.ReparseTag == windows.IO_REPARSE_TAG_DEDUP {
261
262 } else {
263 m |= ModeIrregular
264 }
265 }
266 }
267 return m
268 }
269
270 func (fs *fileStat) ModTime() time.Time {
271 return time.Unix(0, fs.LastWriteTime.Nanoseconds())
272 }
273
274
275 func (fs *fileStat) Sys() any {
276 return &syscall.Win32FileAttributeData{
277 FileAttributes: fs.FileAttributes,
278 CreationTime: fs.CreationTime,
279 LastAccessTime: fs.LastAccessTime,
280 LastWriteTime: fs.LastWriteTime,
281 FileSizeHigh: fs.FileSizeHigh,
282 FileSizeLow: fs.FileSizeLow,
283 }
284 }
285
286 func (fs *fileStat) loadFileId() error {
287 fs.Lock()
288 defer fs.Unlock()
289 if fs.path == "" {
290
291 return nil
292 }
293 var path string
294 if fs.appendNameToPath {
295 path = fixLongPath(fs.path + `\` + fs.name)
296 } else {
297 path = fs.path
298 }
299 pathp, err := syscall.UTF16PtrFromString(path)
300 if err != nil {
301 return err
302 }
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318 attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS | syscall.FILE_FLAG_OPEN_REPARSE_POINT)
319
320 h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0)
321 if err != nil {
322 return err
323 }
324 defer syscall.CloseHandle(h)
325 var i syscall.ByHandleFileInformation
326 err = syscall.GetFileInformationByHandle(h, &i)
327 if err != nil {
328 return err
329 }
330 fs.path = ""
331 fs.vol = i.VolumeSerialNumber
332 fs.idxhi = i.FileIndexHigh
333 fs.idxlo = i.FileIndexLow
334 return nil
335 }
336
337
338
339 func (fs *fileStat) saveInfoFromPath(path string) error {
340 fs.path = path
341 if !isAbs(fs.path) {
342 var err error
343 fs.path, err = syscall.FullPath(fs.path)
344 if err != nil {
345 return &PathError{Op: "FullPath", Path: path, Err: err}
346 }
347 }
348 fs.name = basename(path)
349 return nil
350 }
351
352 func sameFile(fs1, fs2 *fileStat) bool {
353 e := fs1.loadFileId()
354 if e != nil {
355 return false
356 }
357 e = fs2.loadFileId()
358 if e != nil {
359 return false
360 }
361 return fs1.vol == fs2.vol && fs1.idxhi == fs2.idxhi && fs1.idxlo == fs2.idxlo
362 }
363
364
365 func atime(fi FileInfo) time.Time {
366 return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
367 }
368
View as plain text