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