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