main
1//go:build windows
2
3package fs
4
5import (
6 "golang.org/x/sys/windows"
7
8 "github.com/Microsoft/go-winio/internal/stringbuffer"
9)
10
11//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go
12
13// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
14//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *windows.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW
15
16const NullHandle windows.Handle = 0
17
18// AccessMask defines standard, specific, and generic rights.
19//
20// Used with CreateFile and NtCreateFile (and co.).
21//
22// Bitmask:
23// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
24// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
25// +---------------+---------------+-------------------------------+
26// |G|G|G|G|Resvd|A| StandardRights| SpecificRights |
27// |R|W|E|A| |S| | |
28// +-+-------------+---------------+-------------------------------+
29//
30// GR Generic Read
31// GW Generic Write
32// GE Generic Exectue
33// GA Generic All
34// Resvd Reserved
35// AS Access Security System
36//
37// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask
38//
39// https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights
40//
41// https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
42type AccessMask = windows.ACCESS_MASK
43
44//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
45const (
46 // Not actually any.
47 //
48 // For CreateFile: "query certain metadata such as file, directory, or device attributes without accessing that file or device"
49 // https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters
50 FILE_ANY_ACCESS AccessMask = 0
51
52 GENERIC_READ AccessMask = 0x8000_0000
53 GENERIC_WRITE AccessMask = 0x4000_0000
54 GENERIC_EXECUTE AccessMask = 0x2000_0000
55 GENERIC_ALL AccessMask = 0x1000_0000
56 ACCESS_SYSTEM_SECURITY AccessMask = 0x0100_0000
57
58 // Specific Object Access
59 // from ntioapi.h
60
61 FILE_READ_DATA AccessMask = (0x0001) // file & pipe
62 FILE_LIST_DIRECTORY AccessMask = (0x0001) // directory
63
64 FILE_WRITE_DATA AccessMask = (0x0002) // file & pipe
65 FILE_ADD_FILE AccessMask = (0x0002) // directory
66
67 FILE_APPEND_DATA AccessMask = (0x0004) // file
68 FILE_ADD_SUBDIRECTORY AccessMask = (0x0004) // directory
69 FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004) // named pipe
70
71 FILE_READ_EA AccessMask = (0x0008) // file & directory
72 FILE_READ_PROPERTIES AccessMask = FILE_READ_EA
73
74 FILE_WRITE_EA AccessMask = (0x0010) // file & directory
75 FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA
76
77 FILE_EXECUTE AccessMask = (0x0020) // file
78 FILE_TRAVERSE AccessMask = (0x0020) // directory
79
80 FILE_DELETE_CHILD AccessMask = (0x0040) // directory
81
82 FILE_READ_ATTRIBUTES AccessMask = (0x0080) // all
83
84 FILE_WRITE_ATTRIBUTES AccessMask = (0x0100) // all
85
86 FILE_ALL_ACCESS AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
87 FILE_GENERIC_READ AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
88 FILE_GENERIC_WRITE AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
89 FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
90
91 SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF
92
93 // Standard Access
94 // from ntseapi.h
95
96 DELETE AccessMask = 0x0001_0000
97 READ_CONTROL AccessMask = 0x0002_0000
98 WRITE_DAC AccessMask = 0x0004_0000
99 WRITE_OWNER AccessMask = 0x0008_0000
100 SYNCHRONIZE AccessMask = 0x0010_0000
101
102 STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000
103
104 STANDARD_RIGHTS_READ AccessMask = READ_CONTROL
105 STANDARD_RIGHTS_WRITE AccessMask = READ_CONTROL
106 STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL
107
108 STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000
109)
110
111type FileShareMode uint32
112
113//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
114const (
115 FILE_SHARE_NONE FileShareMode = 0x00
116 FILE_SHARE_READ FileShareMode = 0x01
117 FILE_SHARE_WRITE FileShareMode = 0x02
118 FILE_SHARE_DELETE FileShareMode = 0x04
119 FILE_SHARE_VALID_FLAGS FileShareMode = 0x07
120)
121
122type FileCreationDisposition uint32
123
124//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
125const (
126 // from winbase.h
127
128 CREATE_NEW FileCreationDisposition = 0x01
129 CREATE_ALWAYS FileCreationDisposition = 0x02
130 OPEN_EXISTING FileCreationDisposition = 0x03
131 OPEN_ALWAYS FileCreationDisposition = 0x04
132 TRUNCATE_EXISTING FileCreationDisposition = 0x05
133)
134
135// Create disposition values for NtCreate*
136type NTFileCreationDisposition uint32
137
138//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
139const (
140 // From ntioapi.h
141
142 FILE_SUPERSEDE NTFileCreationDisposition = 0x00
143 FILE_OPEN NTFileCreationDisposition = 0x01
144 FILE_CREATE NTFileCreationDisposition = 0x02
145 FILE_OPEN_IF NTFileCreationDisposition = 0x03
146 FILE_OVERWRITE NTFileCreationDisposition = 0x04
147 FILE_OVERWRITE_IF NTFileCreationDisposition = 0x05
148 FILE_MAXIMUM_DISPOSITION NTFileCreationDisposition = 0x05
149)
150
151// CreateFile and co. take flags or attributes together as one parameter.
152// Define alias until we can use generics to allow both
153//
154// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
155type FileFlagOrAttribute uint32
156
157//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
158const (
159 // from winnt.h
160
161 FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000
162 FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000
163 FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000
164 FILE_FLAG_RANDOM_ACCESS FileFlagOrAttribute = 0x1000_0000
165 FILE_FLAG_SEQUENTIAL_SCAN FileFlagOrAttribute = 0x0800_0000
166 FILE_FLAG_DELETE_ON_CLOSE FileFlagOrAttribute = 0x0400_0000
167 FILE_FLAG_BACKUP_SEMANTICS FileFlagOrAttribute = 0x0200_0000
168 FILE_FLAG_POSIX_SEMANTICS FileFlagOrAttribute = 0x0100_0000
169 FILE_FLAG_OPEN_REPARSE_POINT FileFlagOrAttribute = 0x0020_0000
170 FILE_FLAG_OPEN_NO_RECALL FileFlagOrAttribute = 0x0010_0000
171 FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
172)
173
174// NtCreate* functions take a dedicated CreateOptions parameter.
175//
176// https://learn.microsoft.com/en-us/windows/win32/api/Winternl/nf-winternl-ntcreatefile
177//
178// https://learn.microsoft.com/en-us/windows/win32/devnotes/nt-create-named-pipe-file
179type NTCreateOptions uint32
180
181//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
182const (
183 // From ntioapi.h
184
185 FILE_DIRECTORY_FILE NTCreateOptions = 0x0000_0001
186 FILE_WRITE_THROUGH NTCreateOptions = 0x0000_0002
187 FILE_SEQUENTIAL_ONLY NTCreateOptions = 0x0000_0004
188 FILE_NO_INTERMEDIATE_BUFFERING NTCreateOptions = 0x0000_0008
189
190 FILE_SYNCHRONOUS_IO_ALERT NTCreateOptions = 0x0000_0010
191 FILE_SYNCHRONOUS_IO_NONALERT NTCreateOptions = 0x0000_0020
192 FILE_NON_DIRECTORY_FILE NTCreateOptions = 0x0000_0040
193 FILE_CREATE_TREE_CONNECTION NTCreateOptions = 0x0000_0080
194
195 FILE_COMPLETE_IF_OPLOCKED NTCreateOptions = 0x0000_0100
196 FILE_NO_EA_KNOWLEDGE NTCreateOptions = 0x0000_0200
197 FILE_DISABLE_TUNNELING NTCreateOptions = 0x0000_0400
198 FILE_RANDOM_ACCESS NTCreateOptions = 0x0000_0800
199
200 FILE_DELETE_ON_CLOSE NTCreateOptions = 0x0000_1000
201 FILE_OPEN_BY_FILE_ID NTCreateOptions = 0x0000_2000
202 FILE_OPEN_FOR_BACKUP_INTENT NTCreateOptions = 0x0000_4000
203 FILE_NO_COMPRESSION NTCreateOptions = 0x0000_8000
204)
205
206type FileSQSFlag = FileFlagOrAttribute
207
208//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
209const (
210 // from winbase.h
211
212 SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
213 SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16)
214 SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16)
215 SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
216
217 SECURITY_SQOS_PRESENT FileSQSFlag = 0x0010_0000
218 SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F_0000
219)
220
221// GetFinalPathNameByHandle flags
222//
223// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew#parameters
224type GetFinalPathFlag uint32
225
226//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
227const (
228 GetFinalPathDefaultFlag GetFinalPathFlag = 0x0
229
230 FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0
231 FILE_NAME_OPENED GetFinalPathFlag = 0x8
232
233 VOLUME_NAME_DOS GetFinalPathFlag = 0x0
234 VOLUME_NAME_GUID GetFinalPathFlag = 0x1
235 VOLUME_NAME_NT GetFinalPathFlag = 0x2
236 VOLUME_NAME_NONE GetFinalPathFlag = 0x4
237)
238
239// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle
240// with the given handle and flags. It transparently takes care of creating a buffer of the
241// correct size for the call.
242//
243// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
244func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) {
245 b := stringbuffer.NewWString()
246 //TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n?
247 for {
248 n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags))
249 if err != nil {
250 return "", err
251 }
252 // If the buffer wasn't large enough, n will be the total size needed (including null terminator).
253 // Resize and try again.
254 if n > b.Cap() {
255 b.ResizeTo(n)
256 continue
257 }
258 // If the buffer is large enough, n will be the size not including the null terminator.
259 // Convert to a Go string and return.
260 return b.String(), nil
261 }
262}