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