Source file
src/os/stat_windows.go
1
2
3
4
5 package os
6
7 import (
8 "errors"
9 "internal/filepathlite"
10 "internal/syscall/windows"
11 "syscall"
12 "unsafe"
13 )
14
15
16
17 func (file *File) Stat() (FileInfo, error) {
18 if file == nil {
19 return nil, ErrInvalid
20 }
21 return statHandle(file.name, file.pfd.Sysfd)
22 }
23
24
25 func stat(funcname, name string, followSurrogates bool) (FileInfo, error) {
26 if len(name) == 0 {
27 return nil, &PathError{Op: funcname, Path: name, Err: syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
28 }
29 namep, err := syscall.UTF16PtrFromString(fixLongPath(name))
30 if err != nil {
31 return nil, &PathError{Op: funcname, Path: name, Err: err}
32 }
33
34
35
36 var fa syscall.Win32FileAttributeData
37 err = syscall.GetFileAttributesEx(namep, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa)))
38 if errors.Is(err, ErrNotExist) {
39 return nil, &PathError{Op: "GetFileAttributesEx", Path: name, Err: err}
40 }
41 if err == nil && fa.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
42
43
44 fs := newFileStatFromWin32FileAttributeData(&fa)
45 if err := fs.saveInfoFromPath(name); err != nil {
46 return nil, err
47 }
48 return fs, nil
49 }
50
51
52
53 if err == windows.ERROR_SHARING_VIOLATION {
54 var fd syscall.Win32finddata
55 sh, err := syscall.FindFirstFile(namep, &fd)
56 if err != nil {
57 return nil, &PathError{Op: "FindFirstFile", Path: name, Err: err}
58 }
59 syscall.FindClose(sh)
60 if fd.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
61
62 fs := newFileStatFromWin32finddata(&fd)
63 if err := fs.saveInfoFromPath(name); err != nil {
64 return nil, err
65 }
66 return fs, nil
67 }
68 }
69
70
71
72
73
74 var flags uint32 = syscall.FILE_FLAG_BACKUP_SEMANTICS | syscall.FILE_FLAG_OPEN_REPARSE_POINT
75 h, err := syscall.CreateFile(namep, 0, 0, nil, syscall.OPEN_EXISTING, flags, 0)
76
77 if err == windows.ERROR_INVALID_PARAMETER {
78
79
80
81
82 h, err = syscall.CreateFile(namep, syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING, flags, 0)
83 }
84 if err != nil {
85
86
87
88 return nil, &PathError{Op: "CreateFile", Path: name, Err: err}
89 }
90
91 fi, err := statHandle(name, h)
92 syscall.CloseHandle(h)
93 if err == nil && followSurrogates && fi.(*fileStat).isReparseTagNameSurrogate() {
94
95
96
97 h, err = syscall.CreateFile(namep, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
98 if err != nil {
99
100 return nil, &PathError{Op: "CreateFile", Path: name, Err: err}
101 }
102 defer syscall.CloseHandle(h)
103 return statHandle(name, h)
104 }
105 return fi, err
106 }
107
108 func statHandle(name string, h syscall.Handle) (FileInfo, error) {
109 ft, err := syscall.GetFileType(h)
110 if err != nil {
111 return nil, &PathError{Op: "GetFileType", Path: name, Err: err}
112 }
113 switch ft {
114 case syscall.FILE_TYPE_PIPE, syscall.FILE_TYPE_CHAR:
115 return &fileStat{name: filepathlite.Base(name), filetype: ft}, nil
116 }
117 fs, err := newFileStatFromGetFileInformationByHandle(name, h)
118 if err != nil {
119 return nil, err
120 }
121 fs.filetype = ft
122 return fs, nil
123 }
124
125
126 func statNolog(name string) (FileInfo, error) {
127 return stat("Stat", name, true)
128 }
129
130
131 func lstatNolog(name string) (FileInfo, error) {
132 followSurrogates := false
133 if name != "" && IsPathSeparator(name[len(name)-1]) {
134
135
136
137
138
139 followSurrogates = true
140 }
141 return stat("Lstat", name, followSurrogates)
142 }
143
View as plain text