Source file
src/os/types_windows.go
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 Reserved0 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 Reserved0: ti.ReparseTag,
77
78
79
80 }, nil
81 }
82
83
84
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,
94 }
95 }
96
97 func (fs *fileStat) isSymlink() bool {
98
99
100
101 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
102 return false
103 }
104 return fs.Reserved0 == syscall.IO_REPARSE_TAG_SYMLINK ||
105 fs.Reserved0 == windows.IO_REPARSE_TAG_MOUNT_POINT
106 }
107
108 func (fs *fileStat) Size() int64 {
109 return int64(fs.FileSizeHigh)<<32 + int64(fs.FileSizeLow)
110 }
111
112 func (fs *fileStat) Mode() (m FileMode) {
113 if fs == &devNullStat {
114 return ModeDevice | ModeCharDevice | 0666
115 }
116 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
117 m |= 0444
118 } else {
119 m |= 0666
120 }
121 if fs.isSymlink() {
122 return m | ModeSymlink
123 }
124 if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
125 m |= ModeDir | 0111
126 }
127 switch fs.filetype {
128 case syscall.FILE_TYPE_PIPE:
129 m |= ModeNamedPipe
130 case syscall.FILE_TYPE_CHAR:
131 m |= ModeDevice | ModeCharDevice
132 }
133 return m
134 }
135
136 func (fs *fileStat) ModTime() time.Time {
137 return time.Unix(0, fs.LastWriteTime.Nanoseconds())
138 }
139
140
141 func (fs *fileStat) Sys() any {
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,
149 }
150 }
151
152 func (fs *fileStat) loadFileId() error {
153 fs.Lock()
154 defer fs.Unlock()
155 if fs.path == "" {
156
157 return nil
158 }
159 var path string
160 if fs.appendNameToPath {
161 path = fs.path + `\` + fs.name
162 } else {
163 path = fs.path
164 }
165 pathp, err := syscall.UTF16PtrFromString(path)
166 if err != nil {
167 return err
168 }
169 attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
170 if fs.isSymlink() {
171
172
173 attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT
174 }
175 h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0)
176 if err != nil {
177 return err
178 }
179 defer syscall.CloseHandle(h)
180 var i syscall.ByHandleFileInformation
181 err = syscall.GetFileInformationByHandle(h, &i)
182 if err != nil {
183 return err
184 }
185 fs.path = ""
186 fs.vol = i.VolumeSerialNumber
187 fs.idxhi = i.FileIndexHigh
188 fs.idxlo = i.FileIndexLow
189 return nil
190 }
191
192
193
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{Op: "FullPath", Path: path, Err: err}
201 }
202 }
203 fs.name = basename(path)
204 return nil
205 }
206
207
208 var devNullStat = fileStat{
209 name: DevNull,
210
211 vol: 0,
212 idxhi: 0,
213 idxlo: 0,
214 }
215
216 func sameFile(fs1, fs2 *fileStat) bool {
217 e := fs1.loadFileId()
218 if e != nil {
219 return false
220 }
221 e = fs2.loadFileId()
222 if e != nil {
223 return false
224 }
225 return fs1.vol == fs2.vol && fs1.idxhi == fs2.idxhi && fs1.idxlo == fs2.idxlo
226 }
227
228
229 func atime(fi FileInfo) time.Time {
230 return time.Unix(0, fi.Sys().(*syscall.Win32FileAttributeData).LastAccessTime.Nanoseconds())
231 }
232
View as plain text