Merge pull request #117306 from marosset/update-go-winio-dep
updating microsft/go-winio package to latest version
This commit is contained in:
		
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							@@ -15,7 +15,7 @@ require (
 | 
			
		||||
	github.com/Azure/go-autorest/autorest/adal v0.9.23
 | 
			
		||||
	github.com/GoogleCloudPlatform/k8s-cloud-provider v1.18.1-0.20220218231025-f11817397a1b
 | 
			
		||||
	github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab
 | 
			
		||||
	github.com/Microsoft/go-winio v0.4.17
 | 
			
		||||
	github.com/Microsoft/go-winio v0.6.0
 | 
			
		||||
	github.com/Microsoft/hcsshim v0.8.25
 | 
			
		||||
	github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e
 | 
			
		||||
	github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								go.sum
									
									
									
									
									
								
							@@ -82,8 +82,9 @@ github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5
 | 
			
		||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
 | 
			
		||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
 | 
			
		||||
github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
 | 
			
		||||
github.com/Microsoft/go-winio v0.4.17 h1:iT12IBVClFevaf8PuVyi3UmZOVh4OqnaLxDTW2O6j3w=
 | 
			
		||||
github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
 | 
			
		||||
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
 | 
			
		||||
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
 | 
			
		||||
github.com/Microsoft/hcsshim v0.8.25 h1:fRMwXiwk3qDwc0P05eHnh+y2v07JdtsfQ1fuAc69m9g=
 | 
			
		||||
github.com/Microsoft/hcsshim v0.8.25/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
 | 
			
		||||
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
 | 
			
		||||
 
 | 
			
		||||
@@ -83,7 +83,6 @@
 | 
			
		||||
        "sigs.k8s.io/structured-merge-diff/v4"
 | 
			
		||||
      ],
 | 
			
		||||
      "github.com/pkg/errors": [
 | 
			
		||||
        "github.com/Microsoft/go-winio",
 | 
			
		||||
        "github.com/Microsoft/hcsshim",
 | 
			
		||||
        "github.com/aws/aws-sdk-go",
 | 
			
		||||
        "github.com/containerd/cgroups",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/.gitattributes
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/.gitattributes
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
* text=auto eol=lf
 | 
			
		||||
							
								
								
									
										9
									
								
								vendor/github.com/Microsoft/go-winio/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/Microsoft/go-winio/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1 +1,10 @@
 | 
			
		||||
.vscode/
 | 
			
		||||
 | 
			
		||||
*.exe
 | 
			
		||||
 | 
			
		||||
# testing
 | 
			
		||||
testdata
 | 
			
		||||
 | 
			
		||||
# go workspaces
 | 
			
		||||
go.work
 | 
			
		||||
go.work.sum
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										144
									
								
								vendor/github.com/Microsoft/go-winio/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/Microsoft/go-winio/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,144 @@
 | 
			
		||||
run:
 | 
			
		||||
  skip-dirs:
 | 
			
		||||
    - pkg/etw/sample
 | 
			
		||||
 | 
			
		||||
linters:
 | 
			
		||||
  enable:
 | 
			
		||||
    # style
 | 
			
		||||
    - containedctx # struct contains a context
 | 
			
		||||
    - dupl # duplicate code
 | 
			
		||||
    - errname # erorrs are named correctly
 | 
			
		||||
    - goconst # strings that should be constants
 | 
			
		||||
    - godot # comments end in a period
 | 
			
		||||
    - misspell
 | 
			
		||||
    - nolintlint # "//nolint" directives are properly explained
 | 
			
		||||
    - revive # golint replacement
 | 
			
		||||
    - stylecheck # golint replacement, less configurable than revive
 | 
			
		||||
    - unconvert # unnecessary conversions
 | 
			
		||||
    - wastedassign
 | 
			
		||||
 | 
			
		||||
    # bugs, performance, unused, etc ...
 | 
			
		||||
    - contextcheck # function uses a non-inherited context
 | 
			
		||||
    - errorlint # errors not wrapped for 1.13
 | 
			
		||||
    - exhaustive # check exhaustiveness of enum switch statements
 | 
			
		||||
    - gofmt # files are gofmt'ed
 | 
			
		||||
    - gosec # security
 | 
			
		||||
    - nestif # deeply nested ifs
 | 
			
		||||
    - nilerr # returns nil even with non-nil error
 | 
			
		||||
    - prealloc # slices that can be pre-allocated
 | 
			
		||||
    - structcheck # unused struct fields
 | 
			
		||||
    - unparam # unused function params
 | 
			
		||||
 | 
			
		||||
issues:
 | 
			
		||||
  exclude-rules:
 | 
			
		||||
    # err is very often shadowed in nested scopes
 | 
			
		||||
    - linters:
 | 
			
		||||
        - govet
 | 
			
		||||
      text: '^shadow: declaration of "err" shadows declaration'
 | 
			
		||||
 | 
			
		||||
    # ignore long lines for skip autogen directives
 | 
			
		||||
    - linters:
 | 
			
		||||
        - revive
 | 
			
		||||
      text: "^line-length-limit: "
 | 
			
		||||
      source: "^//(go:generate|sys) "
 | 
			
		||||
 | 
			
		||||
    # allow unjustified ignores of error checks in defer statements
 | 
			
		||||
    - linters:
 | 
			
		||||
        - nolintlint
 | 
			
		||||
      text: "^directive `//nolint:errcheck` should provide explanation"
 | 
			
		||||
      source: '^\s*defer '
 | 
			
		||||
 | 
			
		||||
    # allow unjustified ignores of error lints for io.EOF
 | 
			
		||||
    - linters:
 | 
			
		||||
        - nolintlint
 | 
			
		||||
      text: "^directive `//nolint:errorlint` should provide explanation"
 | 
			
		||||
      source: '[=|!]= io.EOF'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
linters-settings:
 | 
			
		||||
  govet:
 | 
			
		||||
    enable-all: true
 | 
			
		||||
    disable:
 | 
			
		||||
      # struct order is often for Win32 compat
 | 
			
		||||
      # also, ignore pointer bytes/GC issues for now until performance becomes an issue
 | 
			
		||||
      - fieldalignment
 | 
			
		||||
    check-shadowing: true
 | 
			
		||||
  nolintlint:
 | 
			
		||||
    allow-leading-space: false
 | 
			
		||||
    require-explanation: true
 | 
			
		||||
    require-specific: true
 | 
			
		||||
  revive:
 | 
			
		||||
    # revive is more configurable than static check, so likely the preferred alternative to static-check
 | 
			
		||||
    # (once the perf issue is solved: https://github.com/golangci/golangci-lint/issues/2997)
 | 
			
		||||
    enable-all-rules:
 | 
			
		||||
      true
 | 
			
		||||
      # https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
 | 
			
		||||
    rules:
 | 
			
		||||
      # rules with required arguments
 | 
			
		||||
      - name: argument-limit
 | 
			
		||||
        disabled: true
 | 
			
		||||
      - name: banned-characters
 | 
			
		||||
        disabled: true
 | 
			
		||||
      - name: cognitive-complexity
 | 
			
		||||
        disabled: true
 | 
			
		||||
      - name: cyclomatic
 | 
			
		||||
        disabled: true
 | 
			
		||||
      - name: file-header
 | 
			
		||||
        disabled: true
 | 
			
		||||
      - name: function-length
 | 
			
		||||
        disabled: true
 | 
			
		||||
      - name: function-result-limit
 | 
			
		||||
        disabled: true
 | 
			
		||||
      - name: max-public-structs
 | 
			
		||||
        disabled: true
 | 
			
		||||
      # geneally annoying rules
 | 
			
		||||
      - name: add-constant # complains about any and all strings and integers
 | 
			
		||||
        disabled: true
 | 
			
		||||
      - name: confusing-naming # we frequently use "Foo()" and "foo()" together
 | 
			
		||||
        disabled: true
 | 
			
		||||
      - name: flag-parameter # excessive, and a common idiom we use
 | 
			
		||||
        disabled: true
 | 
			
		||||
      # general config
 | 
			
		||||
      - name: line-length-limit
 | 
			
		||||
        arguments:
 | 
			
		||||
          - 140
 | 
			
		||||
      - name: var-naming
 | 
			
		||||
        arguments:
 | 
			
		||||
          - []
 | 
			
		||||
          - - CID
 | 
			
		||||
            - CRI
 | 
			
		||||
            - CTRD
 | 
			
		||||
            - DACL
 | 
			
		||||
            - DLL
 | 
			
		||||
            - DOS
 | 
			
		||||
            - ETW
 | 
			
		||||
            - FSCTL
 | 
			
		||||
            - GCS
 | 
			
		||||
            - GMSA
 | 
			
		||||
            - HCS
 | 
			
		||||
            - HV
 | 
			
		||||
            - IO
 | 
			
		||||
            - LCOW
 | 
			
		||||
            - LDAP
 | 
			
		||||
            - LPAC
 | 
			
		||||
            - LTSC
 | 
			
		||||
            - MMIO
 | 
			
		||||
            - NT
 | 
			
		||||
            - OCI
 | 
			
		||||
            - PMEM
 | 
			
		||||
            - PWSH
 | 
			
		||||
            - RX
 | 
			
		||||
            - SACl
 | 
			
		||||
            - SID
 | 
			
		||||
            - SMB
 | 
			
		||||
            - TX
 | 
			
		||||
            - VHD
 | 
			
		||||
            - VHDX
 | 
			
		||||
            - VMID
 | 
			
		||||
            - VPCI
 | 
			
		||||
            - WCOW
 | 
			
		||||
            - WIM
 | 
			
		||||
  stylecheck:
 | 
			
		||||
    checks:
 | 
			
		||||
      - "all"
 | 
			
		||||
      - "-ST1003" # use revive's var naming
 | 
			
		||||
							
								
								
									
										85
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										85
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,4 +1,4 @@
 | 
			
		||||
# go-winio
 | 
			
		||||
# go-winio [](https://github.com/microsoft/go-winio/actions/workflows/ci.yml)
 | 
			
		||||
 | 
			
		||||
This repository contains utilities for efficiently performing Win32 IO operations in
 | 
			
		||||
Go. Currently, this is focused on accessing named pipes and other file handles, and
 | 
			
		||||
@@ -11,12 +11,79 @@ package.
 | 
			
		||||
 | 
			
		||||
Please see the LICENSE file for licensing information.
 | 
			
		||||
 | 
			
		||||
This project has adopted the [Microsoft Open Source Code of
 | 
			
		||||
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
 | 
			
		||||
see the [Code of Conduct
 | 
			
		||||
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
 | 
			
		||||
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
 | 
			
		||||
questions or comments.
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
 | 
			
		||||
for another named pipe implementation.
 | 
			
		||||
This project welcomes contributions and suggestions.
 | 
			
		||||
Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that
 | 
			
		||||
you have the right to, and actually do, grant us the rights to use your contribution.
 | 
			
		||||
For details, visit [Microsoft CLA](https://cla.microsoft.com).
 | 
			
		||||
 | 
			
		||||
When you submit a pull request, a CLA-bot will automatically determine whether you need to
 | 
			
		||||
provide a CLA and decorate the PR appropriately (e.g., label, comment).
 | 
			
		||||
Simply follow the instructions provided by the bot.
 | 
			
		||||
You will only need to do this once across all repos using our CLA.
 | 
			
		||||
 | 
			
		||||
Additionally, the pull request pipeline requires the following steps to be performed before
 | 
			
		||||
mergining.
 | 
			
		||||
 | 
			
		||||
### Code Sign-Off
 | 
			
		||||
 | 
			
		||||
We require that contributors sign their commits using [`git commit --signoff`][git-commit-s]
 | 
			
		||||
to certify they either authored the work themselves or otherwise have permission to use it in this project.
 | 
			
		||||
 | 
			
		||||
A range of commits can be signed off using [`git rebase --signoff`][git-rebase-s].
 | 
			
		||||
 | 
			
		||||
Please see [the developer certificate](https://developercertificate.org) for more info,
 | 
			
		||||
as well as to make sure that you can attest to the rules listed.
 | 
			
		||||
Our CI uses the DCO Github app to ensure that all commits in a given PR are signed-off.
 | 
			
		||||
 | 
			
		||||
### Linting
 | 
			
		||||
 | 
			
		||||
Code must pass a linting stage, which uses [`golangci-lint`][lint].
 | 
			
		||||
The linting settings are stored in [`.golangci.yaml`](./.golangci.yaml), and can be run
 | 
			
		||||
automatically with VSCode by adding the following to your workspace or folder settings:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
    "go.lintTool": "golangci-lint",
 | 
			
		||||
    "go.lintOnSave": "package",
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Additional editor [integrations options are also available][lint-ide].
 | 
			
		||||
 | 
			
		||||
Alternatively, `golangci-lint` can be [installed locally][lint-install] and run from the repo root:
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
# use . or specify a path to only lint a package
 | 
			
		||||
# to show all lint errors, use flags "--max-issues-per-linter=0 --max-same-issues=0"
 | 
			
		||||
> golangci-lint run ./...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Go Generate
 | 
			
		||||
 | 
			
		||||
The pipeline checks that auto-generated code, via `go generate`, are up to date.
 | 
			
		||||
 | 
			
		||||
This can be done for the entire repo:
 | 
			
		||||
 | 
			
		||||
```shell
 | 
			
		||||
> go generate ./...
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Code of Conduct
 | 
			
		||||
 | 
			
		||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
 | 
			
		||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
 | 
			
		||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
 | 
			
		||||
 | 
			
		||||
## Special Thanks
 | 
			
		||||
 | 
			
		||||
Thanks to [natefinch][natefinch] for the inspiration for this library.
 | 
			
		||||
See [npipe](https://github.com/natefinch/npipe) for another named pipe implementation.
 | 
			
		||||
 | 
			
		||||
[lint]: https://golangci-lint.run/
 | 
			
		||||
[lint-ide]: https://golangci-lint.run/usage/integrations/#editor-integration
 | 
			
		||||
[lint-install]: https://golangci-lint.run/usage/install/#local-installation
 | 
			
		||||
 | 
			
		||||
[git-commit-s]: https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s
 | 
			
		||||
[git-rebase-s]: https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---signoff
 | 
			
		||||
 | 
			
		||||
[natefinch]: https://github.com/natefinch
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										41
									
								
								vendor/github.com/Microsoft/go-winio/SECURITY.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								vendor/github.com/Microsoft/go-winio/SECURITY.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.7 BLOCK -->
 | 
			
		||||
 | 
			
		||||
## Security
 | 
			
		||||
 | 
			
		||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
 | 
			
		||||
 | 
			
		||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
 | 
			
		||||
 | 
			
		||||
## Reporting Security Issues
 | 
			
		||||
 | 
			
		||||
**Please do not report security vulnerabilities through public GitHub issues.**
 | 
			
		||||
 | 
			
		||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
 | 
			
		||||
 | 
			
		||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
 | 
			
		||||
 | 
			
		||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). 
 | 
			
		||||
 | 
			
		||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
 | 
			
		||||
 | 
			
		||||
  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
 | 
			
		||||
  * Full paths of source file(s) related to the manifestation of the issue
 | 
			
		||||
  * The location of the affected source code (tag/branch/commit or direct URL)
 | 
			
		||||
  * Any special configuration required to reproduce the issue
 | 
			
		||||
  * Step-by-step instructions to reproduce the issue
 | 
			
		||||
  * Proof-of-concept or exploit code (if possible)
 | 
			
		||||
  * Impact of the issue, including how an attacker might exploit the issue
 | 
			
		||||
 | 
			
		||||
This information will help us triage your report more quickly.
 | 
			
		||||
 | 
			
		||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
 | 
			
		||||
 | 
			
		||||
## Preferred Languages
 | 
			
		||||
 | 
			
		||||
We prefer all communications to be in English.
 | 
			
		||||
 | 
			
		||||
## Policy
 | 
			
		||||
 | 
			
		||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
 | 
			
		||||
 | 
			
		||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
 | 
			
		||||
							
								
								
									
										48
									
								
								vendor/github.com/Microsoft/go-winio/backup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										48
									
								
								vendor/github.com/Microsoft/go-winio/backup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
@@ -7,11 +8,12 @@ import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unicode/utf16"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
 | 
			
		||||
@@ -24,7 +26,7 @@ const (
 | 
			
		||||
	BackupAlternateData
 | 
			
		||||
	BackupLink
 | 
			
		||||
	BackupPropertyData
 | 
			
		||||
	BackupObjectId
 | 
			
		||||
	BackupObjectId //revive:disable-line:var-naming ID, not Id
 | 
			
		||||
	BackupReparseData
 | 
			
		||||
	BackupSparseBlock
 | 
			
		||||
	BackupTxfsData
 | 
			
		||||
@@ -34,14 +36,16 @@ const (
 | 
			
		||||
	StreamSparseAttributes = uint32(8)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//nolint:revive // var-naming: ALL_CAPS
 | 
			
		||||
const (
 | 
			
		||||
	WRITE_DAC              = 0x40000
 | 
			
		||||
	WRITE_OWNER            = 0x80000
 | 
			
		||||
	ACCESS_SYSTEM_SECURITY = 0x1000000
 | 
			
		||||
	WRITE_DAC              = windows.WRITE_DAC
 | 
			
		||||
	WRITE_OWNER            = windows.WRITE_OWNER
 | 
			
		||||
	ACCESS_SYSTEM_SECURITY = windows.ACCESS_SYSTEM_SECURITY
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// BackupHeader represents a backup stream of a file.
 | 
			
		||||
type BackupHeader struct {
 | 
			
		||||
	//revive:disable-next-line:var-naming ID, not Id
 | 
			
		||||
	Id         uint32 // The backup stream ID
 | 
			
		||||
	Attributes uint32 // Stream attributes
 | 
			
		||||
	Size       int64  // The size of the stream in bytes
 | 
			
		||||
@@ -49,8 +53,8 @@ type BackupHeader struct {
 | 
			
		||||
	Offset     int64  // The offset of the stream in the file (for BackupSparseBlock only).
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type win32StreamId struct {
 | 
			
		||||
	StreamId   uint32
 | 
			
		||||
type win32StreamID struct {
 | 
			
		||||
	StreamID   uint32
 | 
			
		||||
	Attributes uint32
 | 
			
		||||
	Size       uint64
 | 
			
		||||
	NameSize   uint32
 | 
			
		||||
@@ -71,7 +75,7 @@ func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
 | 
			
		||||
// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if
 | 
			
		||||
// it was not completely read.
 | 
			
		||||
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
 | 
			
		||||
	if r.bytesLeft > 0 {
 | 
			
		||||
	if r.bytesLeft > 0 { //nolint:nestif // todo: flatten this
 | 
			
		||||
		if s, ok := r.r.(io.Seeker); ok {
 | 
			
		||||
			// Make sure Seek on io.SeekCurrent sometimes succeeds
 | 
			
		||||
			// before trying the actual seek.
 | 
			
		||||
@@ -82,16 +86,16 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
 | 
			
		||||
				r.bytesLeft = 0
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if _, err := io.Copy(ioutil.Discard, r); err != nil {
 | 
			
		||||
		if _, err := io.Copy(io.Discard, r); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	var wsi win32StreamId
 | 
			
		||||
	var wsi win32StreamID
 | 
			
		||||
	if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	hdr := &BackupHeader{
 | 
			
		||||
		Id:         wsi.StreamId,
 | 
			
		||||
		Id:         wsi.StreamID,
 | 
			
		||||
		Attributes: wsi.Attributes,
 | 
			
		||||
		Size:       int64(wsi.Size),
 | 
			
		||||
	}
 | 
			
		||||
@@ -102,7 +106,7 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
 | 
			
		||||
		}
 | 
			
		||||
		hdr.Name = syscall.UTF16ToString(name)
 | 
			
		||||
	}
 | 
			
		||||
	if wsi.StreamId == BackupSparseBlock {
 | 
			
		||||
	if wsi.StreamID == BackupSparseBlock {
 | 
			
		||||
		if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
@@ -147,8 +151,8 @@ func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
 | 
			
		||||
		return fmt.Errorf("missing %d bytes", w.bytesLeft)
 | 
			
		||||
	}
 | 
			
		||||
	name := utf16.Encode([]rune(hdr.Name))
 | 
			
		||||
	wsi := win32StreamId{
 | 
			
		||||
		StreamId:   hdr.Id,
 | 
			
		||||
	wsi := win32StreamID{
 | 
			
		||||
		StreamID:   hdr.Id,
 | 
			
		||||
		Attributes: hdr.Attributes,
 | 
			
		||||
		Size:       uint64(hdr.Size),
 | 
			
		||||
		NameSize:   uint32(len(name) * 2),
 | 
			
		||||
@@ -203,7 +207,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
 | 
			
		||||
	var bytesRead uint32
 | 
			
		||||
	err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{"BackupRead", r.f.Name(), err}
 | 
			
		||||
		return 0, &os.PathError{Op: "BackupRead", Path: r.f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(r.f)
 | 
			
		||||
	if bytesRead == 0 {
 | 
			
		||||
@@ -216,7 +220,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
 | 
			
		||||
// the underlying file.
 | 
			
		||||
func (r *BackupFileReader) Close() error {
 | 
			
		||||
	if r.ctx != 0 {
 | 
			
		||||
		backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
 | 
			
		||||
		_ = backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
 | 
			
		||||
		runtime.KeepAlive(r.f)
 | 
			
		||||
		r.ctx = 0
 | 
			
		||||
	}
 | 
			
		||||
@@ -242,7 +246,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
 | 
			
		||||
	var bytesWritten uint32
 | 
			
		||||
	err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
 | 
			
		||||
		return 0, &os.PathError{Op: "BackupWrite", Path: w.f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(w.f)
 | 
			
		||||
	if int(bytesWritten) != len(b) {
 | 
			
		||||
@@ -255,7 +259,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
 | 
			
		||||
// close the underlying file.
 | 
			
		||||
func (w *BackupFileWriter) Close() error {
 | 
			
		||||
	if w.ctx != 0 {
 | 
			
		||||
		backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
 | 
			
		||||
		_ = backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
 | 
			
		||||
		runtime.KeepAlive(w.f)
 | 
			
		||||
		w.ctx = 0
 | 
			
		||||
	}
 | 
			
		||||
@@ -271,7 +275,13 @@ func OpenForBackup(path string, access uint32, share uint32, createmode uint32)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0)
 | 
			
		||||
	h, err := syscall.CreateFile(&winPath[0],
 | 
			
		||||
		access,
 | 
			
		||||
		share,
 | 
			
		||||
		nil,
 | 
			
		||||
		createmode,
 | 
			
		||||
		syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT,
 | 
			
		||||
		0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
		return nil, err
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
// This package provides utilities for efficiently performing Win32 IO operations in Go.
 | 
			
		||||
// Currently, this package is provides support for genreal IO and management of
 | 
			
		||||
//   - named pipes
 | 
			
		||||
//   - files
 | 
			
		||||
//   - [Hyper-V sockets]
 | 
			
		||||
//
 | 
			
		||||
// This code is similar to Go's [net] package, and uses IO completion ports to avoid
 | 
			
		||||
// blocking IO on system threads, allowing Go to reuse the thread to schedule other goroutines.
 | 
			
		||||
//
 | 
			
		||||
// This limits support to Windows Vista and newer operating systems.
 | 
			
		||||
//
 | 
			
		||||
// Additionally, this package provides support for:
 | 
			
		||||
//   - creating and managing GUIDs
 | 
			
		||||
//   - writing to [ETW]
 | 
			
		||||
//   - opening and manageing VHDs
 | 
			
		||||
//   - parsing [Windows Image files]
 | 
			
		||||
//   - auto-generating Win32 API code
 | 
			
		||||
//
 | 
			
		||||
// [Hyper-V sockets]: https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service
 | 
			
		||||
// [ETW]: https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-
 | 
			
		||||
// [Windows Image files]: https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/work-with-windows-images
 | 
			
		||||
package winio
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/Microsoft/go-winio/ea.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/Microsoft/go-winio/ea.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -33,7 +33,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
 | 
			
		||||
	err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = errInvalidEaBuffer
 | 
			
		||||
		return
 | 
			
		||||
		return ea, nb, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nameOffset := fileFullEaInformationSize
 | 
			
		||||
@@ -43,7 +43,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
 | 
			
		||||
	nextOffset := int(info.NextEntryOffset)
 | 
			
		||||
	if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
 | 
			
		||||
		err = errInvalidEaBuffer
 | 
			
		||||
		return
 | 
			
		||||
		return ea, nb, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ea.Name = string(b[nameOffset : nameOffset+nameLen])
 | 
			
		||||
@@ -52,7 +52,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
 | 
			
		||||
	if info.NextEntryOffset != 0 {
 | 
			
		||||
		nb = b[info.NextEntryOffset:]
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
	return ea, nb, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
 | 
			
		||||
@@ -67,7 +67,7 @@ func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
 | 
			
		||||
		eas = append(eas, ea)
 | 
			
		||||
		b = nb
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
	return eas, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										70
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										70
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
@@ -10,6 +11,8 @@ import (
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
 | 
			
		||||
@@ -23,6 +26,8 @@ type atomicBool int32
 | 
			
		||||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
 | 
			
		||||
func (b *atomicBool) setFalse()   { atomic.StoreInt32((*int32)(b), 0) }
 | 
			
		||||
func (b *atomicBool) setTrue()    { atomic.StoreInt32((*int32)(b), 1) }
 | 
			
		||||
 | 
			
		||||
//revive:disable-next-line:predeclared Keep "new" to maintain consistency with "atomic" pkg
 | 
			
		||||
func (b *atomicBool) swap(new bool) bool {
 | 
			
		||||
	var newInt int32
 | 
			
		||||
	if new {
 | 
			
		||||
@@ -31,11 +36,6 @@ func (b *atomicBool) swap(new bool) bool {
 | 
			
		||||
	return atomic.SwapInt32((*int32)(b), newInt) == 1
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
 | 
			
		||||
	cFILE_SKIP_SET_EVENT_ON_HANDLE        = 2
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrFileClosed = errors.New("file has already been closed")
 | 
			
		||||
	ErrTimeout    = &timeoutError{}
 | 
			
		||||
@@ -43,28 +43,28 @@ var (
 | 
			
		||||
 | 
			
		||||
type timeoutError struct{}
 | 
			
		||||
 | 
			
		||||
func (e *timeoutError) Error() string   { return "i/o timeout" }
 | 
			
		||||
func (e *timeoutError) Timeout() bool   { return true }
 | 
			
		||||
func (e *timeoutError) Temporary() bool { return true }
 | 
			
		||||
func (*timeoutError) Error() string   { return "i/o timeout" }
 | 
			
		||||
func (*timeoutError) Timeout() bool   { return true }
 | 
			
		||||
func (*timeoutError) Temporary() bool { return true }
 | 
			
		||||
 | 
			
		||||
type timeoutChan chan struct{}
 | 
			
		||||
 | 
			
		||||
var ioInitOnce sync.Once
 | 
			
		||||
var ioCompletionPort syscall.Handle
 | 
			
		||||
 | 
			
		||||
// ioResult contains the result of an asynchronous IO operation
 | 
			
		||||
// ioResult contains the result of an asynchronous IO operation.
 | 
			
		||||
type ioResult struct {
 | 
			
		||||
	bytes uint32
 | 
			
		||||
	err   error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ioOperation represents an outstanding asynchronous Win32 IO
 | 
			
		||||
// ioOperation represents an outstanding asynchronous Win32 IO.
 | 
			
		||||
type ioOperation struct {
 | 
			
		||||
	o  syscall.Overlapped
 | 
			
		||||
	ch chan ioResult
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initIo() {
 | 
			
		||||
func initIO() {
 | 
			
		||||
	h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
@@ -93,15 +93,15 @@ type deadlineHandler struct {
 | 
			
		||||
	timedout    atomicBool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// makeWin32File makes a new win32File from an existing file handle
 | 
			
		||||
// makeWin32File makes a new win32File from an existing file handle.
 | 
			
		||||
func makeWin32File(h syscall.Handle) (*win32File, error) {
 | 
			
		||||
	f := &win32File{handle: h}
 | 
			
		||||
	ioInitOnce.Do(initIo)
 | 
			
		||||
	ioInitOnce.Do(initIO)
 | 
			
		||||
	_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
 | 
			
		||||
	err = setFileCompletionNotificationModes(h, windows.FILE_SKIP_COMPLETION_PORT_ON_SUCCESS|windows.FILE_SKIP_SET_EVENT_ON_HANDLE)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -120,14 +120,14 @@ func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
 | 
			
		||||
	return f, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// closeHandle closes the resources associated with a Win32 handle
 | 
			
		||||
// closeHandle closes the resources associated with a Win32 handle.
 | 
			
		||||
func (f *win32File) closeHandle() {
 | 
			
		||||
	f.wgLock.Lock()
 | 
			
		||||
	// Atomically set that we are closing, releasing the resources only once.
 | 
			
		||||
	if !f.closing.swap(true) {
 | 
			
		||||
		f.wgLock.Unlock()
 | 
			
		||||
		// cancel all IO and wait for it to complete
 | 
			
		||||
		cancelIoEx(f.handle, nil)
 | 
			
		||||
		_ = cancelIoEx(f.handle, nil)
 | 
			
		||||
		f.wg.Wait()
 | 
			
		||||
		// at this point, no new IO can start
 | 
			
		||||
		syscall.Close(f.handle)
 | 
			
		||||
@@ -143,9 +143,14 @@ func (f *win32File) Close() error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// prepareIo prepares for a new IO operation.
 | 
			
		||||
// IsClosed checks if the file has been closed.
 | 
			
		||||
func (f *win32File) IsClosed() bool {
 | 
			
		||||
	return f.closing.isSet()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// prepareIO prepares for a new IO operation.
 | 
			
		||||
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
 | 
			
		||||
func (f *win32File) prepareIo() (*ioOperation, error) {
 | 
			
		||||
func (f *win32File) prepareIO() (*ioOperation, error) {
 | 
			
		||||
	f.wgLock.RLock()
 | 
			
		||||
	if f.closing.isSet() {
 | 
			
		||||
		f.wgLock.RUnlock()
 | 
			
		||||
@@ -158,7 +163,7 @@ func (f *win32File) prepareIo() (*ioOperation, error) {
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ioCompletionProcessor processes completed async IOs forever
 | 
			
		||||
// ioCompletionProcessor processes completed async IOs forever.
 | 
			
		||||
func ioCompletionProcessor(h syscall.Handle) {
 | 
			
		||||
	for {
 | 
			
		||||
		var bytes uint32
 | 
			
		||||
@@ -172,15 +177,17 @@ func ioCompletionProcessor(h syscall.Handle) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
 | 
			
		||||
// todo: helsaawy - create an asyncIO version that takes a context
 | 
			
		||||
 | 
			
		||||
// asyncIO processes the return value from ReadFile or WriteFile, blocking until
 | 
			
		||||
// the operation has actually completed.
 | 
			
		||||
func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
 | 
			
		||||
	if err != syscall.ERROR_IO_PENDING {
 | 
			
		||||
func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
 | 
			
		||||
	if err != syscall.ERROR_IO_PENDING { //nolint:errorlint // err is Errno
 | 
			
		||||
		return int(bytes), err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.closing.isSet() {
 | 
			
		||||
		cancelIoEx(f.handle, &c.o)
 | 
			
		||||
		_ = cancelIoEx(f.handle, &c.o)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var timeout timeoutChan
 | 
			
		||||
@@ -194,7 +201,7 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
 | 
			
		||||
	select {
 | 
			
		||||
	case r = <-c.ch:
 | 
			
		||||
		err = r.err
 | 
			
		||||
		if err == syscall.ERROR_OPERATION_ABORTED {
 | 
			
		||||
		if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
 | 
			
		||||
			if f.closing.isSet() {
 | 
			
		||||
				err = ErrFileClosed
 | 
			
		||||
			}
 | 
			
		||||
@@ -204,10 +211,10 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
 | 
			
		||||
			err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
 | 
			
		||||
		}
 | 
			
		||||
	case <-timeout:
 | 
			
		||||
		cancelIoEx(f.handle, &c.o)
 | 
			
		||||
		_ = cancelIoEx(f.handle, &c.o)
 | 
			
		||||
		r = <-c.ch
 | 
			
		||||
		err = r.err
 | 
			
		||||
		if err == syscall.ERROR_OPERATION_ABORTED {
 | 
			
		||||
		if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
 | 
			
		||||
			err = ErrTimeout
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -215,13 +222,14 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
 | 
			
		||||
	// runtime.KeepAlive is needed, as c is passed via native
 | 
			
		||||
	// code to ioCompletionProcessor, c must remain alive
 | 
			
		||||
	// until the channel read is complete.
 | 
			
		||||
	// todo: (de)allocate *ioOperation via win32 heap functions, instead of needing to KeepAlive?
 | 
			
		||||
	runtime.KeepAlive(c)
 | 
			
		||||
	return int(r.bytes), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads from a file handle.
 | 
			
		||||
func (f *win32File) Read(b []byte) (int, error) {
 | 
			
		||||
	c, err := f.prepareIo()
 | 
			
		||||
	c, err := f.prepareIO()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -233,13 +241,13 @@ func (f *win32File) Read(b []byte) (int, error) {
 | 
			
		||||
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
 | 
			
		||||
	n, err := f.asyncIo(c, &f.readDeadline, bytes, err)
 | 
			
		||||
	n, err := f.asyncIO(c, &f.readDeadline, bytes, err)
 | 
			
		||||
	runtime.KeepAlive(b)
 | 
			
		||||
 | 
			
		||||
	// Handle EOF conditions.
 | 
			
		||||
	if err == nil && n == 0 && len(b) != 0 {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	} else if err == syscall.ERROR_BROKEN_PIPE {
 | 
			
		||||
	} else if err == syscall.ERROR_BROKEN_PIPE { //nolint:errorlint // err is Errno
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	} else {
 | 
			
		||||
		return n, err
 | 
			
		||||
@@ -248,7 +256,7 @@ func (f *win32File) Read(b []byte) (int, error) {
 | 
			
		||||
 | 
			
		||||
// Write writes to a file handle.
 | 
			
		||||
func (f *win32File) Write(b []byte) (int, error) {
 | 
			
		||||
	c, err := f.prepareIo()
 | 
			
		||||
	c, err := f.prepareIO()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
@@ -260,7 +268,7 @@ func (f *win32File) Write(b []byte) (int, error) {
 | 
			
		||||
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
 | 
			
		||||
	n, err := f.asyncIo(c, &f.writeDeadline, bytes, err)
 | 
			
		||||
	n, err := f.asyncIO(c, &f.writeDeadline, bytes, err)
 | 
			
		||||
	runtime.KeepAlive(b)
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										29
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
@@ -14,13 +15,18 @@ import (
 | 
			
		||||
type FileBasicInfo struct {
 | 
			
		||||
	CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
 | 
			
		||||
	FileAttributes                                          uint32
 | 
			
		||||
	pad                                                     uint32 // padding
 | 
			
		||||
	_                                                       uint32 // padding
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetFileBasicInfo retrieves times and attributes for a file.
 | 
			
		||||
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
 | 
			
		||||
	bi := &FileBasicInfo{}
 | 
			
		||||
	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
 | 
			
		||||
	if err := windows.GetFileInformationByHandleEx(
 | 
			
		||||
		windows.Handle(f.Fd()),
 | 
			
		||||
		windows.FileBasicInfo,
 | 
			
		||||
		(*byte)(unsafe.Pointer(bi)),
 | 
			
		||||
		uint32(unsafe.Sizeof(*bi)),
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
@@ -29,7 +35,12 @@ func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
 | 
			
		||||
 | 
			
		||||
// SetFileBasicInfo sets times and attributes for a file.
 | 
			
		||||
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
 | 
			
		||||
	if err := windows.SetFileInformationByHandle(windows.Handle(f.Fd()), windows.FileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
 | 
			
		||||
	if err := windows.SetFileInformationByHandle(
 | 
			
		||||
		windows.Handle(f.Fd()),
 | 
			
		||||
		windows.FileBasicInfo,
 | 
			
		||||
		(*byte)(unsafe.Pointer(bi)),
 | 
			
		||||
		uint32(unsafe.Sizeof(*bi)),
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
@@ -48,7 +59,10 @@ type FileStandardInfo struct {
 | 
			
		||||
// GetFileStandardInfo retrieves ended information for the file.
 | 
			
		||||
func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
 | 
			
		||||
	si := &FileStandardInfo{}
 | 
			
		||||
	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileStandardInfo, (*byte)(unsafe.Pointer(si)), uint32(unsafe.Sizeof(*si))); err != nil {
 | 
			
		||||
	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()),
 | 
			
		||||
		windows.FileStandardInfo,
 | 
			
		||||
		(*byte)(unsafe.Pointer(si)),
 | 
			
		||||
		uint32(unsafe.Sizeof(*si))); err != nil {
 | 
			
		||||
		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
@@ -65,7 +79,12 @@ type FileIDInfo struct {
 | 
			
		||||
// GetFileID retrieves the unique (volume, file ID) pair for a file.
 | 
			
		||||
func GetFileID(f *os.File) (*FileIDInfo, error) {
 | 
			
		||||
	fileID := &FileIDInfo{}
 | 
			
		||||
	if err := windows.GetFileInformationByHandleEx(windows.Handle(f.Fd()), windows.FileIdInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
 | 
			
		||||
	if err := windows.GetFileInformationByHandleEx(
 | 
			
		||||
		windows.Handle(f.Fd()),
 | 
			
		||||
		windows.FileIdInfo,
 | 
			
		||||
		(*byte)(unsafe.Pointer(fileID)),
 | 
			
		||||
		uint32(unsafe.Sizeof(*fileID)),
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										360
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										360
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,8 +1,11 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
@@ -11,16 +14,87 @@ import (
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
 | 
			
		||||
	"github.com/Microsoft/go-winio/internal/socket"
 | 
			
		||||
	"github.com/Microsoft/go-winio/pkg/guid"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
 | 
			
		||||
const afHVSock = 34 // AF_HYPERV
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	afHvSock = 34 // AF_HYPERV
 | 
			
		||||
// Well known Service and VM IDs
 | 
			
		||||
//https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
 | 
			
		||||
 | 
			
		||||
	socketError = ^uintptr(0)
 | 
			
		||||
)
 | 
			
		||||
// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
 | 
			
		||||
func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
 | 
			
		||||
	return guid.GUID{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions.
 | 
			
		||||
func HvsockGUIDBroadcast() guid.GUID { //ffffffff-ffff-ffff-ffff-ffffffffffff
 | 
			
		||||
	return guid.GUID{
 | 
			
		||||
		Data1: 0xffffffff,
 | 
			
		||||
		Data2: 0xffff,
 | 
			
		||||
		Data3: 0xffff,
 | 
			
		||||
		Data4: [8]uint8{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockGUIDLoopback is the Loopback VmId for accepting connections to the same partition as the connector.
 | 
			
		||||
func HvsockGUIDLoopback() guid.GUID { // e0e16197-dd56-4a10-9195-5ee7a155a838
 | 
			
		||||
	return guid.GUID{
 | 
			
		||||
		Data1: 0xe0e16197,
 | 
			
		||||
		Data2: 0xdd56,
 | 
			
		||||
		Data3: 0x4a10,
 | 
			
		||||
		Data4: [8]uint8{0x91, 0x95, 0x5e, 0xe7, 0xa1, 0x55, 0xa8, 0x38},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockGUIDSiloHost is the address of a silo's host partition:
 | 
			
		||||
//   - The silo host of a hosted silo is the utility VM.
 | 
			
		||||
//   - The silo host of a silo on a physical host is the physical host.
 | 
			
		||||
func HvsockGUIDSiloHost() guid.GUID { // 36bd0c5c-7276-4223-88ba-7d03b654c568
 | 
			
		||||
	return guid.GUID{
 | 
			
		||||
		Data1: 0x36bd0c5c,
 | 
			
		||||
		Data2: 0x7276,
 | 
			
		||||
		Data3: 0x4223,
 | 
			
		||||
		Data4: [8]byte{0x88, 0xba, 0x7d, 0x03, 0xb6, 0x54, 0xc5, 0x68},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockGUIDChildren is the wildcard VmId for accepting connections from the connector's child partitions.
 | 
			
		||||
func HvsockGUIDChildren() guid.GUID { // 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd
 | 
			
		||||
	return guid.GUID{
 | 
			
		||||
		Data1: 0x90db8b89,
 | 
			
		||||
		Data2: 0xd35,
 | 
			
		||||
		Data3: 0x4f79,
 | 
			
		||||
		Data4: [8]uint8{0x8c, 0xe9, 0x49, 0xea, 0xa, 0xc8, 0xb7, 0xcd},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockGUIDParent is the wildcard VmId for accepting connections from the connector's parent partition.
 | 
			
		||||
// Listening on this VmId accepts connection from:
 | 
			
		||||
//   - Inside silos: silo host partition.
 | 
			
		||||
//   - Inside hosted silo: host of the VM.
 | 
			
		||||
//   - Inside VM: VM host.
 | 
			
		||||
//   - Physical host: Not supported.
 | 
			
		||||
func HvsockGUIDParent() guid.GUID { // a42e7cda-d03f-480c-9cc2-a4de20abb878
 | 
			
		||||
	return guid.GUID{
 | 
			
		||||
		Data1: 0xa42e7cda,
 | 
			
		||||
		Data2: 0xd03f,
 | 
			
		||||
		Data3: 0x480c,
 | 
			
		||||
		Data4: [8]uint8{0x9c, 0xc2, 0xa4, 0xde, 0x20, 0xab, 0xb8, 0x78},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// hvsockVsockServiceTemplate is the Service GUID used for the VSOCK protocol.
 | 
			
		||||
func hvsockVsockServiceTemplate() guid.GUID { // 00000000-facb-11e6-bd58-64006a7986d3
 | 
			
		||||
	return guid.GUID{
 | 
			
		||||
		Data2: 0xfacb,
 | 
			
		||||
		Data3: 0x11e6,
 | 
			
		||||
		Data4: [8]uint8{0xbd, 0x58, 0x64, 0x00, 0x6a, 0x79, 0x86, 0xd3},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// An HvsockAddr is an address for a AF_HYPERV socket.
 | 
			
		||||
type HvsockAddr struct {
 | 
			
		||||
@@ -35,8 +109,10 @@ type rawHvsockAddr struct {
 | 
			
		||||
	ServiceID guid.GUID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ socket.RawSockaddr = &rawHvsockAddr{}
 | 
			
		||||
 | 
			
		||||
// Network returns the address's network name, "hvsock".
 | 
			
		||||
func (addr *HvsockAddr) Network() string {
 | 
			
		||||
func (*HvsockAddr) Network() string {
 | 
			
		||||
	return "hvsock"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -46,14 +122,14 @@ func (addr *HvsockAddr) String() string {
 | 
			
		||||
 | 
			
		||||
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
 | 
			
		||||
func VsockServiceID(port uint32) guid.GUID {
 | 
			
		||||
	g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
 | 
			
		||||
	g := hvsockVsockServiceTemplate() // make a copy
 | 
			
		||||
	g.Data1 = port
 | 
			
		||||
	return g
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (addr *HvsockAddr) raw() rawHvsockAddr {
 | 
			
		||||
	return rawHvsockAddr{
 | 
			
		||||
		Family:    afHvSock,
 | 
			
		||||
		Family:    afHVSock,
 | 
			
		||||
		VMID:      addr.VMID,
 | 
			
		||||
		ServiceID: addr.ServiceID,
 | 
			
		||||
	}
 | 
			
		||||
@@ -64,20 +140,48 @@ func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
 | 
			
		||||
	addr.ServiceID = raw.ServiceID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sockaddr returns a pointer to and the size of this struct.
 | 
			
		||||
//
 | 
			
		||||
// Implements the [socket.RawSockaddr] interface, and allows use in
 | 
			
		||||
// [socket.Bind] and [socket.ConnectEx].
 | 
			
		||||
func (r *rawHvsockAddr) Sockaddr() (unsafe.Pointer, int32, error) {
 | 
			
		||||
	return unsafe.Pointer(r), int32(unsafe.Sizeof(rawHvsockAddr{})), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sockaddr interface allows use with `sockets.Bind()` and `.ConnectEx()`.
 | 
			
		||||
func (r *rawHvsockAddr) FromBytes(b []byte) error {
 | 
			
		||||
	n := int(unsafe.Sizeof(rawHvsockAddr{}))
 | 
			
		||||
 | 
			
		||||
	if len(b) < n {
 | 
			
		||||
		return fmt.Errorf("got %d, want %d: %w", len(b), n, socket.ErrBufferSize)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	copy(unsafe.Slice((*byte)(unsafe.Pointer(r)), n), b[:n])
 | 
			
		||||
	if r.Family != afHVSock {
 | 
			
		||||
		return fmt.Errorf("got %d, want %d: %w", r.Family, afHVSock, socket.ErrAddrFamily)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockListener is a socket listener for the AF_HYPERV address family.
 | 
			
		||||
type HvsockListener struct {
 | 
			
		||||
	sock *win32File
 | 
			
		||||
	addr HvsockAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ net.Listener = &HvsockListener{}
 | 
			
		||||
 | 
			
		||||
// HvsockConn is a connected socket of the AF_HYPERV address family.
 | 
			
		||||
type HvsockConn struct {
 | 
			
		||||
	sock          *win32File
 | 
			
		||||
	local, remote HvsockAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newHvSocket() (*win32File, error) {
 | 
			
		||||
	fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
 | 
			
		||||
var _ net.Conn = &HvsockConn{}
 | 
			
		||||
 | 
			
		||||
func newHVSocket() (*win32File, error) {
 | 
			
		||||
	fd, err := syscall.Socket(afHVSock, syscall.SOCK_STREAM, 1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, os.NewSyscallError("socket", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -93,12 +197,12 @@ func newHvSocket() (*win32File, error) {
 | 
			
		||||
// ListenHvsock listens for connections on the specified hvsock address.
 | 
			
		||||
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
 | 
			
		||||
	l := &HvsockListener{addr: *addr}
 | 
			
		||||
	sock, err := newHvSocket()
 | 
			
		||||
	sock, err := newHVSocket()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("listen", err)
 | 
			
		||||
	}
 | 
			
		||||
	sa := addr.raw()
 | 
			
		||||
	err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa)))
 | 
			
		||||
	err = socket.Bind(windows.Handle(sock.handle), &sa)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("listen", os.NewSyscallError("socket", err))
 | 
			
		||||
	}
 | 
			
		||||
@@ -120,7 +224,7 @@ func (l *HvsockListener) Addr() net.Addr {
 | 
			
		||||
 | 
			
		||||
// Accept waits for the next connection and returns it.
 | 
			
		||||
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
 | 
			
		||||
	sock, err := newHvSocket()
 | 
			
		||||
	sock, err := newHVSocket()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("accept", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -129,27 +233,42 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
 | 
			
		||||
			sock.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	c, err := l.sock.prepareIo()
 | 
			
		||||
	c, err := l.sock.prepareIO()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("accept", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer l.sock.wg.Done()
 | 
			
		||||
 | 
			
		||||
	// AcceptEx, per documentation, requires an extra 16 bytes per address.
 | 
			
		||||
	//
 | 
			
		||||
	// https://docs.microsoft.com/en-us/windows/win32/api/mswsock/nf-mswsock-acceptex
 | 
			
		||||
	const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
 | 
			
		||||
	var addrbuf [addrlen * 2]byte
 | 
			
		||||
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
 | 
			
		||||
	_, err = l.sock.asyncIo(c, nil, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /*rxdatalen*/, addrlen, addrlen, &bytes, &c.o)
 | 
			
		||||
	if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
 | 
			
		||||
		return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn := &HvsockConn{
 | 
			
		||||
		sock: sock,
 | 
			
		||||
	}
 | 
			
		||||
	// The local address returned in the AcceptEx buffer is the same as the Listener socket's
 | 
			
		||||
	// address. However, the service GUID reported by GetSockName is different from the Listeners
 | 
			
		||||
	// socket, and is sometimes the same as the local address of the socket that dialed the
 | 
			
		||||
	// address, with the service GUID.Data1 incremented, but othertimes is different.
 | 
			
		||||
	// todo: does the local address matter? is the listener's address or the actual address appropriate?
 | 
			
		||||
	conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
 | 
			
		||||
	conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
 | 
			
		||||
 | 
			
		||||
	// initialize the accepted socket and update its properties with those of the listening socket
 | 
			
		||||
	if err = windows.Setsockopt(windows.Handle(sock.handle),
 | 
			
		||||
		windows.SOL_SOCKET, windows.SO_UPDATE_ACCEPT_CONTEXT,
 | 
			
		||||
		(*byte)(unsafe.Pointer(&l.sock.handle)), int32(unsafe.Sizeof(l.sock.handle))); err != nil {
 | 
			
		||||
		return nil, conn.opErr("accept", os.NewSyscallError("setsockopt", err))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sock = nil
 | 
			
		||||
	return conn, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -159,43 +278,171 @@ func (l *HvsockListener) Close() error {
 | 
			
		||||
	return l.sock.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Need to finish ConnectEx handling
 | 
			
		||||
func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
 | 
			
		||||
	sock, err := newHvSocket()
 | 
			
		||||
// HvsockDialer configures and dials a Hyper-V Socket (ie, [HvsockConn]).
 | 
			
		||||
type HvsockDialer struct {
 | 
			
		||||
	// Deadline is the time the Dial operation must connect before erroring.
 | 
			
		||||
	Deadline time.Time
 | 
			
		||||
 | 
			
		||||
	// Retries is the number of additional connects to try if the connection times out, is refused,
 | 
			
		||||
	// or the host is unreachable
 | 
			
		||||
	Retries uint
 | 
			
		||||
 | 
			
		||||
	// RetryWait is the time to wait after a connection error to retry
 | 
			
		||||
	RetryWait time.Duration
 | 
			
		||||
 | 
			
		||||
	rt *time.Timer // redial wait timer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial the Hyper-V socket at addr.
 | 
			
		||||
//
 | 
			
		||||
// See [HvsockDialer.Dial] for more information.
 | 
			
		||||
func Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
 | 
			
		||||
	return (&HvsockDialer{}).Dial(ctx, addr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Dial attempts to connect to the Hyper-V socket at addr, and returns a connection if successful.
 | 
			
		||||
// Will attempt (HvsockDialer).Retries if dialing fails, waiting (HvsockDialer).RetryWait between
 | 
			
		||||
// retries.
 | 
			
		||||
//
 | 
			
		||||
// Dialing can be cancelled either by providing (HvsockDialer).Deadline, or cancelling ctx.
 | 
			
		||||
func (d *HvsockDialer) Dial(ctx context.Context, addr *HvsockAddr) (conn *HvsockConn, err error) {
 | 
			
		||||
	op := "dial"
 | 
			
		||||
	// create the conn early to use opErr()
 | 
			
		||||
	conn = &HvsockConn{
 | 
			
		||||
		remote: *addr,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !d.Deadline.IsZero() {
 | 
			
		||||
		var cancel context.CancelFunc
 | 
			
		||||
		ctx, cancel = context.WithDeadline(ctx, d.Deadline)
 | 
			
		||||
		defer cancel()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// preemptive timeout/cancellation check
 | 
			
		||||
	if err = ctx.Err(); err != nil {
 | 
			
		||||
		return nil, conn.opErr(op, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sock, err := newHVSocket()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return nil, conn.opErr(op, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if sock != nil {
 | 
			
		||||
			sock.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	c, err := sock.prepareIo()
 | 
			
		||||
 | 
			
		||||
	sa := addr.raw()
 | 
			
		||||
	err = socket.Bind(windows.Handle(sock.handle), &sa)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return nil, conn.opErr(op, os.NewSyscallError("bind", err))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	c, err := sock.prepareIO()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, conn.opErr(op, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer sock.wg.Done()
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
 | 
			
		||||
	_, err = sock.asyncIo(ctx, c, nil, bytes, err)
 | 
			
		||||
	for i := uint(0); i <= d.Retries; i++ {
 | 
			
		||||
		err = socket.ConnectEx(
 | 
			
		||||
			windows.Handle(sock.handle),
 | 
			
		||||
			&sa,
 | 
			
		||||
			nil, // sendBuf
 | 
			
		||||
			0,   // sendDataLen
 | 
			
		||||
			&bytes,
 | 
			
		||||
			(*windows.Overlapped)(unsafe.Pointer(&c.o)))
 | 
			
		||||
		_, err = sock.asyncIO(c, nil, bytes, err)
 | 
			
		||||
		if i < d.Retries && canRedial(err) {
 | 
			
		||||
			if err = d.redialWait(ctx); err == nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		break
 | 
			
		||||
	}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
		return nil, conn.opErr(op, os.NewSyscallError("connectex", err))
 | 
			
		||||
	}
 | 
			
		||||
	conn := &HvsockConn{
 | 
			
		||||
		sock:   sock,
 | 
			
		||||
		remote: *addr,
 | 
			
		||||
 | 
			
		||||
	// update the connection properties, so shutdown can be used
 | 
			
		||||
	if err = windows.Setsockopt(
 | 
			
		||||
		windows.Handle(sock.handle),
 | 
			
		||||
		windows.SOL_SOCKET,
 | 
			
		||||
		windows.SO_UPDATE_CONNECT_CONTEXT,
 | 
			
		||||
		nil, // optvalue
 | 
			
		||||
		0,   // optlen
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return nil, conn.opErr(op, os.NewSyscallError("setsockopt", err))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get the local name
 | 
			
		||||
	var sal rawHvsockAddr
 | 
			
		||||
	err = socket.GetSockName(windows.Handle(sock.handle), &sal)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, conn.opErr(op, os.NewSyscallError("getsockname", err))
 | 
			
		||||
	}
 | 
			
		||||
	conn.local.fromRaw(&sal)
 | 
			
		||||
 | 
			
		||||
	// one last check for timeout, since asyncIO doesn't check the context
 | 
			
		||||
	if err = ctx.Err(); err != nil {
 | 
			
		||||
		return nil, conn.opErr(op, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	conn.sock = sock
 | 
			
		||||
	sock = nil
 | 
			
		||||
 | 
			
		||||
	return conn, nil
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// redialWait waits before attempting to redial, resetting the timer as appropriate.
 | 
			
		||||
func (d *HvsockDialer) redialWait(ctx context.Context) (err error) {
 | 
			
		||||
	if d.RetryWait == 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if d.rt == nil {
 | 
			
		||||
		d.rt = time.NewTimer(d.RetryWait)
 | 
			
		||||
	} else {
 | 
			
		||||
		// should already be stopped and drained
 | 
			
		||||
		d.rt.Reset(d.RetryWait)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
	case <-d.rt.C:
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// stop and drain the timer
 | 
			
		||||
	if !d.rt.Stop() {
 | 
			
		||||
		<-d.rt.C
 | 
			
		||||
	}
 | 
			
		||||
	return ctx.Err()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// assumes error is a plain, unwrapped syscall.Errno provided by direct syscall.
 | 
			
		||||
func canRedial(err error) bool {
 | 
			
		||||
	//nolint:errorlint // guaranteed to be an Errno
 | 
			
		||||
	switch err {
 | 
			
		||||
	case windows.WSAECONNREFUSED, windows.WSAENETUNREACH, windows.WSAETIMEDOUT,
 | 
			
		||||
		windows.ERROR_CONNECTION_REFUSED, windows.ERROR_CONNECTION_UNAVAIL:
 | 
			
		||||
		return true
 | 
			
		||||
	default:
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) opErr(op string, err error) error {
 | 
			
		||||
	// translate from "file closed" to "socket closed"
 | 
			
		||||
	if errors.Is(err, ErrFileClosed) {
 | 
			
		||||
		err = socket.ErrSocketClosed
 | 
			
		||||
	}
 | 
			
		||||
	return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) Read(b []byte) (int, error) {
 | 
			
		||||
	c, err := conn.sock.prepareIo()
 | 
			
		||||
	c, err := conn.sock.prepareIO()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, conn.opErr("read", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -203,10 +450,11 @@ func (conn *HvsockConn) Read(b []byte) (int, error) {
 | 
			
		||||
	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
 | 
			
		||||
	var flags, bytes uint32
 | 
			
		||||
	err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
 | 
			
		||||
	n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
 | 
			
		||||
	n, err := conn.sock.asyncIO(c, &conn.sock.readDeadline, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if _, ok := err.(syscall.Errno); ok {
 | 
			
		||||
			err = os.NewSyscallError("wsarecv", err)
 | 
			
		||||
		var eno windows.Errno
 | 
			
		||||
		if errors.As(err, &eno) {
 | 
			
		||||
			err = os.NewSyscallError("wsarecv", eno)
 | 
			
		||||
		}
 | 
			
		||||
		return 0, conn.opErr("read", err)
 | 
			
		||||
	} else if n == 0 {
 | 
			
		||||
@@ -229,7 +477,7 @@ func (conn *HvsockConn) Write(b []byte) (int, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) write(b []byte) (int, error) {
 | 
			
		||||
	c, err := conn.sock.prepareIo()
 | 
			
		||||
	c, err := conn.sock.prepareIO()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, conn.opErr("write", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -237,10 +485,11 @@ func (conn *HvsockConn) write(b []byte) (int, error) {
 | 
			
		||||
	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
 | 
			
		||||
	n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
 | 
			
		||||
	n, err := conn.sock.asyncIO(c, &conn.sock.writeDeadline, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if _, ok := err.(syscall.Errno); ok {
 | 
			
		||||
			err = os.NewSyscallError("wsasend", err)
 | 
			
		||||
		var eno windows.Errno
 | 
			
		||||
		if errors.As(err, &eno) {
 | 
			
		||||
			err = os.NewSyscallError("wsasend", eno)
 | 
			
		||||
		}
 | 
			
		||||
		return 0, conn.opErr("write", err)
 | 
			
		||||
	}
 | 
			
		||||
@@ -252,29 +501,43 @@ func (conn *HvsockConn) Close() error {
 | 
			
		||||
	return conn.sock.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) IsClosed() bool {
 | 
			
		||||
	return conn.sock.IsClosed()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// shutdown disables sending or receiving on a socket.
 | 
			
		||||
func (conn *HvsockConn) shutdown(how int) error {
 | 
			
		||||
	err := syscall.Shutdown(conn.sock.handle, syscall.SHUT_RD)
 | 
			
		||||
	if conn.IsClosed() {
 | 
			
		||||
		return socket.ErrSocketClosed
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := syscall.Shutdown(conn.sock.handle, how)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// If the connection was closed, shutdowns fail with "not connected"
 | 
			
		||||
		if errors.Is(err, windows.WSAENOTCONN) ||
 | 
			
		||||
			errors.Is(err, windows.WSAESHUTDOWN) {
 | 
			
		||||
			err = socket.ErrSocketClosed
 | 
			
		||||
		}
 | 
			
		||||
		return os.NewSyscallError("shutdown", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloseRead shuts down the read end of the socket.
 | 
			
		||||
// CloseRead shuts down the read end of the socket, preventing future read operations.
 | 
			
		||||
func (conn *HvsockConn) CloseRead() error {
 | 
			
		||||
	err := conn.shutdown(syscall.SHUT_RD)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return conn.opErr("close", err)
 | 
			
		||||
		return conn.opErr("closeread", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloseWrite shuts down the write end of the socket, notifying the other endpoint that
 | 
			
		||||
// no more data will be written.
 | 
			
		||||
// CloseWrite shuts down the write end of the socket, preventing future write operations and
 | 
			
		||||
// notifying the other endpoint that no more data will be written.
 | 
			
		||||
func (conn *HvsockConn) CloseWrite() error {
 | 
			
		||||
	err := conn.shutdown(syscall.SHUT_WR)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return conn.opErr("close", err)
 | 
			
		||||
		return conn.opErr("closewrite", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
@@ -291,8 +554,13 @@ func (conn *HvsockConn) RemoteAddr() net.Addr {
 | 
			
		||||
 | 
			
		||||
// SetDeadline implements the net.Conn SetDeadline method.
 | 
			
		||||
func (conn *HvsockConn) SetDeadline(t time.Time) error {
 | 
			
		||||
	conn.SetReadDeadline(t)
 | 
			
		||||
	conn.SetWriteDeadline(t)
 | 
			
		||||
	// todo: implement `SetDeadline` for `win32File`
 | 
			
		||||
	if err := conn.SetReadDeadline(t); err != nil {
 | 
			
		||||
		return fmt.Errorf("set read deadline: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err := conn.SetWriteDeadline(t); err != nil {
 | 
			
		||||
		return fmt.Errorf("set write deadline: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/Microsoft/go-winio/internal/socket/rawaddr.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
package socket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// RawSockaddr allows structs to be used with [Bind] and [ConnectEx]. The
 | 
			
		||||
// struct must meet the Win32 sockaddr requirements specified here:
 | 
			
		||||
// https://docs.microsoft.com/en-us/windows/win32/winsock/sockaddr-2
 | 
			
		||||
//
 | 
			
		||||
// Specifically, the struct size must be least larger than an int16 (unsigned short)
 | 
			
		||||
// for the address family.
 | 
			
		||||
type RawSockaddr interface {
 | 
			
		||||
	// Sockaddr returns a pointer to the RawSockaddr and its struct size, allowing
 | 
			
		||||
	// for the RawSockaddr's data to be overwritten by syscalls (if necessary).
 | 
			
		||||
	//
 | 
			
		||||
	// It is the callers responsibility to validate that the values are valid; invalid
 | 
			
		||||
	// pointers or size can cause a panic.
 | 
			
		||||
	Sockaddr() (unsafe.Pointer, int32, error)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										179
									
								
								vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								vendor/github.com/Microsoft/go-winio/internal/socket/socket.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,179 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
 | 
			
		||||
package socket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/Microsoft/go-winio/pkg/guid"
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go socket.go
 | 
			
		||||
 | 
			
		||||
//sys getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getsockname
 | 
			
		||||
//sys getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) [failretval==socketError] = ws2_32.getpeername
 | 
			
		||||
//sys bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
 | 
			
		||||
 | 
			
		||||
const socketError = uintptr(^uint32(0))
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// todo(helsaawy): create custom error types to store the desired vs actual size and addr family?
 | 
			
		||||
 | 
			
		||||
	ErrBufferSize     = errors.New("buffer size")
 | 
			
		||||
	ErrAddrFamily     = errors.New("address family")
 | 
			
		||||
	ErrInvalidPointer = errors.New("invalid pointer")
 | 
			
		||||
	ErrSocketClosed   = fmt.Errorf("socket closed: %w", net.ErrClosed)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// todo(helsaawy): replace these with generics, ie: GetSockName[S RawSockaddr](s windows.Handle) (S, error)
 | 
			
		||||
 | 
			
		||||
// GetSockName writes the local address of socket s to the [RawSockaddr] rsa.
 | 
			
		||||
// If rsa is not large enough, the [windows.WSAEFAULT] is returned.
 | 
			
		||||
func GetSockName(s windows.Handle, rsa RawSockaddr) error {
 | 
			
		||||
	ptr, l, err := rsa.Sockaddr()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// although getsockname returns WSAEFAULT if the buffer is too small, it does not set
 | 
			
		||||
	// &l to the correct size, so--apart from doubling the buffer repeatedly--there is no remedy
 | 
			
		||||
	return getsockname(s, ptr, &l)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetPeerName returns the remote address the socket is connected to.
 | 
			
		||||
//
 | 
			
		||||
// See [GetSockName] for more information.
 | 
			
		||||
func GetPeerName(s windows.Handle, rsa RawSockaddr) error {
 | 
			
		||||
	ptr, l, err := rsa.Sockaddr()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return getpeername(s, ptr, &l)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Bind(s windows.Handle, rsa RawSockaddr) (err error) {
 | 
			
		||||
	ptr, l, err := rsa.Sockaddr()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("could not retrieve socket pointer and size: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return bind(s, ptr, l)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// "golang.org/x/sys/windows".ConnectEx and .Bind only accept internal implementations of the
 | 
			
		||||
// their sockaddr interface, so they cannot be used with HvsockAddr
 | 
			
		||||
// Replicate functionality here from
 | 
			
		||||
// https://cs.opensource.google/go/x/sys/+/master:windows/syscall_windows.go
 | 
			
		||||
 | 
			
		||||
// The function pointers to `AcceptEx`, `ConnectEx` and `GetAcceptExSockaddrs` must be loaded at
 | 
			
		||||
// runtime via a WSAIoctl call:
 | 
			
		||||
// https://docs.microsoft.com/en-us/windows/win32/api/Mswsock/nc-mswsock-lpfn_connectex#remarks
 | 
			
		||||
 | 
			
		||||
type runtimeFunc struct {
 | 
			
		||||
	id   guid.GUID
 | 
			
		||||
	once sync.Once
 | 
			
		||||
	addr uintptr
 | 
			
		||||
	err  error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *runtimeFunc) Load() error {
 | 
			
		||||
	f.once.Do(func() {
 | 
			
		||||
		var s windows.Handle
 | 
			
		||||
		s, f.err = windows.Socket(windows.AF_INET, windows.SOCK_STREAM, windows.IPPROTO_TCP)
 | 
			
		||||
		if f.err != nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		defer windows.CloseHandle(s) //nolint:errcheck
 | 
			
		||||
 | 
			
		||||
		var n uint32
 | 
			
		||||
		f.err = windows.WSAIoctl(s,
 | 
			
		||||
			windows.SIO_GET_EXTENSION_FUNCTION_POINTER,
 | 
			
		||||
			(*byte)(unsafe.Pointer(&f.id)),
 | 
			
		||||
			uint32(unsafe.Sizeof(f.id)),
 | 
			
		||||
			(*byte)(unsafe.Pointer(&f.addr)),
 | 
			
		||||
			uint32(unsafe.Sizeof(f.addr)),
 | 
			
		||||
			&n,
 | 
			
		||||
			nil, //overlapped
 | 
			
		||||
			0,   //completionRoutine
 | 
			
		||||
		)
 | 
			
		||||
	})
 | 
			
		||||
	return f.err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// todo: add `AcceptEx` and `GetAcceptExSockaddrs`
 | 
			
		||||
	WSAID_CONNECTEX = guid.GUID{ //revive:disable-line:var-naming ALL_CAPS
 | 
			
		||||
		Data1: 0x25a207b9,
 | 
			
		||||
		Data2: 0xddf3,
 | 
			
		||||
		Data3: 0x4660,
 | 
			
		||||
		Data4: [8]byte{0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	connectExFunc = runtimeFunc{id: WSAID_CONNECTEX}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func ConnectEx(
 | 
			
		||||
	fd windows.Handle,
 | 
			
		||||
	rsa RawSockaddr,
 | 
			
		||||
	sendBuf *byte,
 | 
			
		||||
	sendDataLen uint32,
 | 
			
		||||
	bytesSent *uint32,
 | 
			
		||||
	overlapped *windows.Overlapped,
 | 
			
		||||
) error {
 | 
			
		||||
	if err := connectExFunc.Load(); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to load ConnectEx function pointer: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	ptr, n, err := rsa.Sockaddr()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BOOL LpfnConnectex(
 | 
			
		||||
//   [in]           SOCKET s,
 | 
			
		||||
//   [in]           const sockaddr *name,
 | 
			
		||||
//   [in]           int namelen,
 | 
			
		||||
//   [in, optional] PVOID lpSendBuffer,
 | 
			
		||||
//   [in]           DWORD dwSendDataLength,
 | 
			
		||||
//   [out]          LPDWORD lpdwBytesSent,
 | 
			
		||||
//   [in]           LPOVERLAPPED lpOverlapped
 | 
			
		||||
// )
 | 
			
		||||
 | 
			
		||||
func connectEx(
 | 
			
		||||
	s windows.Handle,
 | 
			
		||||
	name unsafe.Pointer,
 | 
			
		||||
	namelen int32,
 | 
			
		||||
	sendBuf *byte,
 | 
			
		||||
	sendDataLen uint32,
 | 
			
		||||
	bytesSent *uint32,
 | 
			
		||||
	overlapped *windows.Overlapped,
 | 
			
		||||
) (err error) {
 | 
			
		||||
	// todo: after upgrading to 1.18, switch from syscall.Syscall9 to syscall.SyscallN
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(connectExFunc.addr,
 | 
			
		||||
		7,
 | 
			
		||||
		uintptr(s),
 | 
			
		||||
		uintptr(name),
 | 
			
		||||
		uintptr(namelen),
 | 
			
		||||
		uintptr(unsafe.Pointer(sendBuf)),
 | 
			
		||||
		uintptr(sendDataLen),
 | 
			
		||||
		uintptr(unsafe.Pointer(bytesSent)),
 | 
			
		||||
		uintptr(unsafe.Pointer(overlapped)),
 | 
			
		||||
		0,
 | 
			
		||||
		0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = error(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										72
									
								
								vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								vendor/github.com/Microsoft/go-winio/internal/socket/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
 | 
			
		||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package socket
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ unsafe.Pointer
 | 
			
		||||
 | 
			
		||||
// Do the interface allocations only once for common
 | 
			
		||||
// Errno values.
 | 
			
		||||
const (
 | 
			
		||||
	errnoERROR_IO_PENDING = 997
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
 | 
			
		||||
	errERROR_EINVAL     error = syscall.EINVAL
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// errnoErr returns common boxed Errno values, to prevent
 | 
			
		||||
// allocations at runtime.
 | 
			
		||||
func errnoErr(e syscall.Errno) error {
 | 
			
		||||
	switch e {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return errERROR_EINVAL
 | 
			
		||||
	case errnoERROR_IO_PENDING:
 | 
			
		||||
		return errERROR_IO_PENDING
 | 
			
		||||
	}
 | 
			
		||||
	// TODO: add more here, after collecting data on the common
 | 
			
		||||
	// error values see on Windows. (perhaps when running
 | 
			
		||||
	// all.bat?)
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
 | 
			
		||||
 | 
			
		||||
	procbind        = modws2_32.NewProc("bind")
 | 
			
		||||
	procgetpeername = modws2_32.NewProc("getpeername")
 | 
			
		||||
	procgetsockname = modws2_32.NewProc("getsockname")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
 | 
			
		||||
	if r1 == socketError {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getpeername(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procgetpeername.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
 | 
			
		||||
	if r1 == socketError {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getsockname(s windows.Handle, name unsafe.Pointer, namelen *int32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procgetsockname.Addr(), 3, uintptr(s), uintptr(name), uintptr(unsafe.Pointer(namelen)))
 | 
			
		||||
	if r1 == socketError {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										124
									
								
								vendor/github.com/Microsoft/go-winio/pipe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										124
									
								
								vendor/github.com/Microsoft/go-winio/pipe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
@@ -13,6 +14,8 @@ import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
 | 
			
		||||
@@ -21,10 +24,10 @@ import (
 | 
			
		||||
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
 | 
			
		||||
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
 | 
			
		||||
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
 | 
			
		||||
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile
 | 
			
		||||
//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
 | 
			
		||||
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U
 | 
			
		||||
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl
 | 
			
		||||
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) = ntdll.NtCreateNamedPipeFile
 | 
			
		||||
//sys rtlNtStatusToDosError(status ntStatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
 | 
			
		||||
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U
 | 
			
		||||
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl
 | 
			
		||||
 | 
			
		||||
type ioStatusBlock struct {
 | 
			
		||||
	Status, Information uintptr
 | 
			
		||||
@@ -51,45 +54,22 @@ type securityDescriptor struct {
 | 
			
		||||
	Control  uint16
 | 
			
		||||
	Owner    uintptr
 | 
			
		||||
	Group    uintptr
 | 
			
		||||
	Sacl     uintptr
 | 
			
		||||
	Dacl     uintptr
 | 
			
		||||
	Sacl     uintptr //revive:disable-line:var-naming SACL, not Sacl
 | 
			
		||||
	Dacl     uintptr //revive:disable-line:var-naming DACL, not Dacl
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ntstatus int32
 | 
			
		||||
type ntStatus int32
 | 
			
		||||
 | 
			
		||||
func (status ntstatus) Err() error {
 | 
			
		||||
func (status ntStatus) Err() error {
 | 
			
		||||
	if status >= 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return rtlNtStatusToDosError(status)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	cERROR_PIPE_BUSY      = syscall.Errno(231)
 | 
			
		||||
	cERROR_NO_DATA        = syscall.Errno(232)
 | 
			
		||||
	cERROR_PIPE_CONNECTED = syscall.Errno(535)
 | 
			
		||||
	cERROR_SEM_TIMEOUT    = syscall.Errno(121)
 | 
			
		||||
 | 
			
		||||
	cSECURITY_SQOS_PRESENT = 0x100000
 | 
			
		||||
	cSECURITY_ANONYMOUS    = 0
 | 
			
		||||
 | 
			
		||||
	cPIPE_TYPE_MESSAGE = 4
 | 
			
		||||
 | 
			
		||||
	cPIPE_READMODE_MESSAGE = 2
 | 
			
		||||
 | 
			
		||||
	cFILE_OPEN   = 1
 | 
			
		||||
	cFILE_CREATE = 2
 | 
			
		||||
 | 
			
		||||
	cFILE_PIPE_MESSAGE_TYPE          = 1
 | 
			
		||||
	cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2
 | 
			
		||||
 | 
			
		||||
	cSE_DACL_PRESENT = 4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
 | 
			
		||||
	// This error should match net.errClosing since docker takes a dependency on its text.
 | 
			
		||||
	ErrPipeListenerClosed = errors.New("use of closed network connection")
 | 
			
		||||
	ErrPipeListenerClosed = net.ErrClosed
 | 
			
		||||
 | 
			
		||||
	errPipeWriteClosed = errors.New("pipe has been closed for write")
 | 
			
		||||
)
 | 
			
		||||
@@ -116,9 +96,10 @@ func (f *win32Pipe) RemoteAddr() net.Addr {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32Pipe) SetDeadline(t time.Time) error {
 | 
			
		||||
	f.SetReadDeadline(t)
 | 
			
		||||
	f.SetWriteDeadline(t)
 | 
			
		||||
	return nil
 | 
			
		||||
	if err := f.SetReadDeadline(t); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return f.SetWriteDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloseWrite closes the write side of a message pipe in byte mode.
 | 
			
		||||
@@ -157,14 +138,14 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	n, err := f.win32File.Read(b)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
	if err == io.EOF { //nolint:errorlint
 | 
			
		||||
		// If this was the result of a zero-byte read, then
 | 
			
		||||
		// it is possible that the read was due to a zero-size
 | 
			
		||||
		// message. Since we are simulating CloseWrite with a
 | 
			
		||||
		// zero-byte message, ensure that all future Read() calls
 | 
			
		||||
		// also return EOF.
 | 
			
		||||
		f.readEOF = true
 | 
			
		||||
	} else if err == syscall.ERROR_MORE_DATA {
 | 
			
		||||
	} else if err == syscall.ERROR_MORE_DATA { //nolint:errorlint // err is Errno
 | 
			
		||||
		// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
 | 
			
		||||
		// and the message still has more bytes. Treat this as a success, since
 | 
			
		||||
		// this package presents all named pipes as byte streams.
 | 
			
		||||
@@ -173,7 +154,7 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s pipeAddress) Network() string {
 | 
			
		||||
func (pipeAddress) Network() string {
 | 
			
		||||
	return "pipe"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -184,16 +165,21 @@ func (s pipeAddress) String() string {
 | 
			
		||||
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
 | 
			
		||||
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
 | 
			
		||||
	for {
 | 
			
		||||
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			return syscall.Handle(0), ctx.Err()
 | 
			
		||||
		default:
 | 
			
		||||
			h, err := createFile(*path, access, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
 | 
			
		||||
			h, err := createFile(*path,
 | 
			
		||||
				access,
 | 
			
		||||
				0,
 | 
			
		||||
				nil,
 | 
			
		||||
				syscall.OPEN_EXISTING,
 | 
			
		||||
				windows.FILE_FLAG_OVERLAPPED|windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS,
 | 
			
		||||
				0)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				return h, nil
 | 
			
		||||
			}
 | 
			
		||||
			if err != cERROR_PIPE_BUSY {
 | 
			
		||||
			if err != windows.ERROR_PIPE_BUSY { //nolint:errorlint // err is Errno
 | 
			
		||||
				return h, &os.PathError{Err: err, Op: "open", Path: *path}
 | 
			
		||||
			}
 | 
			
		||||
			// Wait 10 msec and try again. This is a rather simplistic
 | 
			
		||||
@@ -213,9 +199,10 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
 | 
			
		||||
	} else {
 | 
			
		||||
		absTimeout = time.Now().Add(2 * time.Second)
 | 
			
		||||
	}
 | 
			
		||||
	ctx, _ := context.WithDeadline(context.Background(), absTimeout)
 | 
			
		||||
	ctx, cancel := context.WithDeadline(context.Background(), absTimeout)
 | 
			
		||||
	defer cancel()
 | 
			
		||||
	conn, err := DialPipeContext(ctx, path)
 | 
			
		||||
	if err == context.DeadlineExceeded {
 | 
			
		||||
	if errors.Is(err, context.DeadlineExceeded) {
 | 
			
		||||
		return nil, ErrTimeout
 | 
			
		||||
	}
 | 
			
		||||
	return conn, err
 | 
			
		||||
@@ -251,7 +238,7 @@ func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn,
 | 
			
		||||
 | 
			
		||||
	// If the pipe is in message mode, return a message byte pipe, which
 | 
			
		||||
	// supports CloseWrite().
 | 
			
		||||
	if flags&cPIPE_TYPE_MESSAGE != 0 {
 | 
			
		||||
	if flags&windows.PIPE_TYPE_MESSAGE != 0 {
 | 
			
		||||
		return &win32MessageBytePipe{
 | 
			
		||||
			win32Pipe: win32Pipe{win32File: f, path: path},
 | 
			
		||||
		}, nil
 | 
			
		||||
@@ -283,7 +270,11 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
 | 
			
		||||
	oa.Length = unsafe.Sizeof(oa)
 | 
			
		||||
 | 
			
		||||
	var ntPath unicodeString
 | 
			
		||||
	if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil {
 | 
			
		||||
	if err := rtlDosPathNameToNtPathName(&path16[0],
 | 
			
		||||
		&ntPath,
 | 
			
		||||
		0,
 | 
			
		||||
		0,
 | 
			
		||||
	).Err(); err != nil {
 | 
			
		||||
		return 0, &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	defer localFree(ntPath.Buffer)
 | 
			
		||||
@@ -292,8 +283,8 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
 | 
			
		||||
	// The security descriptor is only needed for the first pipe.
 | 
			
		||||
	if first {
 | 
			
		||||
		if sd != nil {
 | 
			
		||||
			len := uint32(len(sd))
 | 
			
		||||
			sdb := localAlloc(0, len)
 | 
			
		||||
			l := uint32(len(sd))
 | 
			
		||||
			sdb := localAlloc(0, l)
 | 
			
		||||
			defer localFree(sdb)
 | 
			
		||||
			copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
 | 
			
		||||
			oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
 | 
			
		||||
@@ -301,28 +292,28 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
 | 
			
		||||
			// Construct the default named pipe security descriptor.
 | 
			
		||||
			var dacl uintptr
 | 
			
		||||
			if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
 | 
			
		||||
				return 0, fmt.Errorf("getting default named pipe ACL: %s", err)
 | 
			
		||||
				return 0, fmt.Errorf("getting default named pipe ACL: %w", err)
 | 
			
		||||
			}
 | 
			
		||||
			defer localFree(dacl)
 | 
			
		||||
 | 
			
		||||
			sdb := &securityDescriptor{
 | 
			
		||||
				Revision: 1,
 | 
			
		||||
				Control:  cSE_DACL_PRESENT,
 | 
			
		||||
				Control:  windows.SE_DACL_PRESENT,
 | 
			
		||||
				Dacl:     dacl,
 | 
			
		||||
			}
 | 
			
		||||
			oa.SecurityDescriptor = sdb
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS)
 | 
			
		||||
	typ := uint32(windows.FILE_PIPE_REJECT_REMOTE_CLIENTS)
 | 
			
		||||
	if c.MessageMode {
 | 
			
		||||
		typ |= cFILE_PIPE_MESSAGE_TYPE
 | 
			
		||||
		typ |= windows.FILE_PIPE_MESSAGE_TYPE
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disposition := uint32(cFILE_OPEN)
 | 
			
		||||
	disposition := uint32(windows.FILE_OPEN)
 | 
			
		||||
	access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
 | 
			
		||||
	if first {
 | 
			
		||||
		disposition = cFILE_CREATE
 | 
			
		||||
		disposition = windows.FILE_CREATE
 | 
			
		||||
		// By not asking for read or write access, the named pipe file system
 | 
			
		||||
		// will put this pipe into an initially disconnected state, blocking
 | 
			
		||||
		// client connections until the next call with first == false.
 | 
			
		||||
@@ -335,7 +326,20 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
 | 
			
		||||
		h    syscall.Handle
 | 
			
		||||
		iosb ioStatusBlock
 | 
			
		||||
	)
 | 
			
		||||
	err = ntCreateNamedPipeFile(&h, access, &oa, &iosb, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout).Err()
 | 
			
		||||
	err = ntCreateNamedPipeFile(&h,
 | 
			
		||||
		access,
 | 
			
		||||
		&oa,
 | 
			
		||||
		&iosb,
 | 
			
		||||
		syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE,
 | 
			
		||||
		disposition,
 | 
			
		||||
		0,
 | 
			
		||||
		typ,
 | 
			
		||||
		0,
 | 
			
		||||
		0,
 | 
			
		||||
		0xffffffff,
 | 
			
		||||
		uint32(c.InputBufferSize),
 | 
			
		||||
		uint32(c.OutputBufferSize),
 | 
			
		||||
		&timeout).Err()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
@@ -380,7 +384,7 @@ func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) {
 | 
			
		||||
		p.Close()
 | 
			
		||||
		p = nil
 | 
			
		||||
		err = <-ch
 | 
			
		||||
		if err == nil || err == ErrFileClosed {
 | 
			
		||||
		if err == nil || err == ErrFileClosed { //nolint:errorlint // err is Errno
 | 
			
		||||
			err = ErrPipeListenerClosed
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -402,12 +406,12 @@ func (l *win32PipeListener) listenerRoutine() {
 | 
			
		||||
				p, err = l.makeConnectedServerPipe()
 | 
			
		||||
				// If the connection was immediately closed by the client, try
 | 
			
		||||
				// again.
 | 
			
		||||
				if err != cERROR_NO_DATA {
 | 
			
		||||
				if err != windows.ERROR_NO_DATA { //nolint:errorlint // err is Errno
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			responseCh <- acceptResponse{p, err}
 | 
			
		||||
			closed = err == ErrPipeListenerClosed
 | 
			
		||||
			closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	syscall.Close(l.firstHandle)
 | 
			
		||||
@@ -469,15 +473,15 @@ func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func connectPipe(p *win32File) error {
 | 
			
		||||
	c, err := p.prepareIo()
 | 
			
		||||
	c, err := p.prepareIO()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer p.wg.Done()
 | 
			
		||||
 | 
			
		||||
	err = connectNamedPipe(p.handle, &c.o)
 | 
			
		||||
	_, err = p.asyncIo(c, nil, 0, err)
 | 
			
		||||
	if err != nil && err != cERROR_PIPE_CONNECTED {
 | 
			
		||||
	_, err = p.asyncIO(c, nil, 0, err)
 | 
			
		||||
	if err != nil && err != windows.ERROR_PIPE_CONNECTED { //nolint:errorlint // err is Errno
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,5 +1,3 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
// Package guid provides a GUID type. The backing structure for a GUID is
 | 
			
		||||
// identical to that used by the golang.org/x/sys/windows GUID type.
 | 
			
		||||
// There are two main binary encodings used for a GUID, the big-endian encoding,
 | 
			
		||||
@@ -9,26 +7,26 @@ package guid
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"crypto/sha1" //nolint:gosec // not used for secure application
 | 
			
		||||
	"encoding"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//go:generate go run golang.org/x/tools/cmd/stringer -type=Variant -trimprefix=Variant -linecomment
 | 
			
		||||
 | 
			
		||||
// Variant specifies which GUID variant (or "type") of the GUID. It determines
 | 
			
		||||
// how the entirety of the rest of the GUID is interpreted.
 | 
			
		||||
type Variant uint8
 | 
			
		||||
 | 
			
		||||
// The variants specified by RFC 4122.
 | 
			
		||||
// The variants specified by RFC 4122 section 4.1.1.
 | 
			
		||||
const (
 | 
			
		||||
	// VariantUnknown specifies a GUID variant which does not conform to one of
 | 
			
		||||
	// the variant encodings specified in RFC 4122.
 | 
			
		||||
	VariantUnknown Variant = iota
 | 
			
		||||
	VariantNCS
 | 
			
		||||
	VariantRFC4122
 | 
			
		||||
	VariantRFC4122 // RFC 4122
 | 
			
		||||
	VariantMicrosoft
 | 
			
		||||
	VariantFuture
 | 
			
		||||
)
 | 
			
		||||
@@ -38,16 +36,13 @@ const (
 | 
			
		||||
// hash of an input string.
 | 
			
		||||
type Version uint8
 | 
			
		||||
 | 
			
		||||
func (v Version) String() string {
 | 
			
		||||
	return strconv.FormatUint(uint64(v), 10)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var _ = (encoding.TextMarshaler)(GUID{})
 | 
			
		||||
var _ = (encoding.TextUnmarshaler)(&GUID{})
 | 
			
		||||
 | 
			
		||||
// GUID represents a GUID/UUID. It has the same structure as
 | 
			
		||||
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
 | 
			
		||||
// that type. It is defined as its own type so that stringification and
 | 
			
		||||
// marshaling can be supported. The representation matches that used by native
 | 
			
		||||
// Windows code.
 | 
			
		||||
type GUID windows.GUID
 | 
			
		||||
 | 
			
		||||
// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
 | 
			
		||||
func NewV4() (GUID, error) {
 | 
			
		||||
	var b [16]byte
 | 
			
		||||
@@ -70,7 +65,7 @@ func NewV4() (GUID, error) {
 | 
			
		||||
// big-endian UTF16 stream of bytes. If that is desired, the string can be
 | 
			
		||||
// encoded as such before being passed to this function.
 | 
			
		||||
func NewV5(namespace GUID, name []byte) (GUID, error) {
 | 
			
		||||
	b := sha1.New()
 | 
			
		||||
	b := sha1.New() //nolint:gosec // not used for secure application
 | 
			
		||||
	namespaceBytes := namespace.ToArray()
 | 
			
		||||
	b.Write(namespaceBytes[:])
 | 
			
		||||
	b.Write(name)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
//go:build !windows
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
package guid
 | 
			
		||||
 | 
			
		||||
// GUID represents a GUID/UUID. It has the same structure as
 | 
			
		||||
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
 | 
			
		||||
// that type. It is defined as its own type as that is only available to builds
 | 
			
		||||
// targeted at `windows`. The representation matches that used by native Windows
 | 
			
		||||
// code.
 | 
			
		||||
type GUID struct {
 | 
			
		||||
	Data1 uint32
 | 
			
		||||
	Data2 uint16
 | 
			
		||||
	Data3 uint16
 | 
			
		||||
	Data4 [8]byte
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package guid
 | 
			
		||||
 | 
			
		||||
import "golang.org/x/sys/windows"
 | 
			
		||||
 | 
			
		||||
// GUID represents a GUID/UUID. It has the same structure as
 | 
			
		||||
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
 | 
			
		||||
// that type. It is defined as its own type so that stringification and
 | 
			
		||||
// marshaling can be supported. The representation matches that used by native
 | 
			
		||||
// Windows code.
 | 
			
		||||
type GUID windows.GUID
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/variant_string.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
// Code generated by "stringer -type=Variant -trimprefix=Variant -linecomment"; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package guid
 | 
			
		||||
 | 
			
		||||
import "strconv"
 | 
			
		||||
 | 
			
		||||
func _() {
 | 
			
		||||
	// An "invalid array index" compiler error signifies that the constant values have changed.
 | 
			
		||||
	// Re-run the stringer command to generate them again.
 | 
			
		||||
	var x [1]struct{}
 | 
			
		||||
	_ = x[VariantUnknown-0]
 | 
			
		||||
	_ = x[VariantNCS-1]
 | 
			
		||||
	_ = x[VariantRFC4122-2]
 | 
			
		||||
	_ = x[VariantMicrosoft-3]
 | 
			
		||||
	_ = x[VariantFuture-4]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const _Variant_name = "UnknownNCSRFC 4122MicrosoftFuture"
 | 
			
		||||
 | 
			
		||||
var _Variant_index = [...]uint8{0, 7, 10, 18, 27, 33}
 | 
			
		||||
 | 
			
		||||
func (i Variant) String() string {
 | 
			
		||||
	if i >= Variant(len(_Variant_index)-1) {
 | 
			
		||||
		return "Variant(" + strconv.FormatInt(int64(i), 10) + ")"
 | 
			
		||||
	}
 | 
			
		||||
	return _Variant_name[_Variant_index[i]:_Variant_index[i+1]]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								vendor/github.com/Microsoft/go-winio/pkg/security/grantvmgroupaccess.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/Microsoft/go-winio/pkg/security/grantvmgroupaccess.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,13 +1,13 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package security
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
@@ -21,6 +21,7 @@ type (
 | 
			
		||||
	trusteeForm         uint32
 | 
			
		||||
	trusteeType         uint32
 | 
			
		||||
 | 
			
		||||
	//nolint:structcheck // structcheck thinks fields are unused, but the are used to pass data to OS
 | 
			
		||||
	explicitAccess struct {
 | 
			
		||||
		accessPermissions accessMask
 | 
			
		||||
		accessMode        accessMode
 | 
			
		||||
@@ -28,6 +29,7 @@ type (
 | 
			
		||||
		trustee           trustee
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//nolint:structcheck,unused // structcheck thinks fields are unused, but the are used to pass data to OS
 | 
			
		||||
	trustee struct {
 | 
			
		||||
		multipleTrustee          *trustee
 | 
			
		||||
		multipleTrusteeOperation int32
 | 
			
		||||
@@ -45,6 +47,7 @@ const (
 | 
			
		||||
	desiredAccessReadControl desiredAccess = 0x20000
 | 
			
		||||
	desiredAccessWriteDac    desiredAccess = 0x40000
 | 
			
		||||
 | 
			
		||||
	//cspell:disable-next-line
 | 
			
		||||
	gvmga = "GrantVmGroupAccess:"
 | 
			
		||||
 | 
			
		||||
	inheritModeNoInheritance                  inheritMode = 0x0
 | 
			
		||||
@@ -57,9 +60,9 @@ const (
 | 
			
		||||
	shareModeRead  shareMode = 0x1
 | 
			
		||||
	shareModeWrite shareMode = 0x2
 | 
			
		||||
 | 
			
		||||
	sidVmGroup = "S-1-5-83-0"
 | 
			
		||||
	sidVMGroup = "S-1-5-83-0"
 | 
			
		||||
 | 
			
		||||
	trusteeFormIsSid trusteeForm = 0
 | 
			
		||||
	trusteeFormIsSID trusteeForm = 0
 | 
			
		||||
 | 
			
		||||
	trusteeTypeWellKnownGroup trusteeType = 5
 | 
			
		||||
)
 | 
			
		||||
@@ -68,11 +71,13 @@ const (
 | 
			
		||||
// include Grant ACE entries for the VM Group SID. This is a golang re-
 | 
			
		||||
// implementation of the same function in vmcompute, just not exported in
 | 
			
		||||
// RS5. Which kind of sucks. Sucks a lot :/
 | 
			
		||||
//
 | 
			
		||||
//revive:disable-next-line:var-naming VM, not Vm
 | 
			
		||||
func GrantVmGroupAccess(name string) error {
 | 
			
		||||
	// Stat (to determine if `name` is a directory).
 | 
			
		||||
	s, err := os.Stat(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "%s os.Stat %s", gvmga, name)
 | 
			
		||||
		return fmt.Errorf("%s os.Stat %s: %w", gvmga, name, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get a handle to the file/directory. Must defer Close on success.
 | 
			
		||||
@@ -80,7 +85,7 @@ func GrantVmGroupAccess(name string) error {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err // Already wrapped
 | 
			
		||||
	}
 | 
			
		||||
	defer syscall.CloseHandle(fd)
 | 
			
		||||
	defer syscall.CloseHandle(fd) //nolint:errcheck
 | 
			
		||||
 | 
			
		||||
	// Get the current DACL and Security Descriptor. Must defer LocalFree on success.
 | 
			
		||||
	ot := objectTypeFileObject
 | 
			
		||||
@@ -88,9 +93,9 @@ func GrantVmGroupAccess(name string) error {
 | 
			
		||||
	sd := uintptr(0)
 | 
			
		||||
	origDACL := uintptr(0)
 | 
			
		||||
	if err := getSecurityInfo(fd, uint32(ot), uint32(si), nil, nil, &origDACL, nil, &sd); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "%s GetSecurityInfo %s", gvmga, name)
 | 
			
		||||
		return fmt.Errorf("%s GetSecurityInfo %s: %w", gvmga, name, err)
 | 
			
		||||
	}
 | 
			
		||||
	defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd)))
 | 
			
		||||
	defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(sd))) //nolint:errcheck
 | 
			
		||||
 | 
			
		||||
	// Generate a new DACL which is the current DACL with the required ACEs added.
 | 
			
		||||
	// Must defer LocalFree on success.
 | 
			
		||||
@@ -98,11 +103,11 @@ func GrantVmGroupAccess(name string) error {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err // Already wrapped
 | 
			
		||||
	}
 | 
			
		||||
	defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL)))
 | 
			
		||||
	defer syscall.LocalFree((syscall.Handle)(unsafe.Pointer(newDACL))) //nolint:errcheck
 | 
			
		||||
 | 
			
		||||
	// And finally use SetSecurityInfo to apply the updated DACL.
 | 
			
		||||
	if err := setSecurityInfo(fd, uint32(ot), uint32(si), uintptr(0), uintptr(0), newDACL, uintptr(0)); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "%s SetSecurityInfo %s", gvmga, name)
 | 
			
		||||
		return fmt.Errorf("%s SetSecurityInfo %s: %w", gvmga, name, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
@@ -111,16 +116,19 @@ func GrantVmGroupAccess(name string) error {
 | 
			
		||||
// createFile is a helper function to call [Nt]CreateFile to get a handle to
 | 
			
		||||
// the file or directory.
 | 
			
		||||
func createFile(name string, isDir bool) (syscall.Handle, error) {
 | 
			
		||||
	namep := syscall.StringToUTF16(name)
 | 
			
		||||
	namep, err := syscall.UTF16FromString(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return syscall.InvalidHandle, fmt.Errorf("could not convernt name to UTF-16: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	da := uint32(desiredAccessReadControl | desiredAccessWriteDac)
 | 
			
		||||
	sm := uint32(shareModeRead | shareModeWrite)
 | 
			
		||||
	fa := uint32(syscall.FILE_ATTRIBUTE_NORMAL)
 | 
			
		||||
	if isDir {
 | 
			
		||||
		fa = uint32(fa | syscall.FILE_FLAG_BACKUP_SEMANTICS)
 | 
			
		||||
		fa |= syscall.FILE_FLAG_BACKUP_SEMANTICS
 | 
			
		||||
	}
 | 
			
		||||
	fd, err := syscall.CreateFile(&namep[0], da, sm, nil, syscall.OPEN_EXISTING, fa, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, errors.Wrapf(err, "%s syscall.CreateFile %s", gvmga, name)
 | 
			
		||||
		return syscall.InvalidHandle, fmt.Errorf("%s syscall.CreateFile %s: %w", gvmga, name, err)
 | 
			
		||||
	}
 | 
			
		||||
	return fd, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -129,9 +137,9 @@ func createFile(name string, isDir bool) (syscall.Handle, error) {
 | 
			
		||||
// The caller is responsible for LocalFree of the returned DACL on success.
 | 
			
		||||
func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintptr, error) {
 | 
			
		||||
	// Generate pointers to the SIDs based on the string SIDs
 | 
			
		||||
	sid, err := syscall.StringToSid(sidVmGroup)
 | 
			
		||||
	sid, err := syscall.StringToSid(sidVMGroup)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, errors.Wrapf(err, "%s syscall.StringToSid %s %s", gvmga, name, sidVmGroup)
 | 
			
		||||
		return 0, fmt.Errorf("%s syscall.StringToSid %s %s: %w", gvmga, name, sidVMGroup, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inheritance := inheritModeNoInheritance
 | 
			
		||||
@@ -140,12 +148,12 @@ func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintp
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	eaArray := []explicitAccess{
 | 
			
		||||
		explicitAccess{
 | 
			
		||||
		{
 | 
			
		||||
			accessPermissions: accessMaskDesiredPermission,
 | 
			
		||||
			accessMode:        accessModeGrant,
 | 
			
		||||
			inheritance:       inheritance,
 | 
			
		||||
			trustee: trustee{
 | 
			
		||||
				trusteeForm: trusteeFormIsSid,
 | 
			
		||||
				trusteeForm: trusteeFormIsSID,
 | 
			
		||||
				trusteeType: trusteeTypeWellKnownGroup,
 | 
			
		||||
				name:        uintptr(unsafe.Pointer(sid)),
 | 
			
		||||
			},
 | 
			
		||||
@@ -154,7 +162,7 @@ func generateDACLWithAcesAdded(name string, isDir bool, origDACL uintptr) (uintp
 | 
			
		||||
 | 
			
		||||
	modifiedDACL := uintptr(0)
 | 
			
		||||
	if err := setEntriesInAcl(uintptr(uint32(1)), uintptr(unsafe.Pointer(&eaArray[0])), origDACL, &modifiedDACL); err != nil {
 | 
			
		||||
		return 0, errors.Wrapf(err, "%s SetEntriesInAcl %s", gvmga, name)
 | 
			
		||||
		return 0, fmt.Errorf("%s SetEntriesInAcl %s: %w", gvmga, name, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return modifiedDACL, nil
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/Microsoft/go-winio/pkg/security/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/Microsoft/go-winio/pkg/security/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
package security
 | 
			
		||||
 | 
			
		||||
//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
 | 
			
		||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
 | 
			
		||||
 | 
			
		||||
//sys getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) [failretval!=0] = advapi32.GetSecurityInfo
 | 
			
		||||
//sys setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) [failretval!=0] = advapi32.SetSecurityInfo
 | 
			
		||||
//sys setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) [failretval!=0] = advapi32.SetEntriesInAclW
 | 
			
		||||
//sys getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (win32err error) = advapi32.GetSecurityInfo
 | 
			
		||||
//sys setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) = advapi32.SetSecurityInfo
 | 
			
		||||
//sys setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (win32err error) = advapi32.SetEntriesInAclW
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										28
									
								
								vendor/github.com/Microsoft/go-winio/pkg/security/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/Microsoft/go-winio/pkg/security/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,4 +1,6 @@
 | 
			
		||||
// Code generated by 'go generate'; DO NOT EDIT.
 | 
			
		||||
//go:build windows
 | 
			
		||||
 | 
			
		||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package security
 | 
			
		||||
 | 
			
		||||
@@ -45,26 +47,26 @@ var (
 | 
			
		||||
	procSetSecurityInfo  = modadvapi32.NewProc("SetSecurityInfo")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procGetSecurityInfo.Addr(), 8, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(ppsidOwner)), uintptr(unsafe.Pointer(ppsidGroup)), uintptr(unsafe.Pointer(ppDacl)), uintptr(unsafe.Pointer(ppSacl)), uintptr(unsafe.Pointer(ppSecurityDescriptor)), 0)
 | 
			
		||||
	if r1 != 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
func getSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, ppsidOwner **uintptr, ppsidGroup **uintptr, ppDacl *uintptr, ppSacl *uintptr, ppSecurityDescriptor *uintptr) (win32err error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall9(procGetSecurityInfo.Addr(), 8, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(unsafe.Pointer(ppsidOwner)), uintptr(unsafe.Pointer(ppsidGroup)), uintptr(unsafe.Pointer(ppDacl)), uintptr(unsafe.Pointer(ppSacl)), uintptr(unsafe.Pointer(ppSecurityDescriptor)), 0)
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		win32err = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)), 0, 0)
 | 
			
		||||
	if r1 != 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
func setEntriesInAcl(count uintptr, pListOfEEs uintptr, oldAcl uintptr, newAcl *uintptr) (win32err error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall6(procSetEntriesInAclW.Addr(), 4, uintptr(count), uintptr(pListOfEEs), uintptr(oldAcl), uintptr(unsafe.Pointer(newAcl)), 0, 0)
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		win32err = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl), 0, 0)
 | 
			
		||||
	if r1 != 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
func setSecurityInfo(handle syscall.Handle, objectType uint32, si uint32, psidOwner uintptr, psidGroup uintptr, pDacl uintptr, pSacl uintptr) (win32err error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall9(procSetSecurityInfo.Addr(), 7, uintptr(handle), uintptr(objectType), uintptr(si), uintptr(psidOwner), uintptr(psidGroup), uintptr(pDacl), uintptr(pSacl), 0, 0)
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		win32err = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										37
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										37
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
@@ -24,19 +25,15 @@ import (
 | 
			
		||||
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	SE_PRIVILEGE_ENABLED = 2
 | 
			
		||||
	//revive:disable-next-line:var-naming ALL_CAPS
 | 
			
		||||
	SE_PRIVILEGE_ENABLED = windows.SE_PRIVILEGE_ENABLED
 | 
			
		||||
 | 
			
		||||
	ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
 | 
			
		||||
	//revive:disable-next-line:var-naming ALL_CAPS
 | 
			
		||||
	ERROR_NOT_ALL_ASSIGNED syscall.Errno = windows.ERROR_NOT_ALL_ASSIGNED
 | 
			
		||||
 | 
			
		||||
	SeBackupPrivilege  = "SeBackupPrivilege"
 | 
			
		||||
	SeRestorePrivilege = "SeRestorePrivilege"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	securityAnonymous = iota
 | 
			
		||||
	securityIdentification
 | 
			
		||||
	securityImpersonation
 | 
			
		||||
	securityDelegation
 | 
			
		||||
	SeBackupPrivilege   = "SeBackupPrivilege"
 | 
			
		||||
	SeRestorePrivilege  = "SeRestorePrivilege"
 | 
			
		||||
	SeSecurityPrivilege = "SeSecurityPrivilege"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
@@ -50,11 +47,9 @@ type PrivilegeError struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *PrivilegeError) Error() string {
 | 
			
		||||
	s := ""
 | 
			
		||||
	s := "Could not enable privilege "
 | 
			
		||||
	if len(e.privileges) > 1 {
 | 
			
		||||
		s = "Could not enable privileges "
 | 
			
		||||
	} else {
 | 
			
		||||
		s = "Could not enable privilege "
 | 
			
		||||
	}
 | 
			
		||||
	for i, p := range e.privileges {
 | 
			
		||||
		if i != 0 {
 | 
			
		||||
@@ -93,7 +88,7 @@ func RunWithPrivileges(names []string, fn func() error) error {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func mapPrivileges(names []string) ([]uint64, error) {
 | 
			
		||||
	var privileges []uint64
 | 
			
		||||
	privileges := make([]uint64, 0, len(names))
 | 
			
		||||
	privNameMutex.Lock()
 | 
			
		||||
	defer privNameMutex.Unlock()
 | 
			
		||||
	for _, name := range names {
 | 
			
		||||
@@ -126,7 +121,7 @@ func enableDisableProcessPrivilege(names []string, action uint32) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p, _ := windows.GetCurrentProcess()
 | 
			
		||||
	p := windows.CurrentProcess()
 | 
			
		||||
	var token windows.Token
 | 
			
		||||
	err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -139,10 +134,10 @@ func enableDisableProcessPrivilege(names []string, action uint32) error {
 | 
			
		||||
 | 
			
		||||
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
 | 
			
		||||
	var b bytes.Buffer
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
 | 
			
		||||
	_ = binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
 | 
			
		||||
	for _, p := range privileges {
 | 
			
		||||
		binary.Write(&b, binary.LittleEndian, p)
 | 
			
		||||
		binary.Write(&b, binary.LittleEndian, action)
 | 
			
		||||
		_ = binary.Write(&b, binary.LittleEndian, p)
 | 
			
		||||
		_ = binary.Write(&b, binary.LittleEndian, action)
 | 
			
		||||
	}
 | 
			
		||||
	prevState := make([]byte, b.Len())
 | 
			
		||||
	reqSize := uint32(0)
 | 
			
		||||
@@ -150,7 +145,7 @@ func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) e
 | 
			
		||||
	if !success {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err == ERROR_NOT_ALL_ASSIGNED {
 | 
			
		||||
	if err == ERROR_NOT_ALL_ASSIGNED { //nolint:errorlint // err is Errno
 | 
			
		||||
		return &PrivilegeError{privileges}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
@@ -176,7 +171,7 @@ func getPrivilegeName(luid uint64) string {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newThreadToken() (windows.Token, error) {
 | 
			
		||||
	err := impersonateSelf(securityImpersonation)
 | 
			
		||||
	err := impersonateSelf(windows.SecurityImpersonation)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								vendor/github.com/Microsoft/go-winio/reparse.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/Microsoft/go-winio/reparse.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,6 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
@@ -113,16 +116,16 @@ func EncodeReparsePoint(rp *ReparsePoint) []byte {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var b bytes.Buffer
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, &data)
 | 
			
		||||
	_ = binary.Write(&b, binary.LittleEndian, &data)
 | 
			
		||||
	if !rp.IsMountPoint {
 | 
			
		||||
		flags := uint32(0)
 | 
			
		||||
		if relative {
 | 
			
		||||
			flags |= 1
 | 
			
		||||
		}
 | 
			
		||||
		binary.Write(&b, binary.LittleEndian, flags)
 | 
			
		||||
		_ = binary.Write(&b, binary.LittleEndian, flags)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, ntTarget16)
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, target16)
 | 
			
		||||
	_ = binary.Write(&b, binary.LittleEndian, ntTarget16)
 | 
			
		||||
	_ = binary.Write(&b, binary.LittleEndian, target16)
 | 
			
		||||
	return b.Bytes()
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										64
									
								
								vendor/github.com/Microsoft/go-winio/sd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										64
									
								
								vendor/github.com/Microsoft/go-winio/sd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,23 +1,25 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
 | 
			
		||||
//sys lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountSidW
 | 
			
		||||
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
 | 
			
		||||
//sys convertStringSidToSid(str *uint16, sid **byte) (err error) = advapi32.ConvertStringSidToSidW
 | 
			
		||||
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
 | 
			
		||||
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
 | 
			
		||||
//sys localFree(mem uintptr) = LocalFree
 | 
			
		||||
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	cERROR_NONE_MAPPED = syscall.Errno(1332)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AccountLookupError struct {
 | 
			
		||||
	Name string
 | 
			
		||||
	Err  error
 | 
			
		||||
@@ -28,8 +30,10 @@ func (e *AccountLookupError) Error() string {
 | 
			
		||||
		return "lookup account: empty account name specified"
 | 
			
		||||
	}
 | 
			
		||||
	var s string
 | 
			
		||||
	switch e.Err {
 | 
			
		||||
	case cERROR_NONE_MAPPED:
 | 
			
		||||
	switch {
 | 
			
		||||
	case errors.Is(e.Err, windows.ERROR_INVALID_SID):
 | 
			
		||||
		s = "the security ID structure is invalid"
 | 
			
		||||
	case errors.Is(e.Err, windows.ERROR_NONE_MAPPED):
 | 
			
		||||
		s = "not found"
 | 
			
		||||
	default:
 | 
			
		||||
		s = e.Err.Error()
 | 
			
		||||
@@ -37,6 +41,8 @@ func (e *AccountLookupError) Error() string {
 | 
			
		||||
	return "lookup account " + e.Name + ": " + s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *AccountLookupError) Unwrap() error { return e.Err }
 | 
			
		||||
 | 
			
		||||
type SddlConversionError struct {
 | 
			
		||||
	Sddl string
 | 
			
		||||
	Err  error
 | 
			
		||||
@@ -46,15 +52,19 @@ func (e *SddlConversionError) Error() string {
 | 
			
		||||
	return "convert " + e.Sddl + ": " + e.Err.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *SddlConversionError) Unwrap() error { return e.Err }
 | 
			
		||||
 | 
			
		||||
// LookupSidByName looks up the SID of an account by name
 | 
			
		||||
//
 | 
			
		||||
//revive:disable-next-line:var-naming SID, not Sid
 | 
			
		||||
func LookupSidByName(name string) (sid string, err error) {
 | 
			
		||||
	if name == "" {
 | 
			
		||||
		return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
 | 
			
		||||
		return "", &AccountLookupError{name, windows.ERROR_NONE_MAPPED}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sidSize, sidNameUse, refDomainSize uint32
 | 
			
		||||
	err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
 | 
			
		||||
	if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
 | 
			
		||||
	if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
 | 
			
		||||
		return "", &AccountLookupError{name, err}
 | 
			
		||||
	}
 | 
			
		||||
	sidBuffer := make([]byte, sidSize)
 | 
			
		||||
@@ -73,6 +83,42 @@ func LookupSidByName(name string) (sid string, err error) {
 | 
			
		||||
	return sid, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LookupNameBySid looks up the name of an account by SID
 | 
			
		||||
//
 | 
			
		||||
//revive:disable-next-line:var-naming SID, not Sid
 | 
			
		||||
func LookupNameBySid(sid string) (name string, err error) {
 | 
			
		||||
	if sid == "" {
 | 
			
		||||
		return "", &AccountLookupError{sid, windows.ERROR_NONE_MAPPED}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sidBuffer, err := windows.UTF16PtrFromString(sid)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", &AccountLookupError{sid, err}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sidPtr *byte
 | 
			
		||||
	if err = convertStringSidToSid(sidBuffer, &sidPtr); err != nil {
 | 
			
		||||
		return "", &AccountLookupError{sid, err}
 | 
			
		||||
	}
 | 
			
		||||
	defer localFree(uintptr(unsafe.Pointer(sidPtr)))
 | 
			
		||||
 | 
			
		||||
	var nameSize, refDomainSize, sidNameUse uint32
 | 
			
		||||
	err = lookupAccountSid(nil, sidPtr, nil, &nameSize, nil, &refDomainSize, &sidNameUse)
 | 
			
		||||
	if err != nil && err != windows.ERROR_INSUFFICIENT_BUFFER { //nolint:errorlint // err is Errno
 | 
			
		||||
		return "", &AccountLookupError{sid, err}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nameBuffer := make([]uint16, nameSize)
 | 
			
		||||
	refDomainBuffer := make([]uint16, refDomainSize)
 | 
			
		||||
	err = lookupAccountSid(nil, sidPtr, &nameBuffer[0], &nameSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", &AccountLookupError{sid, err}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	name = windows.UTF16ToString(nameBuffer)
 | 
			
		||||
	return name, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
 | 
			
		||||
	var sdBuffer uintptr
 | 
			
		||||
	err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
 | 
			
		||||
@@ -87,7 +133,7 @@ func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
 | 
			
		||||
 | 
			
		||||
func SecurityDescriptorToSddl(sd []byte) (string, error) {
 | 
			
		||||
	var sddl *uint16
 | 
			
		||||
	// The returned string length seems to including an aribtrary number of terminating NULs.
 | 
			
		||||
	// The returned string length seems to include an arbitrary number of terminating NULs.
 | 
			
		||||
	// Don't use it.
 | 
			
		||||
	err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,5 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go
 | 
			
		||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./*.go
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/Microsoft/go-winio/tools.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/Microsoft/go-winio/tools.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
//go:build tools
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import _ "golang.org/x/tools/cmd/stringer"
 | 
			
		||||
							
								
								
									
										122
									
								
								vendor/github.com/Microsoft/go-winio/vhd/vhd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										122
									
								
								vendor/github.com/Microsoft/go-winio/vhd/vhd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +1,4 @@
 | 
			
		||||
//go:build windows
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package vhd
 | 
			
		||||
@@ -7,17 +8,16 @@ import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/Microsoft/go-winio/pkg/guid"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//go:generate go run mksyscall_windows.go -output zvhd_windows.go vhd.go
 | 
			
		||||
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zvhd_windows.go vhd.go
 | 
			
		||||
 | 
			
		||||
//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.CreateVirtualDisk
 | 
			
		||||
//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) [failretval != 0] = virtdisk.OpenVirtualDisk
 | 
			
		||||
//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) [failretval != 0] = virtdisk.AttachVirtualDisk
 | 
			
		||||
//sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) [failretval != 0] = virtdisk.DetachVirtualDisk
 | 
			
		||||
//sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) [failretval != 0] = virtdisk.GetVirtualDiskPhysicalPath
 | 
			
		||||
//sys createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) = virtdisk.CreateVirtualDisk
 | 
			
		||||
//sys openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) = virtdisk.OpenVirtualDisk
 | 
			
		||||
//sys attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) = virtdisk.AttachVirtualDisk
 | 
			
		||||
//sys detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) = virtdisk.DetachVirtualDisk
 | 
			
		||||
//sys getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) = virtdisk.GetVirtualDiskPhysicalPath
 | 
			
		||||
 | 
			
		||||
type (
 | 
			
		||||
	CreateVirtualDiskFlag uint32
 | 
			
		||||
@@ -62,20 +62,35 @@ type OpenVirtualDiskParameters struct {
 | 
			
		||||
	Version2 OpenVersion2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The higher level `OpenVersion2` struct uses `bool`s to refer to `GetInfoOnly` and `ReadOnly` for ease of use. However,
 | 
			
		||||
// the internal windows structure uses `BOOL`s aka int32s for these types. `openVersion2` is used for translating
 | 
			
		||||
// `OpenVersion2` fields to the correct windows internal field types on the `Open____` methods.
 | 
			
		||||
type openVersion2 struct {
 | 
			
		||||
	getInfoOnly    int32
 | 
			
		||||
	readOnly       int32
 | 
			
		||||
	resiliencyGUID guid.GUID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type openVirtualDiskParameters struct {
 | 
			
		||||
	version  uint32
 | 
			
		||||
	version2 openVersion2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AttachVersion2 struct {
 | 
			
		||||
	RestrictedOffset uint64
 | 
			
		||||
	RestrictedLength uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type AttachVirtualDiskParameters struct {
 | 
			
		||||
	Version  uint32 // Must always be set to 2
 | 
			
		||||
	Version  uint32
 | 
			
		||||
	Version2 AttachVersion2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	//revive:disable-next-line:var-naming ALL_CAPS
 | 
			
		||||
	VIRTUAL_STORAGE_TYPE_DEVICE_VHDX = 0x3
 | 
			
		||||
 | 
			
		||||
	// Access Mask for opening a VHD
 | 
			
		||||
	// Access Mask for opening a VHD.
 | 
			
		||||
	VirtualDiskAccessNone     VirtualDiskAccessMask = 0x00000000
 | 
			
		||||
	VirtualDiskAccessAttachRO VirtualDiskAccessMask = 0x00010000
 | 
			
		||||
	VirtualDiskAccessAttachRW VirtualDiskAccessMask = 0x00020000
 | 
			
		||||
@@ -87,7 +102,7 @@ const (
 | 
			
		||||
	VirtualDiskAccessAll      VirtualDiskAccessMask = 0x003f0000
 | 
			
		||||
	VirtualDiskAccessWritable VirtualDiskAccessMask = 0x00320000
 | 
			
		||||
 | 
			
		||||
	// Flags for creating a VHD
 | 
			
		||||
	// Flags for creating a VHD.
 | 
			
		||||
	CreateVirtualDiskFlagNone                              CreateVirtualDiskFlag = 0x0
 | 
			
		||||
	CreateVirtualDiskFlagFullPhysicalAllocation            CreateVirtualDiskFlag = 0x1
 | 
			
		||||
	CreateVirtualDiskFlagPreventWritesToSourceDisk         CreateVirtualDiskFlag = 0x2
 | 
			
		||||
@@ -95,12 +110,12 @@ const (
 | 
			
		||||
	CreateVirtualDiskFlagCreateBackingStorage              CreateVirtualDiskFlag = 0x8
 | 
			
		||||
	CreateVirtualDiskFlagUseChangeTrackingSourceLimit      CreateVirtualDiskFlag = 0x10
 | 
			
		||||
	CreateVirtualDiskFlagPreserveParentChangeTrackingState CreateVirtualDiskFlag = 0x20
 | 
			
		||||
	CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage   CreateVirtualDiskFlag = 0x40
 | 
			
		||||
	CreateVirtualDiskFlagVhdSetUseOriginalBackingStorage   CreateVirtualDiskFlag = 0x40 //revive:disable-line:var-naming VHD, not Vhd
 | 
			
		||||
	CreateVirtualDiskFlagSparseFile                        CreateVirtualDiskFlag = 0x80
 | 
			
		||||
	CreateVirtualDiskFlagPmemCompatible                    CreateVirtualDiskFlag = 0x100
 | 
			
		||||
	CreateVirtualDiskFlagPmemCompatible                    CreateVirtualDiskFlag = 0x100 //revive:disable-line:var-naming PMEM, not Pmem
 | 
			
		||||
	CreateVirtualDiskFlagSupportCompressedVolumes          CreateVirtualDiskFlag = 0x200
 | 
			
		||||
 | 
			
		||||
	// Flags for opening a VHD
 | 
			
		||||
	// Flags for opening a VHD.
 | 
			
		||||
	OpenVirtualDiskFlagNone                        VirtualDiskFlag = 0x00000000
 | 
			
		||||
	OpenVirtualDiskFlagNoParents                   VirtualDiskFlag = 0x00000001
 | 
			
		||||
	OpenVirtualDiskFlagBlankFile                   VirtualDiskFlag = 0x00000002
 | 
			
		||||
@@ -113,7 +128,7 @@ const (
 | 
			
		||||
	OpenVirtualDiskFlagNoWriteHardening            VirtualDiskFlag = 0x00000100
 | 
			
		||||
	OpenVirtualDiskFlagSupportCompressedVolumes    VirtualDiskFlag = 0x00000200
 | 
			
		||||
 | 
			
		||||
	// Flags for attaching a VHD
 | 
			
		||||
	// Flags for attaching a VHD.
 | 
			
		||||
	AttachVirtualDiskFlagNone                          AttachVirtualDiskFlag = 0x00000000
 | 
			
		||||
	AttachVirtualDiskFlagReadOnly                      AttachVirtualDiskFlag = 0x00000001
 | 
			
		||||
	AttachVirtualDiskFlagNoDriveLetter                 AttachVirtualDiskFlag = 0x00000002
 | 
			
		||||
@@ -126,12 +141,14 @@ const (
 | 
			
		||||
	AttachVirtualDiskFlagSinglePartition               AttachVirtualDiskFlag = 0x00000100
 | 
			
		||||
	AttachVirtualDiskFlagRegisterVolume                AttachVirtualDiskFlag = 0x00000200
 | 
			
		||||
 | 
			
		||||
	// Flags for detaching a VHD
 | 
			
		||||
	// Flags for detaching a VHD.
 | 
			
		||||
	DetachVirtualDiskFlagNone DetachVirtualDiskFlag = 0x0
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// CreateVhdx is a helper function to create a simple vhdx file at the given path using
 | 
			
		||||
// default values.
 | 
			
		||||
//
 | 
			
		||||
//revive:disable-next-line:var-naming VHDX, not Vhdx
 | 
			
		||||
func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
 | 
			
		||||
	params := CreateVirtualDiskParameters{
 | 
			
		||||
		Version: 2,
 | 
			
		||||
@@ -146,21 +163,20 @@ func CreateVhdx(path string, maxSizeInGb, blockSizeInMb uint32) error {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := syscall.CloseHandle(handle); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
	return syscall.CloseHandle(handle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DetachVirtualDisk detaches a virtual hard disk by handle.
 | 
			
		||||
func DetachVirtualDisk(handle syscall.Handle) (err error) {
 | 
			
		||||
	if err := detachVirtualDisk(handle, 0, 0); err != nil {
 | 
			
		||||
		return errors.Wrap(err, "failed to detach virtual disk")
 | 
			
		||||
		return fmt.Errorf("failed to detach virtual disk: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DetachVhd detaches a vhd found at `path`.
 | 
			
		||||
//
 | 
			
		||||
//revive:disable-next-line:var-naming VHD, not Vhd
 | 
			
		||||
func DetachVhd(path string) error {
 | 
			
		||||
	handle, err := OpenVirtualDisk(
 | 
			
		||||
		path,
 | 
			
		||||
@@ -170,12 +186,16 @@ func DetachVhd(path string) error {
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer syscall.CloseHandle(handle)
 | 
			
		||||
	defer syscall.CloseHandle(handle) //nolint:errcheck
 | 
			
		||||
	return DetachVirtualDisk(handle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AttachVirtualDisk attaches a virtual hard disk for use.
 | 
			
		||||
func AttachVirtualDisk(handle syscall.Handle, attachVirtualDiskFlag AttachVirtualDiskFlag, parameters *AttachVirtualDiskParameters) (err error) {
 | 
			
		||||
func AttachVirtualDisk(
 | 
			
		||||
	handle syscall.Handle,
 | 
			
		||||
	attachVirtualDiskFlag AttachVirtualDiskFlag,
 | 
			
		||||
	parameters *AttachVirtualDiskParameters,
 | 
			
		||||
) (err error) {
 | 
			
		||||
	// Supports both version 1 and 2 of the attach parameters as version 2 wasn't present in RS5.
 | 
			
		||||
	if err := attachVirtualDisk(
 | 
			
		||||
		handle,
 | 
			
		||||
@@ -185,13 +205,15 @@ func AttachVirtualDisk(handle syscall.Handle, attachVirtualDiskFlag AttachVirtua
 | 
			
		||||
		parameters,
 | 
			
		||||
		nil,
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return errors.Wrap(err, "failed to attach virtual disk")
 | 
			
		||||
		return fmt.Errorf("failed to attach virtual disk: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AttachVhd attaches a virtual hard disk at `path` for use. Attaches using version 2
 | 
			
		||||
// of the ATTACH_VIRTUAL_DISK_PARAMETERS.
 | 
			
		||||
//
 | 
			
		||||
//revive:disable-next-line:var-naming VHD, not Vhd
 | 
			
		||||
func AttachVhd(path string) (err error) {
 | 
			
		||||
	handle, err := OpenVirtualDisk(
 | 
			
		||||
		path,
 | 
			
		||||
@@ -202,20 +224,24 @@ func AttachVhd(path string) (err error) {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer syscall.CloseHandle(handle)
 | 
			
		||||
	defer syscall.CloseHandle(handle) //nolint:errcheck
 | 
			
		||||
	params := AttachVirtualDiskParameters{Version: 2}
 | 
			
		||||
	if err := AttachVirtualDisk(
 | 
			
		||||
		handle,
 | 
			
		||||
		AttachVirtualDiskFlagNone,
 | 
			
		||||
		¶ms,
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return errors.Wrap(err, "failed to attach virtual disk")
 | 
			
		||||
		return fmt.Errorf("failed to attach virtual disk: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OpenVirtualDisk obtains a handle to a VHD opened with supplied access mask and flags.
 | 
			
		||||
func OpenVirtualDisk(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag) (syscall.Handle, error) {
 | 
			
		||||
func OpenVirtualDisk(
 | 
			
		||||
	vhdPath string,
 | 
			
		||||
	virtualDiskAccessMask VirtualDiskAccessMask,
 | 
			
		||||
	openVirtualDiskFlags VirtualDiskFlag,
 | 
			
		||||
) (syscall.Handle, error) {
 | 
			
		||||
	parameters := OpenVirtualDiskParameters{Version: 2}
 | 
			
		||||
	handle, err := OpenVirtualDiskWithParameters(
 | 
			
		||||
		vhdPath,
 | 
			
		||||
@@ -230,29 +256,55 @@ func OpenVirtualDisk(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OpenVirtualDiskWithParameters obtains a handle to a VHD opened with supplied access mask, flags and parameters.
 | 
			
		||||
func OpenVirtualDiskWithParameters(vhdPath string, virtualDiskAccessMask VirtualDiskAccessMask, openVirtualDiskFlags VirtualDiskFlag, parameters *OpenVirtualDiskParameters) (syscall.Handle, error) {
 | 
			
		||||
func OpenVirtualDiskWithParameters(
 | 
			
		||||
	vhdPath string,
 | 
			
		||||
	virtualDiskAccessMask VirtualDiskAccessMask,
 | 
			
		||||
	openVirtualDiskFlags VirtualDiskFlag,
 | 
			
		||||
	parameters *OpenVirtualDiskParameters,
 | 
			
		||||
) (syscall.Handle, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		handle      syscall.Handle
 | 
			
		||||
		defaultType VirtualStorageType
 | 
			
		||||
		getInfoOnly int32
 | 
			
		||||
		readOnly    int32
 | 
			
		||||
	)
 | 
			
		||||
	if parameters.Version != 2 {
 | 
			
		||||
		return handle, fmt.Errorf("only version 2 VHDs are supported, found version: %d", parameters.Version)
 | 
			
		||||
	}
 | 
			
		||||
	if parameters.Version2.GetInfoOnly {
 | 
			
		||||
		getInfoOnly = 1
 | 
			
		||||
	}
 | 
			
		||||
	if parameters.Version2.ReadOnly {
 | 
			
		||||
		readOnly = 1
 | 
			
		||||
	}
 | 
			
		||||
	params := &openVirtualDiskParameters{
 | 
			
		||||
		version: parameters.Version,
 | 
			
		||||
		version2: openVersion2{
 | 
			
		||||
			getInfoOnly,
 | 
			
		||||
			readOnly,
 | 
			
		||||
			parameters.Version2.ResiliencyGUID,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	if err := openVirtualDisk(
 | 
			
		||||
		&defaultType,
 | 
			
		||||
		vhdPath,
 | 
			
		||||
		uint32(virtualDiskAccessMask),
 | 
			
		||||
		uint32(openVirtualDiskFlags),
 | 
			
		||||
		parameters,
 | 
			
		||||
		params,
 | 
			
		||||
		&handle,
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return 0, errors.Wrap(err, "failed to open virtual disk")
 | 
			
		||||
		return 0, fmt.Errorf("failed to open virtual disk: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return handle, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateVirtualDisk creates a virtual harddisk and returns a handle to the disk.
 | 
			
		||||
func CreateVirtualDisk(path string, virtualDiskAccessMask VirtualDiskAccessMask, createVirtualDiskFlags CreateVirtualDiskFlag, parameters *CreateVirtualDiskParameters) (syscall.Handle, error) {
 | 
			
		||||
func CreateVirtualDisk(
 | 
			
		||||
	path string,
 | 
			
		||||
	virtualDiskAccessMask VirtualDiskAccessMask,
 | 
			
		||||
	createVirtualDiskFlags CreateVirtualDiskFlag,
 | 
			
		||||
	parameters *CreateVirtualDiskParameters,
 | 
			
		||||
) (syscall.Handle, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		handle      syscall.Handle
 | 
			
		||||
		defaultType VirtualStorageType
 | 
			
		||||
@@ -272,7 +324,7 @@ func CreateVirtualDisk(path string, virtualDiskAccessMask VirtualDiskAccessMask,
 | 
			
		||||
		nil,
 | 
			
		||||
		&handle,
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return handle, errors.Wrap(err, "failed to create virtual disk")
 | 
			
		||||
		return handle, fmt.Errorf("failed to create virtual disk: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return handle, nil
 | 
			
		||||
}
 | 
			
		||||
@@ -290,12 +342,14 @@ func GetVirtualDiskPhysicalPath(handle syscall.Handle) (_ string, err error) {
 | 
			
		||||
		&diskPathSizeInBytes,
 | 
			
		||||
		&diskPhysicalPathBuf[0],
 | 
			
		||||
	); err != nil {
 | 
			
		||||
		return "", errors.Wrap(err, "failed to get disk physical path")
 | 
			
		||||
		return "", fmt.Errorf("failed to get disk physical path: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return windows.UTF16ToString(diskPhysicalPathBuf[:]), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CreateDiffVhd is a helper function to create a differencing virtual disk.
 | 
			
		||||
//
 | 
			
		||||
//revive:disable-next-line:var-naming VHD, not Vhd
 | 
			
		||||
func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error {
 | 
			
		||||
	// Setting `ParentPath` is how to signal to create a differencing disk.
 | 
			
		||||
	createParams := &CreateVirtualDiskParameters{
 | 
			
		||||
@@ -314,10 +368,10 @@ func CreateDiffVhd(diffVhdPath, baseVhdPath string, blockSizeInMB uint32) error
 | 
			
		||||
		createParams,
 | 
			
		||||
	)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to create differencing vhd: %s", err)
 | 
			
		||||
		return fmt.Errorf("failed to create differencing vhd: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	if err := syscall.CloseHandle(vhdHandle); err != nil {
 | 
			
		||||
		return fmt.Errorf("failed to close differencing vhd handle: %s", err)
 | 
			
		||||
		return fmt.Errorf("failed to close differencing vhd handle: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										56
									
								
								vendor/github.com/Microsoft/go-winio/vhd/zvhd_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										56
									
								
								vendor/github.com/Microsoft/go-winio/vhd/zvhd_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,4 +1,6 @@
 | 
			
		||||
// Code generated by 'go generate'; DO NOT EDIT.
 | 
			
		||||
//go:build windows
 | 
			
		||||
 | 
			
		||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package vhd
 | 
			
		||||
 | 
			
		||||
@@ -47,60 +49,60 @@ var (
 | 
			
		||||
	procOpenVirtualDisk            = modvirtdisk.NewProc("OpenVirtualDisk")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
 | 
			
		||||
	if r1 != 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
func attachVirtualDisk(handle syscall.Handle, securityDescriptor *uintptr, attachVirtualDiskFlag uint32, providerSpecificFlags uint32, parameters *AttachVirtualDiskParameters, overlapped *syscall.Overlapped) (win32err error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall6(procAttachVirtualDisk.Addr(), 6, uintptr(handle), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(attachVirtualDiskFlag), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)))
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		win32err = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) {
 | 
			
		||||
func createVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	_p0, win32err = syscall.UTF16PtrFromString(path)
 | 
			
		||||
	if win32err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _createVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, securityDescriptor, createVirtualDiskFlags, providerSpecificFlags, parameters, overlapped, handle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
 | 
			
		||||
	if r1 != 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
func _createVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, securityDescriptor *uintptr, createVirtualDiskFlags uint32, providerSpecificFlags uint32, parameters *CreateVirtualDiskParameters, overlapped *syscall.Overlapped, handle *syscall.Handle) (win32err error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall9(procCreateVirtualDisk.Addr(), 9, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(unsafe.Pointer(securityDescriptor)), uintptr(createVirtualDiskFlags), uintptr(providerSpecificFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(handle)))
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		win32err = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
 | 
			
		||||
	if r1 != 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
func detachVirtualDisk(handle syscall.Handle, detachVirtualDiskFlags uint32, providerSpecificFlags uint32) (win32err error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procDetachVirtualDisk.Addr(), 3, uintptr(handle), uintptr(detachVirtualDiskFlags), uintptr(providerSpecificFlags))
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		win32err = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procGetVirtualDiskPhysicalPath.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
 | 
			
		||||
	if r1 != 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
func getVirtualDiskPhysicalPath(handle syscall.Handle, diskPathSizeInBytes *uint32, buffer *uint16) (win32err error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procGetVirtualDiskPhysicalPath.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(diskPathSizeInBytes)), uintptr(unsafe.Pointer(buffer)))
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		win32err = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) {
 | 
			
		||||
func openVirtualDisk(virtualStorageType *VirtualStorageType, path string, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
	_p0, win32err = syscall.UTF16PtrFromString(path)
 | 
			
		||||
	if win32err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _openVirtualDisk(virtualStorageType, _p0, virtualDiskAccessMask, openVirtualDiskFlags, parameters, handle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *OpenVirtualDiskParameters, handle *syscall.Handle) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
 | 
			
		||||
	if r1 != 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
func _openVirtualDisk(virtualStorageType *VirtualStorageType, path *uint16, virtualDiskAccessMask uint32, openVirtualDiskFlags uint32, parameters *openVirtualDiskParameters, handle *syscall.Handle) (win32err error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall6(procOpenVirtualDisk.Addr(), 6, uintptr(unsafe.Pointer(virtualStorageType)), uintptr(unsafe.Pointer(path)), uintptr(virtualDiskAccessMask), uintptr(openVirtualDiskFlags), uintptr(unsafe.Pointer(parameters)), uintptr(unsafe.Pointer(handle)))
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		win32err = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										45
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,4 +1,6 @@
 | 
			
		||||
// Code generated by 'go generate'; DO NOT EDIT.
 | 
			
		||||
//go:build windows
 | 
			
		||||
 | 
			
		||||
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
@@ -47,9 +49,11 @@ var (
 | 
			
		||||
	procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
 | 
			
		||||
	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW")
 | 
			
		||||
	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
 | 
			
		||||
	procConvertStringSidToSidW                               = modadvapi32.NewProc("ConvertStringSidToSidW")
 | 
			
		||||
	procGetSecurityDescriptorLength                          = modadvapi32.NewProc("GetSecurityDescriptorLength")
 | 
			
		||||
	procImpersonateSelf                                      = modadvapi32.NewProc("ImpersonateSelf")
 | 
			
		||||
	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW")
 | 
			
		||||
	procLookupAccountSidW                                    = modadvapi32.NewProc("LookupAccountSidW")
 | 
			
		||||
	procLookupPrivilegeDisplayNameW                          = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
 | 
			
		||||
	procLookupPrivilegeNameW                                 = modadvapi32.NewProc("LookupPrivilegeNameW")
 | 
			
		||||
	procLookupPrivilegeValueW                                = modadvapi32.NewProc("LookupPrivilegeValueW")
 | 
			
		||||
@@ -74,7 +78,6 @@ var (
 | 
			
		||||
	procRtlDosPathNameToNtPathName_U                         = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
 | 
			
		||||
	procRtlNtStatusToDosErrorNoTeb                           = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
 | 
			
		||||
	procWSAGetOverlappedResult                               = modws2_32.NewProc("WSAGetOverlappedResult")
 | 
			
		||||
	procbind                                                 = modws2_32.NewProc("bind")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
 | 
			
		||||
@@ -123,6 +126,14 @@ func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertStringSidToSid(str *uint16, sid **byte) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procConvertStringSidToSidW.Addr(), 2, uintptr(unsafe.Pointer(str)), uintptr(unsafe.Pointer(sid)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
 | 
			
		||||
	len = uint32(r0)
 | 
			
		||||
@@ -154,6 +165,14 @@ func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidS
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupAccountSid(systemName *uint16, sid *byte, name *uint16, nameSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procLookupAccountSidW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(systemName)
 | 
			
		||||
@@ -380,25 +399,25 @@ func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err erro
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) {
 | 
			
		||||
func ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntStatus) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall15(procNtCreateNamedPipeFile.Addr(), 14, uintptr(unsafe.Pointer(pipe)), uintptr(access), uintptr(unsafe.Pointer(oa)), uintptr(unsafe.Pointer(iosb)), uintptr(share), uintptr(disposition), uintptr(options), uintptr(typ), uintptr(readMode), uintptr(completionMode), uintptr(maxInstances), uintptr(inboundQuota), uintptr(outputQuota), uintptr(unsafe.Pointer(timeout)), 0)
 | 
			
		||||
	status = ntstatus(r0)
 | 
			
		||||
	status = ntStatus(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) {
 | 
			
		||||
func rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
 | 
			
		||||
	status = ntstatus(r0)
 | 
			
		||||
	status = ntStatus(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) {
 | 
			
		||||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
 | 
			
		||||
	status = ntstatus(r0)
 | 
			
		||||
	status = ntStatus(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rtlNtStatusToDosError(status ntstatus) (winerr error) {
 | 
			
		||||
func rtlNtStatusToDosError(status ntStatus) (winerr error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		winerr = syscall.Errno(r0)
 | 
			
		||||
@@ -417,11 +436,3 @@ func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procbind.Addr(), 3, uintptr(s), uintptr(name), uintptr(namelen))
 | 
			
		||||
	if r1 == socketError {
 | 
			
		||||
		err = errnoErr(e1)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										657
									
								
								vendor/golang.org/x/tools/cmd/stringer/stringer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										657
									
								
								vendor/golang.org/x/tools/cmd/stringer/stringer.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,657 @@
 | 
			
		||||
// Copyright 2014 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// Stringer is a tool to automate the creation of methods that satisfy the fmt.Stringer
 | 
			
		||||
// interface. Given the name of a (signed or unsigned) integer type T that has constants
 | 
			
		||||
// defined, stringer will create a new self-contained Go source file implementing
 | 
			
		||||
//
 | 
			
		||||
//	func (t T) String() string
 | 
			
		||||
//
 | 
			
		||||
// The file is created in the same package and directory as the package that defines T.
 | 
			
		||||
// It has helpful defaults designed for use with go generate.
 | 
			
		||||
//
 | 
			
		||||
// Stringer works best with constants that are consecutive values such as created using iota,
 | 
			
		||||
// but creates good code regardless. In the future it might also provide custom support for
 | 
			
		||||
// constant sets that are bit patterns.
 | 
			
		||||
//
 | 
			
		||||
// For example, given this snippet,
 | 
			
		||||
//
 | 
			
		||||
//	package painkiller
 | 
			
		||||
//
 | 
			
		||||
//	type Pill int
 | 
			
		||||
//
 | 
			
		||||
//	const (
 | 
			
		||||
//		Placebo Pill = iota
 | 
			
		||||
//		Aspirin
 | 
			
		||||
//		Ibuprofen
 | 
			
		||||
//		Paracetamol
 | 
			
		||||
//		Acetaminophen = Paracetamol
 | 
			
		||||
//	)
 | 
			
		||||
//
 | 
			
		||||
// running this command
 | 
			
		||||
//
 | 
			
		||||
//	stringer -type=Pill
 | 
			
		||||
//
 | 
			
		||||
// in the same directory will create the file pill_string.go, in package painkiller,
 | 
			
		||||
// containing a definition of
 | 
			
		||||
//
 | 
			
		||||
//	func (Pill) String() string
 | 
			
		||||
//
 | 
			
		||||
// That method will translate the value of a Pill constant to the string representation
 | 
			
		||||
// of the respective constant name, so that the call fmt.Print(painkiller.Aspirin) will
 | 
			
		||||
// print the string "Aspirin".
 | 
			
		||||
//
 | 
			
		||||
// Typically this process would be run using go generate, like this:
 | 
			
		||||
//
 | 
			
		||||
//	//go:generate stringer -type=Pill
 | 
			
		||||
//
 | 
			
		||||
// If multiple constants have the same value, the lexically first matching name will
 | 
			
		||||
// be used (in the example, Acetaminophen will print as "Paracetamol").
 | 
			
		||||
//
 | 
			
		||||
// With no arguments, it processes the package in the current directory.
 | 
			
		||||
// Otherwise, the arguments must name a single directory holding a Go package
 | 
			
		||||
// or a set of Go source files that represent a single Go package.
 | 
			
		||||
//
 | 
			
		||||
// The -type flag accepts a comma-separated list of types so a single run can
 | 
			
		||||
// generate methods for multiple types. The default output file is t_string.go,
 | 
			
		||||
// where t is the lower-cased name of the first type listed. It can be overridden
 | 
			
		||||
// with the -output flag.
 | 
			
		||||
//
 | 
			
		||||
// The -linecomment flag tells stringer to generate the text of any line comment, trimmed
 | 
			
		||||
// of leading spaces, instead of the constant name. For instance, if the constants above had a
 | 
			
		||||
// Pill prefix, one could write
 | 
			
		||||
//
 | 
			
		||||
//	PillAspirin // Aspirin
 | 
			
		||||
//
 | 
			
		||||
// to suppress it in the output.
 | 
			
		||||
package main // import "golang.org/x/tools/cmd/stringer"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"go/ast"
 | 
			
		||||
	"go/constant"
 | 
			
		||||
	"go/format"
 | 
			
		||||
	"go/token"
 | 
			
		||||
	"go/types"
 | 
			
		||||
	"log"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/tools/go/packages"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	typeNames   = flag.String("type", "", "comma-separated list of type names; must be set")
 | 
			
		||||
	output      = flag.String("output", "", "output file name; default srcdir/<type>_string.go")
 | 
			
		||||
	trimprefix  = flag.String("trimprefix", "", "trim the `prefix` from the generated constant names")
 | 
			
		||||
	linecomment = flag.Bool("linecomment", false, "use line comment text as printed text when present")
 | 
			
		||||
	buildTags   = flag.String("tags", "", "comma-separated list of build tags to apply")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Usage is a replacement usage function for the flags package.
 | 
			
		||||
func Usage() {
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "Usage of stringer:\n")
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T [directory]\n")
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T files... # Must be a single package\n")
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "For more information, see:\n")
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "\thttps://pkg.go.dev/golang.org/x/tools/cmd/stringer\n")
 | 
			
		||||
	fmt.Fprintf(os.Stderr, "Flags:\n")
 | 
			
		||||
	flag.PrintDefaults()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	log.SetFlags(0)
 | 
			
		||||
	log.SetPrefix("stringer: ")
 | 
			
		||||
	flag.Usage = Usage
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	if len(*typeNames) == 0 {
 | 
			
		||||
		flag.Usage()
 | 
			
		||||
		os.Exit(2)
 | 
			
		||||
	}
 | 
			
		||||
	types := strings.Split(*typeNames, ",")
 | 
			
		||||
	var tags []string
 | 
			
		||||
	if len(*buildTags) > 0 {
 | 
			
		||||
		tags = strings.Split(*buildTags, ",")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// We accept either one directory or a list of files. Which do we have?
 | 
			
		||||
	args := flag.Args()
 | 
			
		||||
	if len(args) == 0 {
 | 
			
		||||
		// Default: process whole package in current directory.
 | 
			
		||||
		args = []string{"."}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Parse the package once.
 | 
			
		||||
	var dir string
 | 
			
		||||
	g := Generator{
 | 
			
		||||
		trimPrefix:  *trimprefix,
 | 
			
		||||
		lineComment: *linecomment,
 | 
			
		||||
	}
 | 
			
		||||
	// TODO(suzmue): accept other patterns for packages (directories, list of files, import paths, etc).
 | 
			
		||||
	if len(args) == 1 && isDirectory(args[0]) {
 | 
			
		||||
		dir = args[0]
 | 
			
		||||
	} else {
 | 
			
		||||
		if len(tags) != 0 {
 | 
			
		||||
			log.Fatal("-tags option applies only to directories, not when files are specified")
 | 
			
		||||
		}
 | 
			
		||||
		dir = filepath.Dir(args[0])
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g.parsePackage(args, tags)
 | 
			
		||||
 | 
			
		||||
	// Print the header and package clause.
 | 
			
		||||
	g.Printf("// Code generated by \"stringer %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
 | 
			
		||||
	g.Printf("\n")
 | 
			
		||||
	g.Printf("package %s", g.pkg.name)
 | 
			
		||||
	g.Printf("\n")
 | 
			
		||||
	g.Printf("import \"strconv\"\n") // Used by all methods.
 | 
			
		||||
 | 
			
		||||
	// Run generate for each type.
 | 
			
		||||
	for _, typeName := range types {
 | 
			
		||||
		g.generate(typeName)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Format the output.
 | 
			
		||||
	src := g.format()
 | 
			
		||||
 | 
			
		||||
	// Write to file.
 | 
			
		||||
	outputName := *output
 | 
			
		||||
	if outputName == "" {
 | 
			
		||||
		baseName := fmt.Sprintf("%s_string.go", types[0])
 | 
			
		||||
		outputName = filepath.Join(dir, strings.ToLower(baseName))
 | 
			
		||||
	}
 | 
			
		||||
	err := os.WriteFile(outputName, src, 0644)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("writing output: %s", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isDirectory reports whether the named file is a directory.
 | 
			
		||||
func isDirectory(name string) bool {
 | 
			
		||||
	info, err := os.Stat(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return info.IsDir()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Generator holds the state of the analysis. Primarily used to buffer
 | 
			
		||||
// the output for format.Source.
 | 
			
		||||
type Generator struct {
 | 
			
		||||
	buf bytes.Buffer // Accumulated output.
 | 
			
		||||
	pkg *Package     // Package we are scanning.
 | 
			
		||||
 | 
			
		||||
	trimPrefix  string
 | 
			
		||||
	lineComment bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *Generator) Printf(format string, args ...interface{}) {
 | 
			
		||||
	fmt.Fprintf(&g.buf, format, args...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// File holds a single parsed file and associated data.
 | 
			
		||||
type File struct {
 | 
			
		||||
	pkg  *Package  // Package to which this file belongs.
 | 
			
		||||
	file *ast.File // Parsed AST.
 | 
			
		||||
	// These fields are reset for each type being generated.
 | 
			
		||||
	typeName string  // Name of the constant type.
 | 
			
		||||
	values   []Value // Accumulator for constant values of that type.
 | 
			
		||||
 | 
			
		||||
	trimPrefix  string
 | 
			
		||||
	lineComment bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Package struct {
 | 
			
		||||
	name  string
 | 
			
		||||
	defs  map[*ast.Ident]types.Object
 | 
			
		||||
	files []*File
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parsePackage analyzes the single package constructed from the patterns and tags.
 | 
			
		||||
// parsePackage exits if there is an error.
 | 
			
		||||
func (g *Generator) parsePackage(patterns []string, tags []string) {
 | 
			
		||||
	cfg := &packages.Config{
 | 
			
		||||
		Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax,
 | 
			
		||||
		// TODO: Need to think about constants in test files. Maybe write type_string_test.go
 | 
			
		||||
		// in a separate pass? For later.
 | 
			
		||||
		Tests:      false,
 | 
			
		||||
		BuildFlags: []string{fmt.Sprintf("-tags=%s", strings.Join(tags, " "))},
 | 
			
		||||
	}
 | 
			
		||||
	pkgs, err := packages.Load(cfg, patterns...)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if len(pkgs) != 1 {
 | 
			
		||||
		log.Fatalf("error: %d packages found", len(pkgs))
 | 
			
		||||
	}
 | 
			
		||||
	g.addPackage(pkgs[0])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// addPackage adds a type checked Package and its syntax files to the generator.
 | 
			
		||||
func (g *Generator) addPackage(pkg *packages.Package) {
 | 
			
		||||
	g.pkg = &Package{
 | 
			
		||||
		name:  pkg.Name,
 | 
			
		||||
		defs:  pkg.TypesInfo.Defs,
 | 
			
		||||
		files: make([]*File, len(pkg.Syntax)),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, file := range pkg.Syntax {
 | 
			
		||||
		g.pkg.files[i] = &File{
 | 
			
		||||
			file:        file,
 | 
			
		||||
			pkg:         g.pkg,
 | 
			
		||||
			trimPrefix:  g.trimPrefix,
 | 
			
		||||
			lineComment: g.lineComment,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generate produces the String method for the named type.
 | 
			
		||||
func (g *Generator) generate(typeName string) {
 | 
			
		||||
	values := make([]Value, 0, 100)
 | 
			
		||||
	for _, file := range g.pkg.files {
 | 
			
		||||
		// Set the state for this run of the walker.
 | 
			
		||||
		file.typeName = typeName
 | 
			
		||||
		file.values = nil
 | 
			
		||||
		if file.file != nil {
 | 
			
		||||
			ast.Inspect(file.file, file.genDecl)
 | 
			
		||||
			values = append(values, file.values...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(values) == 0 {
 | 
			
		||||
		log.Fatalf("no values defined for type %s", typeName)
 | 
			
		||||
	}
 | 
			
		||||
	// Generate code that will fail if the constants change value.
 | 
			
		||||
	g.Printf("func _() {\n")
 | 
			
		||||
	g.Printf("\t// An \"invalid array index\" compiler error signifies that the constant values have changed.\n")
 | 
			
		||||
	g.Printf("\t// Re-run the stringer command to generate them again.\n")
 | 
			
		||||
	g.Printf("\tvar x [1]struct{}\n")
 | 
			
		||||
	for _, v := range values {
 | 
			
		||||
		g.Printf("\t_ = x[%s - %s]\n", v.originalName, v.str)
 | 
			
		||||
	}
 | 
			
		||||
	g.Printf("}\n")
 | 
			
		||||
	runs := splitIntoRuns(values)
 | 
			
		||||
	// The decision of which pattern to use depends on the number of
 | 
			
		||||
	// runs in the numbers. If there's only one, it's easy. For more than
 | 
			
		||||
	// one, there's a tradeoff between complexity and size of the data
 | 
			
		||||
	// and code vs. the simplicity of a map. A map takes more space,
 | 
			
		||||
	// but so does the code. The decision here (crossover at 10) is
 | 
			
		||||
	// arbitrary, but considers that for large numbers of runs the cost
 | 
			
		||||
	// of the linear scan in the switch might become important, and
 | 
			
		||||
	// rather than use yet another algorithm such as binary search,
 | 
			
		||||
	// we punt and use a map. In any case, the likelihood of a map
 | 
			
		||||
	// being necessary for any realistic example other than bitmasks
 | 
			
		||||
	// is very low. And bitmasks probably deserve their own analysis,
 | 
			
		||||
	// to be done some other day.
 | 
			
		||||
	switch {
 | 
			
		||||
	case len(runs) == 1:
 | 
			
		||||
		g.buildOneRun(runs, typeName)
 | 
			
		||||
	case len(runs) <= 10:
 | 
			
		||||
		g.buildMultipleRuns(runs, typeName)
 | 
			
		||||
	default:
 | 
			
		||||
		g.buildMap(runs, typeName)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// splitIntoRuns breaks the values into runs of contiguous sequences.
 | 
			
		||||
// For example, given 1,2,3,5,6,7 it returns {1,2,3},{5,6,7}.
 | 
			
		||||
// The input slice is known to be non-empty.
 | 
			
		||||
func splitIntoRuns(values []Value) [][]Value {
 | 
			
		||||
	// We use stable sort so the lexically first name is chosen for equal elements.
 | 
			
		||||
	sort.Stable(byValue(values))
 | 
			
		||||
	// Remove duplicates. Stable sort has put the one we want to print first,
 | 
			
		||||
	// so use that one. The String method won't care about which named constant
 | 
			
		||||
	// was the argument, so the first name for the given value is the only one to keep.
 | 
			
		||||
	// We need to do this because identical values would cause the switch or map
 | 
			
		||||
	// to fail to compile.
 | 
			
		||||
	j := 1
 | 
			
		||||
	for i := 1; i < len(values); i++ {
 | 
			
		||||
		if values[i].value != values[i-1].value {
 | 
			
		||||
			values[j] = values[i]
 | 
			
		||||
			j++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	values = values[:j]
 | 
			
		||||
	runs := make([][]Value, 0, 10)
 | 
			
		||||
	for len(values) > 0 {
 | 
			
		||||
		// One contiguous sequence per outer loop.
 | 
			
		||||
		i := 1
 | 
			
		||||
		for i < len(values) && values[i].value == values[i-1].value+1 {
 | 
			
		||||
			i++
 | 
			
		||||
		}
 | 
			
		||||
		runs = append(runs, values[:i])
 | 
			
		||||
		values = values[i:]
 | 
			
		||||
	}
 | 
			
		||||
	return runs
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// format returns the gofmt-ed contents of the Generator's buffer.
 | 
			
		||||
func (g *Generator) format() []byte {
 | 
			
		||||
	src, err := format.Source(g.buf.Bytes())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// Should never happen, but can arise when developing this code.
 | 
			
		||||
		// The user can compile the output to see the error.
 | 
			
		||||
		log.Printf("warning: internal error: invalid Go generated: %s", err)
 | 
			
		||||
		log.Printf("warning: compile the package to analyze the error")
 | 
			
		||||
		return g.buf.Bytes()
 | 
			
		||||
	}
 | 
			
		||||
	return src
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Value represents a declared constant.
 | 
			
		||||
type Value struct {
 | 
			
		||||
	originalName string // The name of the constant.
 | 
			
		||||
	name         string // The name with trimmed prefix.
 | 
			
		||||
	// The value is stored as a bit pattern alone. The boolean tells us
 | 
			
		||||
	// whether to interpret it as an int64 or a uint64; the only place
 | 
			
		||||
	// this matters is when sorting.
 | 
			
		||||
	// Much of the time the str field is all we need; it is printed
 | 
			
		||||
	// by Value.String.
 | 
			
		||||
	value  uint64 // Will be converted to int64 when needed.
 | 
			
		||||
	signed bool   // Whether the constant is a signed type.
 | 
			
		||||
	str    string // The string representation given by the "go/constant" package.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (v *Value) String() string {
 | 
			
		||||
	return v.str
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// byValue lets us sort the constants into increasing order.
 | 
			
		||||
// We take care in the Less method to sort in signed or unsigned order,
 | 
			
		||||
// as appropriate.
 | 
			
		||||
type byValue []Value
 | 
			
		||||
 | 
			
		||||
func (b byValue) Len() int      { return len(b) }
 | 
			
		||||
func (b byValue) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
 | 
			
		||||
func (b byValue) Less(i, j int) bool {
 | 
			
		||||
	if b[i].signed {
 | 
			
		||||
		return int64(b[i].value) < int64(b[j].value)
 | 
			
		||||
	}
 | 
			
		||||
	return b[i].value < b[j].value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// genDecl processes one declaration clause.
 | 
			
		||||
func (f *File) genDecl(node ast.Node) bool {
 | 
			
		||||
	decl, ok := node.(*ast.GenDecl)
 | 
			
		||||
	if !ok || decl.Tok != token.CONST {
 | 
			
		||||
		// We only care about const declarations.
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	// The name of the type of the constants we are declaring.
 | 
			
		||||
	// Can change if this is a multi-element declaration.
 | 
			
		||||
	typ := ""
 | 
			
		||||
	// Loop over the elements of the declaration. Each element is a ValueSpec:
 | 
			
		||||
	// a list of names possibly followed by a type, possibly followed by values.
 | 
			
		||||
	// If the type and value are both missing, we carry down the type (and value,
 | 
			
		||||
	// but the "go/types" package takes care of that).
 | 
			
		||||
	for _, spec := range decl.Specs {
 | 
			
		||||
		vspec := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST.
 | 
			
		||||
		if vspec.Type == nil && len(vspec.Values) > 0 {
 | 
			
		||||
			// "X = 1". With no type but a value. If the constant is untyped,
 | 
			
		||||
			// skip this vspec and reset the remembered type.
 | 
			
		||||
			typ = ""
 | 
			
		||||
 | 
			
		||||
			// If this is a simple type conversion, remember the type.
 | 
			
		||||
			// We don't mind if this is actually a call; a qualified call won't
 | 
			
		||||
			// be matched (that will be SelectorExpr, not Ident), and only unusual
 | 
			
		||||
			// situations will result in a function call that appears to be
 | 
			
		||||
			// a type conversion.
 | 
			
		||||
			ce, ok := vspec.Values[0].(*ast.CallExpr)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			id, ok := ce.Fun.(*ast.Ident)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			typ = id.Name
 | 
			
		||||
		}
 | 
			
		||||
		if vspec.Type != nil {
 | 
			
		||||
			// "X T". We have a type. Remember it.
 | 
			
		||||
			ident, ok := vspec.Type.(*ast.Ident)
 | 
			
		||||
			if !ok {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			typ = ident.Name
 | 
			
		||||
		}
 | 
			
		||||
		if typ != f.typeName {
 | 
			
		||||
			// This is not the type we're looking for.
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		// We now have a list of names (from one line of source code) all being
 | 
			
		||||
		// declared with the desired type.
 | 
			
		||||
		// Grab their names and actual values and store them in f.values.
 | 
			
		||||
		for _, name := range vspec.Names {
 | 
			
		||||
			if name.Name == "_" {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			// This dance lets the type checker find the values for us. It's a
 | 
			
		||||
			// bit tricky: look up the object declared by the name, find its
 | 
			
		||||
			// types.Const, and extract its value.
 | 
			
		||||
			obj, ok := f.pkg.defs[name]
 | 
			
		||||
			if !ok {
 | 
			
		||||
				log.Fatalf("no value for constant %s", name)
 | 
			
		||||
			}
 | 
			
		||||
			info := obj.Type().Underlying().(*types.Basic).Info()
 | 
			
		||||
			if info&types.IsInteger == 0 {
 | 
			
		||||
				log.Fatalf("can't handle non-integer constant type %s", typ)
 | 
			
		||||
			}
 | 
			
		||||
			value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST.
 | 
			
		||||
			if value.Kind() != constant.Int {
 | 
			
		||||
				log.Fatalf("can't happen: constant is not an integer %s", name)
 | 
			
		||||
			}
 | 
			
		||||
			i64, isInt := constant.Int64Val(value)
 | 
			
		||||
			u64, isUint := constant.Uint64Val(value)
 | 
			
		||||
			if !isInt && !isUint {
 | 
			
		||||
				log.Fatalf("internal error: value of %s is not an integer: %s", name, value.String())
 | 
			
		||||
			}
 | 
			
		||||
			if !isInt {
 | 
			
		||||
				u64 = uint64(i64)
 | 
			
		||||
			}
 | 
			
		||||
			v := Value{
 | 
			
		||||
				originalName: name.Name,
 | 
			
		||||
				value:        u64,
 | 
			
		||||
				signed:       info&types.IsUnsigned == 0,
 | 
			
		||||
				str:          value.String(),
 | 
			
		||||
			}
 | 
			
		||||
			if c := vspec.Comment; f.lineComment && c != nil && len(c.List) == 1 {
 | 
			
		||||
				v.name = strings.TrimSpace(c.Text())
 | 
			
		||||
			} else {
 | 
			
		||||
				v.name = strings.TrimPrefix(v.originalName, f.trimPrefix)
 | 
			
		||||
			}
 | 
			
		||||
			f.values = append(f.values, v)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helpers
 | 
			
		||||
 | 
			
		||||
// usize returns the number of bits of the smallest unsigned integer
 | 
			
		||||
// type that will hold n. Used to create the smallest possible slice of
 | 
			
		||||
// integers to use as indexes into the concatenated strings.
 | 
			
		||||
func usize(n int) int {
 | 
			
		||||
	switch {
 | 
			
		||||
	case n < 1<<8:
 | 
			
		||||
		return 8
 | 
			
		||||
	case n < 1<<16:
 | 
			
		||||
		return 16
 | 
			
		||||
	default:
 | 
			
		||||
		// 2^32 is enough constants for anyone.
 | 
			
		||||
		return 32
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// declareIndexAndNameVars declares the index slices and concatenated names
 | 
			
		||||
// strings representing the runs of values.
 | 
			
		||||
func (g *Generator) declareIndexAndNameVars(runs [][]Value, typeName string) {
 | 
			
		||||
	var indexes, names []string
 | 
			
		||||
	for i, run := range runs {
 | 
			
		||||
		index, name := g.createIndexAndNameDecl(run, typeName, fmt.Sprintf("_%d", i))
 | 
			
		||||
		if len(run) != 1 {
 | 
			
		||||
			indexes = append(indexes, index)
 | 
			
		||||
		}
 | 
			
		||||
		names = append(names, name)
 | 
			
		||||
	}
 | 
			
		||||
	g.Printf("const (\n")
 | 
			
		||||
	for _, name := range names {
 | 
			
		||||
		g.Printf("\t%s\n", name)
 | 
			
		||||
	}
 | 
			
		||||
	g.Printf(")\n\n")
 | 
			
		||||
 | 
			
		||||
	if len(indexes) > 0 {
 | 
			
		||||
		g.Printf("var (")
 | 
			
		||||
		for _, index := range indexes {
 | 
			
		||||
			g.Printf("\t%s\n", index)
 | 
			
		||||
		}
 | 
			
		||||
		g.Printf(")\n\n")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// declareIndexAndNameVar is the single-run version of declareIndexAndNameVars
 | 
			
		||||
func (g *Generator) declareIndexAndNameVar(run []Value, typeName string) {
 | 
			
		||||
	index, name := g.createIndexAndNameDecl(run, typeName, "")
 | 
			
		||||
	g.Printf("const %s\n", name)
 | 
			
		||||
	g.Printf("var %s\n", index)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// createIndexAndNameDecl returns the pair of declarations for the run. The caller will add "const" and "var".
 | 
			
		||||
func (g *Generator) createIndexAndNameDecl(run []Value, typeName string, suffix string) (string, string) {
 | 
			
		||||
	b := new(bytes.Buffer)
 | 
			
		||||
	indexes := make([]int, len(run))
 | 
			
		||||
	for i := range run {
 | 
			
		||||
		b.WriteString(run[i].name)
 | 
			
		||||
		indexes[i] = b.Len()
 | 
			
		||||
	}
 | 
			
		||||
	nameConst := fmt.Sprintf("_%s_name%s = %q", typeName, suffix, b.String())
 | 
			
		||||
	nameLen := b.Len()
 | 
			
		||||
	b.Reset()
 | 
			
		||||
	fmt.Fprintf(b, "_%s_index%s = [...]uint%d{0, ", typeName, suffix, usize(nameLen))
 | 
			
		||||
	for i, v := range indexes {
 | 
			
		||||
		if i > 0 {
 | 
			
		||||
			fmt.Fprintf(b, ", ")
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Fprintf(b, "%d", v)
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Fprintf(b, "}")
 | 
			
		||||
	return b.String(), nameConst
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// declareNameVars declares the concatenated names string representing all the values in the runs.
 | 
			
		||||
func (g *Generator) declareNameVars(runs [][]Value, typeName string, suffix string) {
 | 
			
		||||
	g.Printf("const _%s_name%s = \"", typeName, suffix)
 | 
			
		||||
	for _, run := range runs {
 | 
			
		||||
		for i := range run {
 | 
			
		||||
			g.Printf("%s", run[i].name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	g.Printf("\"\n")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// buildOneRun generates the variables and String method for a single run of contiguous values.
 | 
			
		||||
func (g *Generator) buildOneRun(runs [][]Value, typeName string) {
 | 
			
		||||
	values := runs[0]
 | 
			
		||||
	g.Printf("\n")
 | 
			
		||||
	g.declareIndexAndNameVar(values, typeName)
 | 
			
		||||
	// The generated code is simple enough to write as a Printf format.
 | 
			
		||||
	lessThanZero := ""
 | 
			
		||||
	if values[0].signed {
 | 
			
		||||
		lessThanZero = "i < 0 || "
 | 
			
		||||
	}
 | 
			
		||||
	if values[0].value == 0 { // Signed or unsigned, 0 is still 0.
 | 
			
		||||
		g.Printf(stringOneRun, typeName, usize(len(values)), lessThanZero)
 | 
			
		||||
	} else {
 | 
			
		||||
		g.Printf(stringOneRunWithOffset, typeName, values[0].String(), usize(len(values)), lessThanZero)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Arguments to format are:
 | 
			
		||||
//
 | 
			
		||||
//	[1]: type name
 | 
			
		||||
//	[2]: size of index element (8 for uint8 etc.)
 | 
			
		||||
//	[3]: less than zero check (for signed types)
 | 
			
		||||
const stringOneRun = `func (i %[1]s) String() string {
 | 
			
		||||
	if %[3]si >= %[1]s(len(_%[1]s_index)-1) {
 | 
			
		||||
		return "%[1]s(" + strconv.FormatInt(int64(i), 10) + ")"
 | 
			
		||||
	}
 | 
			
		||||
	return _%[1]s_name[_%[1]s_index[i]:_%[1]s_index[i+1]]
 | 
			
		||||
}
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// Arguments to format are:
 | 
			
		||||
//	[1]: type name
 | 
			
		||||
//	[2]: lowest defined value for type, as a string
 | 
			
		||||
//	[3]: size of index element (8 for uint8 etc.)
 | 
			
		||||
//	[4]: less than zero check (for signed types)
 | 
			
		||||
/*
 | 
			
		||||
 */
 | 
			
		||||
const stringOneRunWithOffset = `func (i %[1]s) String() string {
 | 
			
		||||
	i -= %[2]s
 | 
			
		||||
	if %[4]si >= %[1]s(len(_%[1]s_index)-1) {
 | 
			
		||||
		return "%[1]s(" + strconv.FormatInt(int64(i + %[2]s), 10) + ")"
 | 
			
		||||
	}
 | 
			
		||||
	return _%[1]s_name[_%[1]s_index[i] : _%[1]s_index[i+1]]
 | 
			
		||||
}
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
// buildMultipleRuns generates the variables and String method for multiple runs of contiguous values.
 | 
			
		||||
// For this pattern, a single Printf format won't do.
 | 
			
		||||
func (g *Generator) buildMultipleRuns(runs [][]Value, typeName string) {
 | 
			
		||||
	g.Printf("\n")
 | 
			
		||||
	g.declareIndexAndNameVars(runs, typeName)
 | 
			
		||||
	g.Printf("func (i %s) String() string {\n", typeName)
 | 
			
		||||
	g.Printf("\tswitch {\n")
 | 
			
		||||
	for i, values := range runs {
 | 
			
		||||
		if len(values) == 1 {
 | 
			
		||||
			g.Printf("\tcase i == %s:\n", &values[0])
 | 
			
		||||
			g.Printf("\t\treturn _%s_name_%d\n", typeName, i)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if values[0].value == 0 && !values[0].signed {
 | 
			
		||||
			// For an unsigned lower bound of 0, "0 <= i" would be redundant.
 | 
			
		||||
			g.Printf("\tcase i <= %s:\n", &values[len(values)-1])
 | 
			
		||||
		} else {
 | 
			
		||||
			g.Printf("\tcase %s <= i && i <= %s:\n", &values[0], &values[len(values)-1])
 | 
			
		||||
		}
 | 
			
		||||
		if values[0].value != 0 {
 | 
			
		||||
			g.Printf("\t\ti -= %s\n", &values[0])
 | 
			
		||||
		}
 | 
			
		||||
		g.Printf("\t\treturn _%s_name_%d[_%s_index_%d[i]:_%s_index_%d[i+1]]\n",
 | 
			
		||||
			typeName, i, typeName, i, typeName, i)
 | 
			
		||||
	}
 | 
			
		||||
	g.Printf("\tdefault:\n")
 | 
			
		||||
	g.Printf("\t\treturn \"%s(\" + strconv.FormatInt(int64(i), 10) + \")\"\n", typeName)
 | 
			
		||||
	g.Printf("\t}\n")
 | 
			
		||||
	g.Printf("}\n")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// buildMap handles the case where the space is so sparse a map is a reasonable fallback.
 | 
			
		||||
// It's a rare situation but has simple code.
 | 
			
		||||
func (g *Generator) buildMap(runs [][]Value, typeName string) {
 | 
			
		||||
	g.Printf("\n")
 | 
			
		||||
	g.declareNameVars(runs, typeName, "")
 | 
			
		||||
	g.Printf("\nvar _%s_map = map[%s]string{\n", typeName, typeName)
 | 
			
		||||
	n := 0
 | 
			
		||||
	for _, values := range runs {
 | 
			
		||||
		for _, value := range values {
 | 
			
		||||
			g.Printf("\t%s: _%s_name[%d:%d],\n", &value, typeName, n, n+len(value.name))
 | 
			
		||||
			n += len(value.name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	g.Printf("}\n\n")
 | 
			
		||||
	g.Printf(stringMap, typeName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Argument to format is the type name.
 | 
			
		||||
const stringMap = `func (i %[1]s) String() string {
 | 
			
		||||
	if str, ok := _%[1]s_map[i]; ok {
 | 
			
		||||
		return str
 | 
			
		||||
	}
 | 
			
		||||
	return "%[1]s(" + strconv.FormatInt(int64(i), 10) + ")"
 | 
			
		||||
}
 | 
			
		||||
`
 | 
			
		||||
							
								
								
									
										6
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -58,9 +58,10 @@ github.com/JeffAshton/win_pdh
 | 
			
		||||
# github.com/MakeNowJust/heredoc v1.0.0
 | 
			
		||||
## explicit; go 1.12
 | 
			
		||||
github.com/MakeNowJust/heredoc
 | 
			
		||||
# github.com/Microsoft/go-winio v0.4.17
 | 
			
		||||
## explicit; go 1.12
 | 
			
		||||
# github.com/Microsoft/go-winio v0.6.0
 | 
			
		||||
## explicit; go 1.17
 | 
			
		||||
github.com/Microsoft/go-winio
 | 
			
		||||
github.com/Microsoft/go-winio/internal/socket
 | 
			
		||||
github.com/Microsoft/go-winio/pkg/guid
 | 
			
		||||
github.com/Microsoft/go-winio/pkg/security
 | 
			
		||||
github.com/Microsoft/go-winio/vhd
 | 
			
		||||
@@ -1028,6 +1029,7 @@ golang.org/x/time/rate
 | 
			
		||||
# golang.org/x/tools v0.8.0
 | 
			
		||||
## explicit; go 1.18
 | 
			
		||||
golang.org/x/tools/benchmark/parse
 | 
			
		||||
golang.org/x/tools/cmd/stringer
 | 
			
		||||
golang.org/x/tools/container/intsets
 | 
			
		||||
golang.org/x/tools/go/ast/astutil
 | 
			
		||||
golang.org/x/tools/go/ast/inspector
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user