fs.go 9.8 KB

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