mirror of
https://github.com/ko-build/ko.git
synced 2025-07-15 23:54:17 +02:00
bump ggcr and handle breaking change (#866)
This commit is contained in:
14
go.mod
14
go.mod
@ -10,8 +10,8 @@ require (
|
|||||||
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936
|
github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936
|
||||||
github.com/go-training/helloworld v0.0.0-20200225145412-ba5f4379d78b
|
github.com/go-training/helloworld v0.0.0-20200225145412-ba5f4379d78b
|
||||||
github.com/google/go-cmp v0.5.9
|
github.com/google/go-cmp v0.5.9
|
||||||
github.com/google/go-containerregistry v0.11.0
|
github.com/google/go-containerregistry v0.12.0
|
||||||
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198
|
github.com/opencontainers/image-spec v1.1.0-rc2
|
||||||
github.com/sigstore/cosign v1.13.1
|
github.com/sigstore/cosign v1.13.1
|
||||||
github.com/spf13/cobra v1.6.1
|
github.com/spf13/cobra v1.6.1
|
||||||
github.com/spf13/viper v1.14.0
|
github.com/spf13/viper v1.14.0
|
||||||
@ -36,7 +36,7 @@ require (
|
|||||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||||
github.com/BurntSushi/toml v1.1.0 // indirect
|
github.com/BurntSushi/toml v1.1.0 // indirect
|
||||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||||
github.com/alessio/shellescape v1.4.1 // indirect
|
github.com/alessio/shellescape v1.4.1 // indirect
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.16 // indirect
|
github.com/aws/aws-sdk-go-v2 v1.16.16 // indirect
|
||||||
@ -55,11 +55,11 @@ require (
|
|||||||
github.com/aws/smithy-go v1.13.3 // indirect
|
github.com/aws/smithy-go v1.13.3 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||||
github.com/docker/cli v20.10.17+incompatible // indirect
|
github.com/docker/cli v20.10.20+incompatible // indirect
|
||||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
github.com/docker/go-units v0.4.0 // indirect
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/go-logr/logr v1.2.3 // indirect
|
github.com/go-logr/logr v1.2.3 // indirect
|
||||||
@ -109,7 +109,7 @@ require (
|
|||||||
golang.org/x/crypto v0.1.0 // indirect
|
golang.org/x/crypto v0.1.0 // indirect
|
||||||
golang.org/x/mod v0.6.0 // indirect
|
golang.org/x/mod v0.6.0 // indirect
|
||||||
golang.org/x/net v0.1.0 // indirect
|
golang.org/x/net v0.1.0 // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 // indirect
|
golang.org/x/oauth2 v0.1.0 // indirect
|
||||||
golang.org/x/sys v0.1.0 // indirect
|
golang.org/x/sys v0.1.0 // indirect
|
||||||
golang.org/x/term v0.1.0 // indirect
|
golang.org/x/term v0.1.0 // indirect
|
||||||
golang.org/x/text v0.4.0 // indirect
|
golang.org/x/text v0.4.0 // indirect
|
||||||
|
@ -51,7 +51,7 @@ func New() *cobra.Command {
|
|||||||
|
|
||||||
// Also add the auth group from crane to facilitate logging into a
|
// Also add the auth group from crane to facilitate logging into a
|
||||||
// registry.
|
// registry.
|
||||||
authCmd := cranecmd.NewCmdAuth("ko", "auth")
|
authCmd := cranecmd.NewCmdAuth(nil, "ko", "auth")
|
||||||
// That was a mistake, but just set it to Hidden so we don't break people.
|
// That was a mistake, but just set it to Hidden so we don't break people.
|
||||||
authCmd.Hidden = true
|
authCmd.Hidden = true
|
||||||
root.AddCommand(authCmd)
|
root.AddCommand(authCmd)
|
||||||
|
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
|
*.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
|
74
vendor/github.com/Microsoft/go-winio/README.md
generated
vendored
74
vendor/github.com/Microsoft/go-winio/README.md
generated
vendored
@ -13,16 +13,60 @@ Please see the LICENSE file for licensing information.
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA)
|
This project welcomes contributions and suggestions.
|
||||||
declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
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
|
When you submit a pull request, a CLA-bot will automatically determine whether you need to
|
||||||
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.
|
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.
|
||||||
|
|
||||||
We also require that contributors sign their commits using git commit -s or git commit --signoff to certify they either authored the work themselves
|
Additionally, the pull request pipeline requires the following steps to be performed before
|
||||||
or otherwise have permission to use it in this project. Please see https://developercertificate.org/ for more info, as well as to make sure that you can
|
mergining.
|
||||||
attest to the rules listed. Our CI uses the DCO Github app to ensure that all commits in a given PR are signed-off.
|
|
||||||
|
|
||||||
|
### 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
|
## Code of Conduct
|
||||||
|
|
||||||
@ -30,8 +74,16 @@ This project has adopted the [Microsoft Open Source Code of Conduct](https://ope
|
|||||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
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.
|
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Special Thanks
|
## Special Thanks
|
||||||
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
|
|
||||||
for another named pipe implementation.
|
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
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
@ -7,11 +8,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unicode/utf16"
|
"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
|
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
|
||||||
@ -24,7 +26,7 @@ const (
|
|||||||
BackupAlternateData
|
BackupAlternateData
|
||||||
BackupLink
|
BackupLink
|
||||||
BackupPropertyData
|
BackupPropertyData
|
||||||
BackupObjectId
|
BackupObjectId //revive:disable-line:var-naming ID, not Id
|
||||||
BackupReparseData
|
BackupReparseData
|
||||||
BackupSparseBlock
|
BackupSparseBlock
|
||||||
BackupTxfsData
|
BackupTxfsData
|
||||||
@ -34,14 +36,16 @@ const (
|
|||||||
StreamSparseAttributes = uint32(8)
|
StreamSparseAttributes = uint32(8)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//nolint:revive // var-naming: ALL_CAPS
|
||||||
const (
|
const (
|
||||||
WRITE_DAC = 0x40000
|
WRITE_DAC = windows.WRITE_DAC
|
||||||
WRITE_OWNER = 0x80000
|
WRITE_OWNER = windows.WRITE_OWNER
|
||||||
ACCESS_SYSTEM_SECURITY = 0x1000000
|
ACCESS_SYSTEM_SECURITY = windows.ACCESS_SYSTEM_SECURITY
|
||||||
)
|
)
|
||||||
|
|
||||||
// BackupHeader represents a backup stream of a file.
|
// BackupHeader represents a backup stream of a file.
|
||||||
type BackupHeader struct {
|
type BackupHeader struct {
|
||||||
|
//revive:disable-next-line:var-naming ID, not Id
|
||||||
Id uint32 // The backup stream ID
|
Id uint32 // The backup stream ID
|
||||||
Attributes uint32 // Stream attributes
|
Attributes uint32 // Stream attributes
|
||||||
Size int64 // The size of the stream in bytes
|
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).
|
Offset int64 // The offset of the stream in the file (for BackupSparseBlock only).
|
||||||
}
|
}
|
||||||
|
|
||||||
type win32StreamId struct {
|
type win32StreamID struct {
|
||||||
StreamId uint32
|
StreamID uint32
|
||||||
Attributes uint32
|
Attributes uint32
|
||||||
Size uint64
|
Size uint64
|
||||||
NameSize uint32
|
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
|
// 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.
|
// it was not completely read.
|
||||||
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
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 {
|
if s, ok := r.r.(io.Seeker); ok {
|
||||||
// Make sure Seek on io.SeekCurrent sometimes succeeds
|
// Make sure Seek on io.SeekCurrent sometimes succeeds
|
||||||
// before trying the actual seek.
|
// before trying the actual seek.
|
||||||
@ -82,16 +86,16 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
|||||||
r.bytesLeft = 0
|
r.bytesLeft = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if _, err := io.Copy(ioutil.Discard, r); err != nil {
|
if _, err := io.Copy(io.Discard, r); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var wsi win32StreamId
|
var wsi win32StreamID
|
||||||
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
|
if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
hdr := &BackupHeader{
|
hdr := &BackupHeader{
|
||||||
Id: wsi.StreamId,
|
Id: wsi.StreamID,
|
||||||
Attributes: wsi.Attributes,
|
Attributes: wsi.Attributes,
|
||||||
Size: int64(wsi.Size),
|
Size: int64(wsi.Size),
|
||||||
}
|
}
|
||||||
@ -102,7 +106,7 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
|
|||||||
}
|
}
|
||||||
hdr.Name = syscall.UTF16ToString(name)
|
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 {
|
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -147,8 +151,8 @@ func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
|
|||||||
return fmt.Errorf("missing %d bytes", w.bytesLeft)
|
return fmt.Errorf("missing %d bytes", w.bytesLeft)
|
||||||
}
|
}
|
||||||
name := utf16.Encode([]rune(hdr.Name))
|
name := utf16.Encode([]rune(hdr.Name))
|
||||||
wsi := win32StreamId{
|
wsi := win32StreamID{
|
||||||
StreamId: hdr.Id,
|
StreamID: hdr.Id,
|
||||||
Attributes: hdr.Attributes,
|
Attributes: hdr.Attributes,
|
||||||
Size: uint64(hdr.Size),
|
Size: uint64(hdr.Size),
|
||||||
NameSize: uint32(len(name) * 2),
|
NameSize: uint32(len(name) * 2),
|
||||||
@ -203,7 +207,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
|
|||||||
var bytesRead uint32
|
var bytesRead uint32
|
||||||
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
|
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
|
||||||
if err != nil {
|
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)
|
runtime.KeepAlive(r.f)
|
||||||
if bytesRead == 0 {
|
if bytesRead == 0 {
|
||||||
@ -216,7 +220,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
|
|||||||
// the underlying file.
|
// the underlying file.
|
||||||
func (r *BackupFileReader) Close() error {
|
func (r *BackupFileReader) Close() error {
|
||||||
if r.ctx != 0 {
|
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)
|
runtime.KeepAlive(r.f)
|
||||||
r.ctx = 0
|
r.ctx = 0
|
||||||
}
|
}
|
||||||
@ -242,7 +246,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
|
|||||||
var bytesWritten uint32
|
var bytesWritten uint32
|
||||||
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
|
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
|
||||||
if err != nil {
|
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)
|
runtime.KeepAlive(w.f)
|
||||||
if int(bytesWritten) != len(b) {
|
if int(bytesWritten) != len(b) {
|
||||||
@ -255,7 +259,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
|
|||||||
// close the underlying file.
|
// close the underlying file.
|
||||||
func (w *BackupFileWriter) Close() error {
|
func (w *BackupFileWriter) Close() error {
|
||||||
if w.ctx != 0 {
|
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)
|
runtime.KeepAlive(w.f)
|
||||||
w.ctx = 0
|
w.ctx = 0
|
||||||
}
|
}
|
||||||
@ -271,7 +275,13 @@ func OpenForBackup(path string, access uint32, share uint32, createmode uint32)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
err = &os.PathError{Op: "open", Path: path, Err: err}
|
err = &os.PathError{Op: "open", Path: path, Err: err}
|
||||||
return nil, 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)
|
err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errInvalidEaBuffer
|
err = errInvalidEaBuffer
|
||||||
return
|
return ea, nb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
nameOffset := fileFullEaInformationSize
|
nameOffset := fileFullEaInformationSize
|
||||||
@ -43,7 +43,7 @@ func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
|
|||||||
nextOffset := int(info.NextEntryOffset)
|
nextOffset := int(info.NextEntryOffset)
|
||||||
if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
|
if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
|
||||||
err = errInvalidEaBuffer
|
err = errInvalidEaBuffer
|
||||||
return
|
return ea, nb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ea.Name = string(b[nameOffset : nameOffset+nameLen])
|
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 {
|
if info.NextEntryOffset != 0 {
|
||||||
nb = b[info.NextEntryOffset:]
|
nb = b[info.NextEntryOffset:]
|
||||||
}
|
}
|
||||||
return
|
return ea, nb, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
|
// 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)
|
eas = append(eas, ea)
|
||||||
b = nb
|
b = nb
|
||||||
}
|
}
|
||||||
return
|
return eas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
|
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
|
||||||
|
66
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
66
vendor/github.com/Microsoft/go-winio/file.go
generated
vendored
@ -11,6 +11,8 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
|
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
|
||||||
@ -24,6 +26,8 @@ type atomicBool int32
|
|||||||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
|
||||||
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
func (b *atomicBool) setFalse() { atomic.StoreInt32((*int32)(b), 0) }
|
||||||
func (b *atomicBool) setTrue() { atomic.StoreInt32((*int32)(b), 1) }
|
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 {
|
func (b *atomicBool) swap(new bool) bool {
|
||||||
var newInt int32
|
var newInt int32
|
||||||
if new {
|
if new {
|
||||||
@ -32,11 +36,6 @@ func (b *atomicBool) swap(new bool) bool {
|
|||||||
return atomic.SwapInt32((*int32)(b), newInt) == 1
|
return atomic.SwapInt32((*int32)(b), newInt) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 1
|
|
||||||
cFILE_SKIP_SET_EVENT_ON_HANDLE = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrFileClosed = errors.New("file has already been closed")
|
ErrFileClosed = errors.New("file has already been closed")
|
||||||
ErrTimeout = &timeoutError{}
|
ErrTimeout = &timeoutError{}
|
||||||
@ -44,28 +43,28 @@ var (
|
|||||||
|
|
||||||
type timeoutError struct{}
|
type timeoutError struct{}
|
||||||
|
|
||||||
func (e *timeoutError) Error() string { return "i/o timeout" }
|
func (*timeoutError) Error() string { return "i/o timeout" }
|
||||||
func (e *timeoutError) Timeout() bool { return true }
|
func (*timeoutError) Timeout() bool { return true }
|
||||||
func (e *timeoutError) Temporary() bool { return true }
|
func (*timeoutError) Temporary() bool { return true }
|
||||||
|
|
||||||
type timeoutChan chan struct{}
|
type timeoutChan chan struct{}
|
||||||
|
|
||||||
var ioInitOnce sync.Once
|
var ioInitOnce sync.Once
|
||||||
var ioCompletionPort syscall.Handle
|
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 {
|
type ioResult struct {
|
||||||
bytes uint32
|
bytes uint32
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// ioOperation represents an outstanding asynchronous Win32 IO
|
// ioOperation represents an outstanding asynchronous Win32 IO.
|
||||||
type ioOperation struct {
|
type ioOperation struct {
|
||||||
o syscall.Overlapped
|
o syscall.Overlapped
|
||||||
ch chan ioResult
|
ch chan ioResult
|
||||||
}
|
}
|
||||||
|
|
||||||
func initIo() {
|
func initIO() {
|
||||||
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
|
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -94,15 +93,15 @@ type deadlineHandler struct {
|
|||||||
timedout atomicBool
|
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) {
|
func makeWin32File(h syscall.Handle) (*win32File, error) {
|
||||||
f := &win32File{handle: h}
|
f := &win32File{handle: h}
|
||||||
ioInitOnce.Do(initIo)
|
ioInitOnce.Do(initIO)
|
||||||
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
|
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -121,14 +120,14 @@ func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
|
|||||||
return f, nil
|
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() {
|
func (f *win32File) closeHandle() {
|
||||||
f.wgLock.Lock()
|
f.wgLock.Lock()
|
||||||
// Atomically set that we are closing, releasing the resources only once.
|
// Atomically set that we are closing, releasing the resources only once.
|
||||||
if !f.closing.swap(true) {
|
if !f.closing.swap(true) {
|
||||||
f.wgLock.Unlock()
|
f.wgLock.Unlock()
|
||||||
// cancel all IO and wait for it to complete
|
// cancel all IO and wait for it to complete
|
||||||
cancelIoEx(f.handle, nil)
|
_ = cancelIoEx(f.handle, nil)
|
||||||
f.wg.Wait()
|
f.wg.Wait()
|
||||||
// at this point, no new IO can start
|
// at this point, no new IO can start
|
||||||
syscall.Close(f.handle)
|
syscall.Close(f.handle)
|
||||||
@ -144,14 +143,14 @@ func (f *win32File) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsClosed checks if the file has been closed
|
// IsClosed checks if the file has been closed.
|
||||||
func (f *win32File) IsClosed() bool {
|
func (f *win32File) IsClosed() bool {
|
||||||
return f.closing.isSet()
|
return f.closing.isSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareIo prepares for a new IO operation.
|
// prepareIO prepares for a new IO operation.
|
||||||
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
|
// 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()
|
f.wgLock.RLock()
|
||||||
if f.closing.isSet() {
|
if f.closing.isSet() {
|
||||||
f.wgLock.RUnlock()
|
f.wgLock.RUnlock()
|
||||||
@ -164,7 +163,7 @@ func (f *win32File) prepareIo() (*ioOperation, error) {
|
|||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ioCompletionProcessor processes completed async IOs forever
|
// ioCompletionProcessor processes completed async IOs forever.
|
||||||
func ioCompletionProcessor(h syscall.Handle) {
|
func ioCompletionProcessor(h syscall.Handle) {
|
||||||
for {
|
for {
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
@ -178,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.
|
// the operation has actually completed.
|
||||||
func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
|
func (f *win32File) asyncIO(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
|
||||||
if err != syscall.ERROR_IO_PENDING {
|
if err != syscall.ERROR_IO_PENDING { //nolint:errorlint // err is Errno
|
||||||
return int(bytes), err
|
return int(bytes), err
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.closing.isSet() {
|
if f.closing.isSet() {
|
||||||
cancelIoEx(f.handle, &c.o)
|
_ = cancelIoEx(f.handle, &c.o)
|
||||||
}
|
}
|
||||||
|
|
||||||
var timeout timeoutChan
|
var timeout timeoutChan
|
||||||
@ -200,7 +201,7 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
|||||||
select {
|
select {
|
||||||
case r = <-c.ch:
|
case r = <-c.ch:
|
||||||
err = r.err
|
err = r.err
|
||||||
if err == syscall.ERROR_OPERATION_ABORTED {
|
if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||||
if f.closing.isSet() {
|
if f.closing.isSet() {
|
||||||
err = ErrFileClosed
|
err = ErrFileClosed
|
||||||
}
|
}
|
||||||
@ -210,10 +211,10 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
|||||||
err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
|
err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
|
||||||
}
|
}
|
||||||
case <-timeout:
|
case <-timeout:
|
||||||
cancelIoEx(f.handle, &c.o)
|
_ = cancelIoEx(f.handle, &c.o)
|
||||||
r = <-c.ch
|
r = <-c.ch
|
||||||
err = r.err
|
err = r.err
|
||||||
if err == syscall.ERROR_OPERATION_ABORTED {
|
if err == syscall.ERROR_OPERATION_ABORTED { //nolint:errorlint // err is Errno
|
||||||
err = ErrTimeout
|
err = ErrTimeout
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,13 +222,14 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
|
|||||||
// runtime.KeepAlive is needed, as c is passed via native
|
// runtime.KeepAlive is needed, as c is passed via native
|
||||||
// code to ioCompletionProcessor, c must remain alive
|
// code to ioCompletionProcessor, c must remain alive
|
||||||
// until the channel read is complete.
|
// until the channel read is complete.
|
||||||
|
// todo: (de)allocate *ioOperation via win32 heap functions, instead of needing to KeepAlive?
|
||||||
runtime.KeepAlive(c)
|
runtime.KeepAlive(c)
|
||||||
return int(r.bytes), err
|
return int(r.bytes), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read reads from a file handle.
|
// Read reads from a file handle.
|
||||||
func (f *win32File) Read(b []byte) (int, error) {
|
func (f *win32File) Read(b []byte) (int, error) {
|
||||||
c, err := f.prepareIo()
|
c, err := f.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -239,13 +241,13 @@ func (f *win32File) Read(b []byte) (int, error) {
|
|||||||
|
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
|
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)
|
runtime.KeepAlive(b)
|
||||||
|
|
||||||
// Handle EOF conditions.
|
// Handle EOF conditions.
|
||||||
if err == nil && n == 0 && len(b) != 0 {
|
if err == nil && n == 0 && len(b) != 0 {
|
||||||
return 0, io.EOF
|
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
|
return 0, io.EOF
|
||||||
} else {
|
} else {
|
||||||
return n, err
|
return n, err
|
||||||
@ -254,7 +256,7 @@ func (f *win32File) Read(b []byte) (int, error) {
|
|||||||
|
|
||||||
// Write writes to a file handle.
|
// Write writes to a file handle.
|
||||||
func (f *win32File) Write(b []byte) (int, error) {
|
func (f *win32File) Write(b []byte) (int, error) {
|
||||||
c, err := f.prepareIo()
|
c, err := f.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -266,7 +268,7 @@ func (f *win32File) Write(b []byte) (int, error) {
|
|||||||
|
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
|
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)
|
runtime.KeepAlive(b)
|
||||||
return n, err
|
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
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
@ -14,13 +15,18 @@ import (
|
|||||||
type FileBasicInfo struct {
|
type FileBasicInfo struct {
|
||||||
CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
|
CreationTime, LastAccessTime, LastWriteTime, ChangeTime windows.Filetime
|
||||||
FileAttributes uint32
|
FileAttributes uint32
|
||||||
pad uint32 // padding
|
_ uint32 // padding
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFileBasicInfo retrieves times and attributes for a file.
|
// GetFileBasicInfo retrieves times and attributes for a file.
|
||||||
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
||||||
bi := &FileBasicInfo{}
|
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}
|
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(f)
|
runtime.KeepAlive(f)
|
||||||
@ -29,7 +35,12 @@ func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
|
|||||||
|
|
||||||
// SetFileBasicInfo sets times and attributes for a file.
|
// SetFileBasicInfo sets times and attributes for a file.
|
||||||
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
|
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}
|
return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(f)
|
runtime.KeepAlive(f)
|
||||||
@ -48,7 +59,10 @@ type FileStandardInfo struct {
|
|||||||
// GetFileStandardInfo retrieves ended information for the file.
|
// GetFileStandardInfo retrieves ended information for the file.
|
||||||
func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
|
func GetFileStandardInfo(f *os.File) (*FileStandardInfo, error) {
|
||||||
si := &FileStandardInfo{}
|
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}
|
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(f)
|
runtime.KeepAlive(f)
|
||||||
@ -65,7 +79,12 @@ type FileIDInfo struct {
|
|||||||
// GetFileID retrieves the unique (volume, file ID) pair for a file.
|
// GetFileID retrieves the unique (volume, file ID) pair for a file.
|
||||||
func GetFileID(f *os.File) (*FileIDInfo, error) {
|
func GetFileID(f *os.File) (*FileIDInfo, error) {
|
||||||
fileID := &FileIDInfo{}
|
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}
|
return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(f)
|
runtime.KeepAlive(f)
|
||||||
|
345
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
345
vendor/github.com/Microsoft/go-winio/hvsock.go
generated
vendored
@ -4,6 +4,8 @@
|
|||||||
package winio
|
package winio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
@ -12,16 +14,87 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
"github.com/Microsoft/go-winio/internal/socket"
|
||||||
"github.com/Microsoft/go-winio/pkg/guid"
|
"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 (
|
// Well known Service and VM IDs
|
||||||
afHvSock = 34 // AF_HYPERV
|
//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.
|
// An HvsockAddr is an address for a AF_HYPERV socket.
|
||||||
type HvsockAddr struct {
|
type HvsockAddr struct {
|
||||||
@ -36,8 +109,10 @@ type rawHvsockAddr struct {
|
|||||||
ServiceID guid.GUID
|
ServiceID guid.GUID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ socket.RawSockaddr = &rawHvsockAddr{}
|
||||||
|
|
||||||
// Network returns the address's network name, "hvsock".
|
// Network returns the address's network name, "hvsock".
|
||||||
func (addr *HvsockAddr) Network() string {
|
func (*HvsockAddr) Network() string {
|
||||||
return "hvsock"
|
return "hvsock"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,14 +122,14 @@ func (addr *HvsockAddr) String() string {
|
|||||||
|
|
||||||
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
|
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
|
||||||
func VsockServiceID(port uint32) guid.GUID {
|
func VsockServiceID(port uint32) guid.GUID {
|
||||||
g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
|
g := hvsockVsockServiceTemplate() // make a copy
|
||||||
g.Data1 = port
|
g.Data1 = port
|
||||||
return g
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
func (addr *HvsockAddr) raw() rawHvsockAddr {
|
func (addr *HvsockAddr) raw() rawHvsockAddr {
|
||||||
return rawHvsockAddr{
|
return rawHvsockAddr{
|
||||||
Family: afHvSock,
|
Family: afHVSock,
|
||||||
VMID: addr.VMID,
|
VMID: addr.VMID,
|
||||||
ServiceID: addr.ServiceID,
|
ServiceID: addr.ServiceID,
|
||||||
}
|
}
|
||||||
@ -65,20 +140,48 @@ func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
|
|||||||
addr.ServiceID = raw.ServiceID
|
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.
|
// HvsockListener is a socket listener for the AF_HYPERV address family.
|
||||||
type HvsockListener struct {
|
type HvsockListener struct {
|
||||||
sock *win32File
|
sock *win32File
|
||||||
addr HvsockAddr
|
addr HvsockAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ net.Listener = &HvsockListener{}
|
||||||
|
|
||||||
// HvsockConn is a connected socket of the AF_HYPERV address family.
|
// HvsockConn is a connected socket of the AF_HYPERV address family.
|
||||||
type HvsockConn struct {
|
type HvsockConn struct {
|
||||||
sock *win32File
|
sock *win32File
|
||||||
local, remote HvsockAddr
|
local, remote HvsockAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func newHvSocket() (*win32File, error) {
|
var _ net.Conn = &HvsockConn{}
|
||||||
fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
|
|
||||||
|
func newHVSocket() (*win32File, error) {
|
||||||
|
fd, err := syscall.Socket(afHVSock, syscall.SOCK_STREAM, 1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, os.NewSyscallError("socket", err)
|
return nil, os.NewSyscallError("socket", err)
|
||||||
}
|
}
|
||||||
@ -94,12 +197,12 @@ func newHvSocket() (*win32File, error) {
|
|||||||
// ListenHvsock listens for connections on the specified hvsock address.
|
// ListenHvsock listens for connections on the specified hvsock address.
|
||||||
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
|
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
|
||||||
l := &HvsockListener{addr: *addr}
|
l := &HvsockListener{addr: *addr}
|
||||||
sock, err := newHvSocket()
|
sock, err := newHVSocket()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, l.opErr("listen", err)
|
return nil, l.opErr("listen", err)
|
||||||
}
|
}
|
||||||
sa := addr.raw()
|
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 {
|
if err != nil {
|
||||||
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
|
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
|
||||||
}
|
}
|
||||||
@ -121,7 +224,7 @@ func (l *HvsockListener) Addr() net.Addr {
|
|||||||
|
|
||||||
// Accept waits for the next connection and returns it.
|
// Accept waits for the next connection and returns it.
|
||||||
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
|
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
|
||||||
sock, err := newHvSocket()
|
sock, err := newHVSocket()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, l.opErr("accept", err)
|
return nil, l.opErr("accept", err)
|
||||||
}
|
}
|
||||||
@ -130,27 +233,42 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
|
|||||||
sock.Close()
|
sock.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
c, err := l.sock.prepareIo()
|
c, err := l.sock.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, l.opErr("accept", err)
|
return nil, l.opErr("accept", err)
|
||||||
}
|
}
|
||||||
defer l.sock.wg.Done()
|
defer l.sock.wg.Done()
|
||||||
|
|
||||||
// AcceptEx, per documentation, requires an extra 16 bytes per address.
|
// 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{}))
|
const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
|
||||||
var addrbuf [addrlen * 2]byte
|
var addrbuf [addrlen * 2]byte
|
||||||
|
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
|
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /*rxdatalen*/, addrlen, addrlen, &bytes, &c.o)
|
||||||
_, err = l.sock.asyncIo(c, nil, bytes, err)
|
if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
|
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
conn := &HvsockConn{
|
conn := &HvsockConn{
|
||||||
sock: sock,
|
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.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
|
||||||
conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
|
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
|
sock = nil
|
||||||
return conn, nil
|
return conn, nil
|
||||||
}
|
}
|
||||||
@ -160,43 +278,171 @@ func (l *HvsockListener) Close() error {
|
|||||||
return l.sock.Close()
|
return l.sock.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need to finish ConnectEx handling
|
// HvsockDialer configures and dials a Hyper-V Socket (ie, [HvsockConn]).
|
||||||
func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
|
type HvsockDialer struct {
|
||||||
sock, err := newHvSocket()
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, conn.opErr(op, err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if sock != nil {
|
if sock != nil {
|
||||||
sock.Close()
|
sock.Close()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
c, err := sock.prepareIo()
|
|
||||||
|
sa := addr.raw()
|
||||||
|
err = socket.Bind(windows.Handle(sock.handle), &sa)
|
||||||
if err != nil {
|
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()
|
defer sock.wg.Done()
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
|
for i := uint(0); i <= d.Retries; i++ {
|
||||||
_, err = sock.asyncIo(ctx, c, nil, bytes, err)
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, conn.opErr(op, os.NewSyscallError("connectex", err))
|
||||||
}
|
}
|
||||||
conn := &HvsockConn{
|
|
||||||
sock: sock,
|
// update the connection properties, so shutdown can be used
|
||||||
remote: *addr,
|
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
|
sock = nil
|
||||||
|
|
||||||
return conn, 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 {
|
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}
|
return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *HvsockConn) Read(b []byte) (int, error) {
|
func (conn *HvsockConn) Read(b []byte) (int, error) {
|
||||||
c, err := conn.sock.prepareIo()
|
c, err := conn.sock.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, conn.opErr("read", err)
|
return 0, conn.opErr("read", err)
|
||||||
}
|
}
|
||||||
@ -204,10 +450,11 @@ func (conn *HvsockConn) Read(b []byte) (int, error) {
|
|||||||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||||
var flags, bytes uint32
|
var flags, bytes uint32
|
||||||
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
|
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 err != nil {
|
||||||
if _, ok := err.(syscall.Errno); ok {
|
var eno windows.Errno
|
||||||
err = os.NewSyscallError("wsarecv", err)
|
if errors.As(err, &eno) {
|
||||||
|
err = os.NewSyscallError("wsarecv", eno)
|
||||||
}
|
}
|
||||||
return 0, conn.opErr("read", err)
|
return 0, conn.opErr("read", err)
|
||||||
} else if n == 0 {
|
} else if n == 0 {
|
||||||
@ -230,7 +477,7 @@ func (conn *HvsockConn) Write(b []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return 0, conn.opErr("write", err)
|
return 0, conn.opErr("write", err)
|
||||||
}
|
}
|
||||||
@ -238,10 +485,11 @@ func (conn *HvsockConn) write(b []byte) (int, error) {
|
|||||||
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
|
||||||
var bytes uint32
|
var bytes uint32
|
||||||
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
|
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 err != nil {
|
||||||
if _, ok := err.(syscall.Errno); ok {
|
var eno windows.Errno
|
||||||
err = os.NewSyscallError("wsasend", err)
|
if errors.As(err, &eno) {
|
||||||
|
err = os.NewSyscallError("wsasend", eno)
|
||||||
}
|
}
|
||||||
return 0, conn.opErr("write", err)
|
return 0, conn.opErr("write", err)
|
||||||
}
|
}
|
||||||
@ -257,13 +505,19 @@ func (conn *HvsockConn) IsClosed() bool {
|
|||||||
return conn.sock.IsClosed()
|
return conn.sock.IsClosed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shutdown disables sending or receiving on a socket.
|
||||||
func (conn *HvsockConn) shutdown(how int) error {
|
func (conn *HvsockConn) shutdown(how int) error {
|
||||||
if conn.IsClosed() {
|
if conn.IsClosed() {
|
||||||
return ErrFileClosed
|
return socket.ErrSocketClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
err := syscall.Shutdown(conn.sock.handle, how)
|
err := syscall.Shutdown(conn.sock.handle, how)
|
||||||
if err != nil {
|
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 os.NewSyscallError("shutdown", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -273,7 +527,7 @@ func (conn *HvsockConn) shutdown(how int) error {
|
|||||||
func (conn *HvsockConn) CloseRead() error {
|
func (conn *HvsockConn) CloseRead() error {
|
||||||
err := conn.shutdown(syscall.SHUT_RD)
|
err := conn.shutdown(syscall.SHUT_RD)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conn.opErr("close", err)
|
return conn.opErr("closeread", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -283,7 +537,7 @@ func (conn *HvsockConn) CloseRead() error {
|
|||||||
func (conn *HvsockConn) CloseWrite() error {
|
func (conn *HvsockConn) CloseWrite() error {
|
||||||
err := conn.shutdown(syscall.SHUT_WR)
|
err := conn.shutdown(syscall.SHUT_WR)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conn.opErr("close", err)
|
return conn.opErr("closewrite", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -300,8 +554,13 @@ func (conn *HvsockConn) RemoteAddr() net.Addr {
|
|||||||
|
|
||||||
// SetDeadline implements the net.Conn SetDeadline method.
|
// SetDeadline implements the net.Conn SetDeadline method.
|
||||||
func (conn *HvsockConn) SetDeadline(t time.Time) error {
|
func (conn *HvsockConn) SetDeadline(t time.Time) error {
|
||||||
conn.SetReadDeadline(t)
|
// todo: implement `SetDeadline` for `win32File`
|
||||||
conn.SetWriteDeadline(t)
|
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
|
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
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
@ -13,6 +14,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
|
//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 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 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 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 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 rtlNtStatusToDosError(status ntStatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
|
||||||
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U
|
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntStatus) = ntdll.RtlDosPathNameToNtPathName_U
|
||||||
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl
|
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntStatus) = ntdll.RtlDefaultNpAcl
|
||||||
|
|
||||||
type ioStatusBlock struct {
|
type ioStatusBlock struct {
|
||||||
Status, Information uintptr
|
Status, Information uintptr
|
||||||
@ -51,45 +54,22 @@ type securityDescriptor struct {
|
|||||||
Control uint16
|
Control uint16
|
||||||
Owner uintptr
|
Owner uintptr
|
||||||
Group uintptr
|
Group uintptr
|
||||||
Sacl uintptr
|
Sacl uintptr //revive:disable-line:var-naming SACL, not Sacl
|
||||||
Dacl uintptr
|
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 {
|
if status >= 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return rtlNtStatusToDosError(status)
|
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 (
|
var (
|
||||||
// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
|
// 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 = net.ErrClosed
|
||||||
ErrPipeListenerClosed = errors.New("use of closed network connection")
|
|
||||||
|
|
||||||
errPipeWriteClosed = errors.New("pipe has been closed for write")
|
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 {
|
func (f *win32Pipe) SetDeadline(t time.Time) error {
|
||||||
f.SetReadDeadline(t)
|
if err := f.SetReadDeadline(t); err != nil {
|
||||||
f.SetWriteDeadline(t)
|
return err
|
||||||
return nil
|
}
|
||||||
|
return f.SetWriteDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CloseWrite closes the write side of a message pipe in byte mode.
|
// 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
|
return 0, io.EOF
|
||||||
}
|
}
|
||||||
n, err := f.win32File.Read(b)
|
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
|
// If this was the result of a zero-byte read, then
|
||||||
// it is possible that the read was due to a zero-size
|
// it is possible that the read was due to a zero-size
|
||||||
// message. Since we are simulating CloseWrite with a
|
// message. Since we are simulating CloseWrite with a
|
||||||
// zero-byte message, ensure that all future Read() calls
|
// zero-byte message, ensure that all future Read() calls
|
||||||
// also return EOF.
|
// also return EOF.
|
||||||
f.readEOF = true
|
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
|
// 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
|
// and the message still has more bytes. Treat this as a success, since
|
||||||
// this package presents all named pipes as byte streams.
|
// this package presents all named pipes as byte streams.
|
||||||
@ -173,7 +154,7 @@ func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
|
|||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s pipeAddress) Network() string {
|
func (pipeAddress) Network() string {
|
||||||
return "pipe"
|
return "pipe"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,16 +165,21 @@ func (s pipeAddress) String() string {
|
|||||||
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
|
// 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) {
|
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
|
||||||
for {
|
for {
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return syscall.Handle(0), ctx.Err()
|
return syscall.Handle(0), ctx.Err()
|
||||||
default:
|
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 {
|
if err == nil {
|
||||||
return h, 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}
|
return h, &os.PathError{Err: err, Op: "open", Path: *path}
|
||||||
}
|
}
|
||||||
// Wait 10 msec and try again. This is a rather simplistic
|
// 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 {
|
} else {
|
||||||
absTimeout = time.Now().Add(2 * time.Second)
|
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)
|
conn, err := DialPipeContext(ctx, path)
|
||||||
if err == context.DeadlineExceeded {
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
return nil, ErrTimeout
|
return nil, ErrTimeout
|
||||||
}
|
}
|
||||||
return conn, err
|
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
|
// If the pipe is in message mode, return a message byte pipe, which
|
||||||
// supports CloseWrite().
|
// supports CloseWrite().
|
||||||
if flags&cPIPE_TYPE_MESSAGE != 0 {
|
if flags&windows.PIPE_TYPE_MESSAGE != 0 {
|
||||||
return &win32MessageBytePipe{
|
return &win32MessageBytePipe{
|
||||||
win32Pipe: win32Pipe{win32File: f, path: path},
|
win32Pipe: win32Pipe{win32File: f, path: path},
|
||||||
}, nil
|
}, nil
|
||||||
@ -283,7 +270,11 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
|
|||||||
oa.Length = unsafe.Sizeof(oa)
|
oa.Length = unsafe.Sizeof(oa)
|
||||||
|
|
||||||
var ntPath unicodeString
|
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}
|
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||||
}
|
}
|
||||||
defer localFree(ntPath.Buffer)
|
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.
|
// The security descriptor is only needed for the first pipe.
|
||||||
if first {
|
if first {
|
||||||
if sd != nil {
|
if sd != nil {
|
||||||
len := uint32(len(sd))
|
l := uint32(len(sd))
|
||||||
sdb := localAlloc(0, len)
|
sdb := localAlloc(0, l)
|
||||||
defer localFree(sdb)
|
defer localFree(sdb)
|
||||||
copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
|
copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
|
||||||
oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
|
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.
|
// Construct the default named pipe security descriptor.
|
||||||
var dacl uintptr
|
var dacl uintptr
|
||||||
if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
|
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)
|
defer localFree(dacl)
|
||||||
|
|
||||||
sdb := &securityDescriptor{
|
sdb := &securityDescriptor{
|
||||||
Revision: 1,
|
Revision: 1,
|
||||||
Control: cSE_DACL_PRESENT,
|
Control: windows.SE_DACL_PRESENT,
|
||||||
Dacl: dacl,
|
Dacl: dacl,
|
||||||
}
|
}
|
||||||
oa.SecurityDescriptor = sdb
|
oa.SecurityDescriptor = sdb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS)
|
typ := uint32(windows.FILE_PIPE_REJECT_REMOTE_CLIENTS)
|
||||||
if c.MessageMode {
|
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)
|
access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
|
||||||
if first {
|
if first {
|
||||||
disposition = cFILE_CREATE
|
disposition = windows.FILE_CREATE
|
||||||
// By not asking for read or write access, the named pipe file system
|
// By not asking for read or write access, the named pipe file system
|
||||||
// will put this pipe into an initially disconnected state, blocking
|
// will put this pipe into an initially disconnected state, blocking
|
||||||
// client connections until the next call with first == false.
|
// 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
|
h syscall.Handle
|
||||||
iosb ioStatusBlock
|
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 {
|
if err != nil {
|
||||||
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
return 0, &os.PathError{Op: "open", Path: path, Err: err}
|
||||||
}
|
}
|
||||||
@ -380,7 +384,7 @@ func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) {
|
|||||||
p.Close()
|
p.Close()
|
||||||
p = nil
|
p = nil
|
||||||
err = <-ch
|
err = <-ch
|
||||||
if err == nil || err == ErrFileClosed {
|
if err == nil || err == ErrFileClosed { //nolint:errorlint // err is Errno
|
||||||
err = ErrPipeListenerClosed
|
err = ErrPipeListenerClosed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -402,12 +406,12 @@ func (l *win32PipeListener) listenerRoutine() {
|
|||||||
p, err = l.makeConnectedServerPipe()
|
p, err = l.makeConnectedServerPipe()
|
||||||
// If the connection was immediately closed by the client, try
|
// If the connection was immediately closed by the client, try
|
||||||
// again.
|
// again.
|
||||||
if err != cERROR_NO_DATA {
|
if err != windows.ERROR_NO_DATA { //nolint:errorlint // err is Errno
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
responseCh <- acceptResponse{p, err}
|
responseCh <- acceptResponse{p, err}
|
||||||
closed = err == ErrPipeListenerClosed
|
closed = err == ErrPipeListenerClosed //nolint:errorlint // err is Errno
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
syscall.Close(l.firstHandle)
|
syscall.Close(l.firstHandle)
|
||||||
@ -469,15 +473,15 @@ func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func connectPipe(p *win32File) error {
|
func connectPipe(p *win32File) error {
|
||||||
c, err := p.prepareIo()
|
c, err := p.prepareIO()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer p.wg.Done()
|
defer p.wg.Done()
|
||||||
|
|
||||||
err = connectNamedPipe(p.handle, &c.o)
|
err = connectNamedPipe(p.handle, &c.o)
|
||||||
_, err = p.asyncIo(c, nil, 0, err)
|
_, err = p.asyncIO(c, nil, 0, err)
|
||||||
if err != nil && err != cERROR_PIPE_CONNECTED {
|
if err != nil && err != windows.ERROR_PIPE_CONNECTED { //nolint:errorlint // err is Errno
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
16
vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
generated
vendored
16
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
|
// 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.
|
// 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,
|
// There are two main binary encodings used for a GUID, the big-endian encoding,
|
||||||
@ -9,24 +7,26 @@ package guid
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha1"
|
"crypto/sha1" //nolint:gosec // not used for secure application
|
||||||
"encoding"
|
"encoding"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//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
|
// Variant specifies which GUID variant (or "type") of the GUID. It determines
|
||||||
// how the entirety of the rest of the GUID is interpreted.
|
// how the entirety of the rest of the GUID is interpreted.
|
||||||
type Variant uint8
|
type Variant uint8
|
||||||
|
|
||||||
// The variants specified by RFC 4122.
|
// The variants specified by RFC 4122 section 4.1.1.
|
||||||
const (
|
const (
|
||||||
// VariantUnknown specifies a GUID variant which does not conform to one of
|
// VariantUnknown specifies a GUID variant which does not conform to one of
|
||||||
// the variant encodings specified in RFC 4122.
|
// the variant encodings specified in RFC 4122.
|
||||||
VariantUnknown Variant = iota
|
VariantUnknown Variant = iota
|
||||||
VariantNCS
|
VariantNCS
|
||||||
VariantRFC4122
|
VariantRFC4122 // RFC 4122
|
||||||
VariantMicrosoft
|
VariantMicrosoft
|
||||||
VariantFuture
|
VariantFuture
|
||||||
)
|
)
|
||||||
@ -36,6 +36,10 @@ const (
|
|||||||
// hash of an input string.
|
// hash of an input string.
|
||||||
type Version uint8
|
type Version uint8
|
||||||
|
|
||||||
|
func (v Version) String() string {
|
||||||
|
return strconv.FormatUint(uint64(v), 10)
|
||||||
|
}
|
||||||
|
|
||||||
var _ = (encoding.TextMarshaler)(GUID{})
|
var _ = (encoding.TextMarshaler)(GUID{})
|
||||||
var _ = (encoding.TextUnmarshaler)(&GUID{})
|
var _ = (encoding.TextUnmarshaler)(&GUID{})
|
||||||
|
|
||||||
@ -61,7 +65,7 @@ func NewV4() (GUID, error) {
|
|||||||
// big-endian UTF16 stream of bytes. If that is desired, the string can be
|
// big-endian UTF16 stream of bytes. If that is desired, the string can be
|
||||||
// encoded as such before being passed to this function.
|
// encoded as such before being passed to this function.
|
||||||
func NewV5(namespace GUID, name []byte) (GUID, error) {
|
func NewV5(namespace GUID, name []byte) (GUID, error) {
|
||||||
b := sha1.New()
|
b := sha1.New() //nolint:gosec // not used for secure application
|
||||||
namespaceBytes := namespace.ToArray()
|
namespaceBytes := namespace.ToArray()
|
||||||
b.Write(namespaceBytes[:])
|
b.Write(namespaceBytes[:])
|
||||||
b.Write(name)
|
b.Write(name)
|
||||||
|
1
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
generated
vendored
1
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_nonwindows.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build !windows
|
||||||
// +build !windows
|
// +build !windows
|
||||||
|
|
||||||
package guid
|
package guid
|
||||||
|
3
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
generated
vendored
3
vendor/github.com/Microsoft/go-winio/pkg/guid/guid_windows.go
generated
vendored
@ -1,3 +1,6 @@
|
|||||||
|
//go:build windows
|
||||||
|
// +build windows
|
||||||
|
|
||||||
package guid
|
package guid
|
||||||
|
|
||||||
import "golang.org/x/sys/windows"
|
import "golang.org/x/sys/windows"
|
||||||
|
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]]
|
||||||
|
}
|
32
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
32
vendor/github.com/Microsoft/go-winio/privilege.go
generated
vendored
@ -1,3 +1,4 @@
|
|||||||
|
//go:build windows
|
||||||
// +build windows
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
@ -24,22 +25,17 @@ import (
|
|||||||
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
|
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
|
||||||
|
|
||||||
const (
|
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"
|
SeBackupPrivilege = "SeBackupPrivilege"
|
||||||
SeRestorePrivilege = "SeRestorePrivilege"
|
SeRestorePrivilege = "SeRestorePrivilege"
|
||||||
SeSecurityPrivilege = "SeSecurityPrivilege"
|
SeSecurityPrivilege = "SeSecurityPrivilege"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
securityAnonymous = iota
|
|
||||||
securityIdentification
|
|
||||||
securityImpersonation
|
|
||||||
securityDelegation
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
privNames = make(map[string]uint64)
|
privNames = make(map[string]uint64)
|
||||||
privNameMutex sync.Mutex
|
privNameMutex sync.Mutex
|
||||||
@ -51,11 +47,9 @@ type PrivilegeError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *PrivilegeError) Error() string {
|
func (e *PrivilegeError) Error() string {
|
||||||
s := ""
|
s := "Could not enable privilege "
|
||||||
if len(e.privileges) > 1 {
|
if len(e.privileges) > 1 {
|
||||||
s = "Could not enable privileges "
|
s = "Could not enable privileges "
|
||||||
} else {
|
|
||||||
s = "Could not enable privilege "
|
|
||||||
}
|
}
|
||||||
for i, p := range e.privileges {
|
for i, p := range e.privileges {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
@ -94,7 +88,7 @@ func RunWithPrivileges(names []string, fn func() error) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mapPrivileges(names []string) ([]uint64, error) {
|
func mapPrivileges(names []string) ([]uint64, error) {
|
||||||
var privileges []uint64
|
privileges := make([]uint64, 0, len(names))
|
||||||
privNameMutex.Lock()
|
privNameMutex.Lock()
|
||||||
defer privNameMutex.Unlock()
|
defer privNameMutex.Unlock()
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
@ -127,7 +121,7 @@ func enableDisableProcessPrivilege(names []string, action uint32) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
p, _ := windows.GetCurrentProcess()
|
p := windows.CurrentProcess()
|
||||||
var token windows.Token
|
var token windows.Token
|
||||||
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
|
err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -140,10 +134,10 @@ func enableDisableProcessPrivilege(names []string, action uint32) error {
|
|||||||
|
|
||||||
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
|
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
|
_ = binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
|
||||||
for _, p := range privileges {
|
for _, p := range privileges {
|
||||||
binary.Write(&b, binary.LittleEndian, p)
|
_ = binary.Write(&b, binary.LittleEndian, p)
|
||||||
binary.Write(&b, binary.LittleEndian, action)
|
_ = binary.Write(&b, binary.LittleEndian, action)
|
||||||
}
|
}
|
||||||
prevState := make([]byte, b.Len())
|
prevState := make([]byte, b.Len())
|
||||||
reqSize := uint32(0)
|
reqSize := uint32(0)
|
||||||
@ -151,7 +145,7 @@ func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) e
|
|||||||
if !success {
|
if !success {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err == ERROR_NOT_ALL_ASSIGNED {
|
if err == ERROR_NOT_ALL_ASSIGNED { //nolint:errorlint // err is Errno
|
||||||
return &PrivilegeError{privileges}
|
return &PrivilegeError{privileges}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -177,7 +171,7 @@ func getPrivilegeName(luid uint64) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newThreadToken() (windows.Token, error) {
|
func newThreadToken() (windows.Token, error) {
|
||||||
err := impersonateSelf(securityImpersonation)
|
err := impersonateSelf(windows.SecurityImpersonation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
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
|
package winio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -113,16 +116,16 @@ func EncodeReparsePoint(rp *ReparsePoint) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
binary.Write(&b, binary.LittleEndian, &data)
|
_ = binary.Write(&b, binary.LittleEndian, &data)
|
||||||
if !rp.IsMountPoint {
|
if !rp.IsMountPoint {
|
||||||
flags := uint32(0)
|
flags := uint32(0)
|
||||||
if relative {
|
if relative {
|
||||||
flags |= 1
|
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, ntTarget16)
|
||||||
binary.Write(&b, binary.LittleEndian, target16)
|
_ = binary.Write(&b, binary.LittleEndian, target16)
|
||||||
return b.Bytes()
|
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
|
// +build windows
|
||||||
|
|
||||||
package winio
|
package winio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"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 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 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 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 convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
|
||||||
//sys localFree(mem uintptr) = LocalFree
|
//sys localFree(mem uintptr) = LocalFree
|
||||||
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
|
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
|
||||||
|
|
||||||
const (
|
|
||||||
cERROR_NONE_MAPPED = syscall.Errno(1332)
|
|
||||||
)
|
|
||||||
|
|
||||||
type AccountLookupError struct {
|
type AccountLookupError struct {
|
||||||
Name string
|
Name string
|
||||||
Err error
|
Err error
|
||||||
@ -28,8 +30,10 @@ func (e *AccountLookupError) Error() string {
|
|||||||
return "lookup account: empty account name specified"
|
return "lookup account: empty account name specified"
|
||||||
}
|
}
|
||||||
var s string
|
var s string
|
||||||
switch e.Err {
|
switch {
|
||||||
case cERROR_NONE_MAPPED:
|
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"
|
s = "not found"
|
||||||
default:
|
default:
|
||||||
s = e.Err.Error()
|
s = e.Err.Error()
|
||||||
@ -37,6 +41,8 @@ func (e *AccountLookupError) Error() string {
|
|||||||
return "lookup account " + e.Name + ": " + s
|
return "lookup account " + e.Name + ": " + s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *AccountLookupError) Unwrap() error { return e.Err }
|
||||||
|
|
||||||
type SddlConversionError struct {
|
type SddlConversionError struct {
|
||||||
Sddl string
|
Sddl string
|
||||||
Err error
|
Err error
|
||||||
@ -46,15 +52,19 @@ func (e *SddlConversionError) Error() string {
|
|||||||
return "convert " + e.Sddl + ": " + e.Err.Error()
|
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
|
// 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) {
|
func LookupSidByName(name string) (sid string, err error) {
|
||||||
if name == "" {
|
if name == "" {
|
||||||
return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
|
return "", &AccountLookupError{name, windows.ERROR_NONE_MAPPED}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sidSize, sidNameUse, refDomainSize uint32
|
var sidSize, sidNameUse, refDomainSize uint32
|
||||||
err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
|
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}
|
return "", &AccountLookupError{name, err}
|
||||||
}
|
}
|
||||||
sidBuffer := make([]byte, sidSize)
|
sidBuffer := make([]byte, sidSize)
|
||||||
@ -73,6 +83,42 @@ func LookupSidByName(name string) (sid string, err error) {
|
|||||||
return sid, nil
|
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) {
|
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
|
||||||
var sdBuffer uintptr
|
var sdBuffer uintptr
|
||||||
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
|
err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
|
||||||
@ -87,7 +133,7 @@ func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
|
|||||||
|
|
||||||
func SecurityDescriptorToSddl(sd []byte) (string, error) {
|
func SecurityDescriptorToSddl(sd []byte) (string, error) {
|
||||||
var sddl *uint16
|
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.
|
// Don't use it.
|
||||||
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
|
err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
|
||||||
if err != 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
|
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"
|
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
|
package winio
|
||||||
|
|
||||||
@ -47,9 +49,11 @@ var (
|
|||||||
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
|
procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
|
||||||
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
procConvertSidToStringSidW = modadvapi32.NewProc("ConvertSidToStringSidW")
|
||||||
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
|
procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
|
||||||
|
procConvertStringSidToSidW = modadvapi32.NewProc("ConvertStringSidToSidW")
|
||||||
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
|
procGetSecurityDescriptorLength = modadvapi32.NewProc("GetSecurityDescriptorLength")
|
||||||
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
||||||
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
procLookupAccountNameW = modadvapi32.NewProc("LookupAccountNameW")
|
||||||
|
procLookupAccountSidW = modadvapi32.NewProc("LookupAccountSidW")
|
||||||
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
procLookupPrivilegeDisplayNameW = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
|
||||||
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
|
procLookupPrivilegeNameW = modadvapi32.NewProc("LookupPrivilegeNameW")
|
||||||
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
|
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
|
||||||
@ -74,7 +78,6 @@ var (
|
|||||||
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
|
procRtlDosPathNameToNtPathName_U = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
|
||||||
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
|
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
|
||||||
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
|
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) {
|
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
|
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) {
|
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
|
||||||
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
|
r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
|
||||||
len = uint32(r0)
|
len = uint32(r0)
|
||||||
@ -154,6 +165,14 @@ func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidS
|
|||||||
return
|
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) {
|
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
|
||||||
var _p0 *uint16
|
var _p0 *uint16
|
||||||
_p0, err = syscall.UTF16PtrFromString(systemName)
|
_p0, err = syscall.UTF16PtrFromString(systemName)
|
||||||
@ -380,25 +399,25 @@ func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err erro
|
|||||||
return
|
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)
|
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
|
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)
|
r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
|
||||||
status = ntstatus(r0)
|
status = ntStatus(r0)
|
||||||
return
|
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)
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func rtlNtStatusToDosError(status ntstatus) (winerr error) {
|
func rtlNtStatusToDosError(status ntStatus) (winerr error) {
|
||||||
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
|
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
|
||||||
if r0 != 0 {
|
if r0 != 0 {
|
||||||
winerr = syscall.Errno(r0)
|
winerr = syscall.Errno(r0)
|
||||||
@ -417,11 +436,3 @@ func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint
|
|||||||
}
|
}
|
||||||
return
|
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
|
|
||||||
}
|
|
||||||
|
2
vendor/github.com/docker/cli/cli/config/credentials/native_store.go
generated
vendored
2
vendor/github.com/docker/cli/cli/config/credentials/native_store.go
generated
vendored
@ -7,7 +7,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
remoteCredentialsPrefix = "docker-credential-"
|
remoteCredentialsPrefix = "docker-credential-" //nolint:gosec // ignore G101: Potential hardcoded credentials
|
||||||
tokenUsername = "<token>"
|
tokenUsername = "<token>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
8
vendor/github.com/docker/docker-credential-helpers/credentials/credentials.go
generated
vendored
8
vendor/github.com/docker/docker-credential-helpers/credentials/credentials.go
generated
vendored
@ -169,8 +169,8 @@ func Erase(helper Helper, reader io.Reader) error {
|
|||||||
return helper.Delete(serverURL)
|
return helper.Delete(serverURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
//List returns all the serverURLs of keys in
|
// List returns all the serverURLs of keys in
|
||||||
//the OS store as a list of strings
|
// the OS store as a list of strings
|
||||||
func List(helper Helper, writer io.Writer) error {
|
func List(helper Helper, writer io.Writer) error {
|
||||||
accts, err := helper.List()
|
accts, err := helper.List()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -179,8 +179,8 @@ func List(helper Helper, writer io.Writer) error {
|
|||||||
return json.NewEncoder(writer).Encode(accts)
|
return json.NewEncoder(writer).Encode(accts)
|
||||||
}
|
}
|
||||||
|
|
||||||
//PrintVersion outputs the current version.
|
// PrintVersion outputs the current version.
|
||||||
func PrintVersion(writer io.Writer) error {
|
func PrintVersion(writer io.Writer) error {
|
||||||
fmt.Fprintln(writer, Version)
|
fmt.Fprintf(writer, "%s (%s) %s\n", Name, Package, Version)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
16
vendor/github.com/docker/docker-credential-helpers/credentials/version.go
generated
vendored
16
vendor/github.com/docker/docker-credential-helpers/credentials/version.go
generated
vendored
@ -1,4 +1,16 @@
|
|||||||
package credentials
|
package credentials
|
||||||
|
|
||||||
// Version holds a string describing the current version
|
var (
|
||||||
const Version = "0.6.4"
|
// Name is filled at linking time
|
||||||
|
Name = ""
|
||||||
|
|
||||||
|
// Package is filled at linking time
|
||||||
|
Package = "github.com/docker/docker-credential-helpers"
|
||||||
|
|
||||||
|
// Version holds the complete version number. Filled in at linking time.
|
||||||
|
Version = "v0.0.0+unknown"
|
||||||
|
|
||||||
|
// Revision is filled with the VCS (e.g. git) revision being used to build
|
||||||
|
// the program at linking time.
|
||||||
|
Revision = ""
|
||||||
|
)
|
||||||
|
70
vendor/github.com/docker/go-units/size.go
generated
vendored
70
vendor/github.com/docker/go-units/size.go
generated
vendored
@ -2,7 +2,6 @@ package units
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -26,16 +25,17 @@ const (
|
|||||||
PiB = 1024 * TiB
|
PiB = 1024 * TiB
|
||||||
)
|
)
|
||||||
|
|
||||||
type unitMap map[string]int64
|
type unitMap map[byte]int64
|
||||||
|
|
||||||
var (
|
var (
|
||||||
decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
|
decimalMap = unitMap{'k': KB, 'm': MB, 'g': GB, 't': TB, 'p': PB}
|
||||||
binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB}
|
binaryMap = unitMap{'k': KiB, 'm': MiB, 'g': GiB, 't': TiB, 'p': PiB}
|
||||||
sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[iI]?[bB]?$`)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
var (
|
||||||
var binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
|
decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}
|
||||||
|
binaryAbbrs = []string{"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
|
||||||
|
)
|
||||||
|
|
||||||
func getSizeAndUnit(size float64, base float64, _map []string) (float64, string) {
|
func getSizeAndUnit(size float64, base float64, _map []string) (float64, string) {
|
||||||
i := 0
|
i := 0
|
||||||
@ -89,20 +89,66 @@ func RAMInBytes(size string) (int64, error) {
|
|||||||
|
|
||||||
// Parses the human-readable size string into the amount it represents.
|
// Parses the human-readable size string into the amount it represents.
|
||||||
func parseSize(sizeStr string, uMap unitMap) (int64, error) {
|
func parseSize(sizeStr string, uMap unitMap) (int64, error) {
|
||||||
matches := sizeRegex.FindStringSubmatch(sizeStr)
|
// TODO: rewrite to use strings.Cut if there's a space
|
||||||
if len(matches) != 4 {
|
// once Go < 1.18 is deprecated.
|
||||||
|
sep := strings.LastIndexAny(sizeStr, "01234567890. ")
|
||||||
|
if sep == -1 {
|
||||||
|
// There should be at least a digit.
|
||||||
return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
|
return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
|
||||||
}
|
}
|
||||||
|
var num, sfx string
|
||||||
|
if sizeStr[sep] != ' ' {
|
||||||
|
num = sizeStr[:sep+1]
|
||||||
|
sfx = sizeStr[sep+1:]
|
||||||
|
} else {
|
||||||
|
// Omit the space separator.
|
||||||
|
num = sizeStr[:sep]
|
||||||
|
sfx = sizeStr[sep+1:]
|
||||||
|
}
|
||||||
|
|
||||||
size, err := strconv.ParseFloat(matches[1], 64)
|
size, err := strconv.ParseFloat(num, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
// Backward compatibility: reject negative sizes.
|
||||||
|
if size < 0 {
|
||||||
|
return -1, fmt.Errorf("invalid size: '%s'", sizeStr)
|
||||||
|
}
|
||||||
|
|
||||||
unitPrefix := strings.ToLower(matches[3])
|
if len(sfx) == 0 {
|
||||||
if mul, ok := uMap[unitPrefix]; ok {
|
return int64(size), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the suffix.
|
||||||
|
|
||||||
|
if len(sfx) > 3 { // Too long.
|
||||||
|
goto badSuffix
|
||||||
|
}
|
||||||
|
sfx = strings.ToLower(sfx)
|
||||||
|
// Trivial case: b suffix.
|
||||||
|
if sfx[0] == 'b' {
|
||||||
|
if len(sfx) > 1 { // no extra characters allowed after b.
|
||||||
|
goto badSuffix
|
||||||
|
}
|
||||||
|
return int64(size), nil
|
||||||
|
}
|
||||||
|
// A suffix from the map.
|
||||||
|
if mul, ok := uMap[sfx[0]]; ok {
|
||||||
size *= float64(mul)
|
size *= float64(mul)
|
||||||
|
} else {
|
||||||
|
goto badSuffix
|
||||||
|
}
|
||||||
|
|
||||||
|
// The suffix may have extra "b" or "ib" (e.g. KiB or MB).
|
||||||
|
switch {
|
||||||
|
case len(sfx) == 2 && sfx[1] != 'b':
|
||||||
|
goto badSuffix
|
||||||
|
case len(sfx) == 3 && sfx[1:] != "ib":
|
||||||
|
goto badSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
return int64(size), nil
|
return int64(size), nil
|
||||||
|
|
||||||
|
badSuffix:
|
||||||
|
return -1, fmt.Errorf("invalid suffix: '%s'", sfx)
|
||||||
}
|
}
|
||||||
|
9
vendor/github.com/google/go-containerregistry/cmd/crane/cmd/append.go
generated
vendored
9
vendor/github.com/google/go-containerregistry/cmd/crane/cmd/append.go
generated
vendored
@ -23,6 +23,7 @@ import (
|
|||||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/empty"
|
"github.com/google/go-containerregistry/pkg/v1/empty"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||||
|
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||||
specsv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
specsv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
@ -31,7 +32,7 @@ import (
|
|||||||
func NewCmdAppend(options *[]crane.Option) *cobra.Command {
|
func NewCmdAppend(options *[]crane.Option) *cobra.Command {
|
||||||
var baseRef, newTag, outFile string
|
var baseRef, newTag, outFile string
|
||||||
var newLayers []string
|
var newLayers []string
|
||||||
var annotate bool
|
var annotate, ociEmptyBase bool
|
||||||
|
|
||||||
appendCmd := &cobra.Command{
|
appendCmd := &cobra.Command{
|
||||||
Use: "append",
|
Use: "append",
|
||||||
@ -51,6 +52,10 @@ container image.`,
|
|||||||
if baseRef == "" {
|
if baseRef == "" {
|
||||||
logs.Warn.Printf("base unspecified, using empty image")
|
logs.Warn.Printf("base unspecified, using empty image")
|
||||||
base = empty.Image
|
base = empty.Image
|
||||||
|
if ociEmptyBase {
|
||||||
|
base = mutate.MediaType(base, types.OCIManifestSchema1)
|
||||||
|
base = mutate.ConfigMediaType(base, types.OCIConfigJSON)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
base, err = crane.Pull(baseRef, *options...)
|
base, err = crane.Pull(baseRef, *options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -108,7 +113,9 @@ container image.`,
|
|||||||
appendCmd.Flags().StringSliceVarP(&newLayers, "new_layer", "f", []string{}, "Path to tarball to append to image")
|
appendCmd.Flags().StringSliceVarP(&newLayers, "new_layer", "f", []string{}, "Path to tarball to append to image")
|
||||||
appendCmd.Flags().StringVarP(&outFile, "output", "o", "", "Path to new tarball of resulting image")
|
appendCmd.Flags().StringVarP(&outFile, "output", "o", "", "Path to new tarball of resulting image")
|
||||||
appendCmd.Flags().BoolVar(&annotate, "set-base-image-annotations", false, "If true, annotate the resulting image as being based on the base image")
|
appendCmd.Flags().BoolVar(&annotate, "set-base-image-annotations", false, "If true, annotate the resulting image as being based on the base image")
|
||||||
|
appendCmd.Flags().BoolVar(&ociEmptyBase, "oci-empty-base", false, "If true, empty base image will have OCI media types instead of Docker")
|
||||||
|
|
||||||
|
appendCmd.MarkFlagsMutuallyExclusive("oci-empty-base", "base")
|
||||||
appendCmd.MarkFlagRequired("new_tag")
|
appendCmd.MarkFlagRequired("new_tag")
|
||||||
appendCmd.MarkFlagRequired("new_layer")
|
appendCmd.MarkFlagRequired("new_layer")
|
||||||
return appendCmd
|
return appendCmd
|
||||||
|
38
vendor/github.com/google/go-containerregistry/cmd/crane/cmd/auth.go
generated
vendored
38
vendor/github.com/google/go-containerregistry/cmd/crane/cmd/auth.go
generated
vendored
@ -26,19 +26,20 @@ import (
|
|||||||
"github.com/docker/cli/cli/config"
|
"github.com/docker/cli/cli/config"
|
||||||
"github.com/docker/cli/cli/config/types"
|
"github.com/docker/cli/cli/config/types"
|
||||||
"github.com/google/go-containerregistry/pkg/authn"
|
"github.com/google/go-containerregistry/pkg/authn"
|
||||||
|
"github.com/google/go-containerregistry/pkg/crane"
|
||||||
"github.com/google/go-containerregistry/pkg/name"
|
"github.com/google/go-containerregistry/pkg/name"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCmdAuth creates a new cobra.Command for the auth subcommand.
|
// NewCmdAuth creates a new cobra.Command for the auth subcommand.
|
||||||
func NewCmdAuth(argv ...string) *cobra.Command {
|
func NewCmdAuth(options []crane.Option, argv ...string) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "auth",
|
Use: "auth",
|
||||||
Short: "Log in or access credentials",
|
Short: "Log in or access credentials",
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.NoArgs,
|
||||||
RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Usage() },
|
RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Usage() },
|
||||||
}
|
}
|
||||||
cmd.AddCommand(NewCmdAuthGet(argv...), NewCmdAuthLogin(argv...))
|
cmd.AddCommand(NewCmdAuthGet(options, argv...), NewCmdAuthLogin(argv...))
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,30 +63,41 @@ func toCreds(config *authn.AuthConfig) credentials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewCmdAuthGet creates a new `crane auth get` command.
|
// NewCmdAuthGet creates a new `crane auth get` command.
|
||||||
func NewCmdAuthGet(argv ...string) *cobra.Command {
|
func NewCmdAuthGet(options []crane.Option, argv ...string) *cobra.Command {
|
||||||
if len(argv) == 0 {
|
if len(argv) == 0 {
|
||||||
argv = []string{os.Args[0]}
|
argv = []string{os.Args[0]}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseCmd := strings.Join(argv, " ")
|
||||||
eg := fmt.Sprintf(` # Read configured credentials for reg.example.com
|
eg := fmt.Sprintf(` # Read configured credentials for reg.example.com
|
||||||
echo "reg.example.com" | %s get
|
$ echo "reg.example.com" | %s get
|
||||||
{"username":"AzureDiamond","password":"hunter2"}`, strings.Join(argv, " "))
|
{"username":"AzureDiamond","password":"hunter2"}
|
||||||
|
# or
|
||||||
|
$ %s get reg.example.com
|
||||||
|
{"username":"AzureDiamond","password":"hunter2"}`, baseCmd, baseCmd)
|
||||||
|
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "get",
|
Use: "get [REGISTRY_ADDR]",
|
||||||
Short: "Implements a credential helper",
|
Short: "Implements a credential helper",
|
||||||
Example: eg,
|
Example: eg,
|
||||||
Args: cobra.NoArgs,
|
Args: cobra.MaximumNArgs(1),
|
||||||
RunE: func(_ *cobra.Command, args []string) error {
|
RunE: func(_ *cobra.Command, args []string) error {
|
||||||
b, err := ioutil.ReadAll(os.Stdin)
|
registryAddr := ""
|
||||||
|
if len(args) == 1 {
|
||||||
|
registryAddr = args[0]
|
||||||
|
} else {
|
||||||
|
b, err := ioutil.ReadAll(os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
registryAddr = strings.TrimSpace(string(b))
|
||||||
|
}
|
||||||
|
|
||||||
|
reg, err := name.NewRegistry(registryAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
reg, err := name.NewRegistry(strings.TrimSpace(string(b)))
|
authorizer, err := crane.GetOptions(options...).Keychain.Resolve(reg)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
authorizer, err := authn.DefaultKeychain.Resolve(reg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
5
vendor/github.com/google/go-containerregistry/cmd/crane/cmd/root.go
generated
vendored
5
vendor/github.com/google/go-containerregistry/cmd/crane/cmd/root.go
generated
vendored
@ -70,12 +70,13 @@ func New(use, short string, options []crane.Option) *cobra.Command {
|
|||||||
|
|
||||||
options = append(options, crane.WithPlatform(platform.platform))
|
options = append(options, crane.WithPlatform(platform.platform))
|
||||||
|
|
||||||
transport := remote.DefaultTransport.Clone()
|
transport := remote.DefaultTransport.(*http.Transport).Clone()
|
||||||
transport.TLSClientConfig = &tls.Config{
|
transport.TLSClientConfig = &tls.Config{
|
||||||
InsecureSkipVerify: insecure, //nolint: gosec
|
InsecureSkipVerify: insecure, //nolint: gosec
|
||||||
}
|
}
|
||||||
|
|
||||||
var rt http.RoundTripper = transport
|
var rt http.RoundTripper = transport
|
||||||
|
|
||||||
// Add any http headers if they are set in the config file.
|
// Add any http headers if they are set in the config file.
|
||||||
cf, err := config.Load(os.Getenv("DOCKER_CONFIG"))
|
cf, err := config.Load(os.Getenv("DOCKER_CONFIG"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -93,7 +94,7 @@ func New(use, short string, options []crane.Option) *cobra.Command {
|
|||||||
|
|
||||||
commands := []*cobra.Command{
|
commands := []*cobra.Command{
|
||||||
NewCmdAppend(&options),
|
NewCmdAppend(&options),
|
||||||
NewCmdAuth("crane", "auth"),
|
NewCmdAuth(options, "crane", "auth"),
|
||||||
NewCmdBlob(&options),
|
NewCmdBlob(&options),
|
||||||
NewCmdCatalog(&options),
|
NewCmdCatalog(&options),
|
||||||
NewCmdConfig(&options),
|
NewCmdConfig(&options),
|
||||||
|
4
vendor/github.com/google/go-containerregistry/pkg/authn/README.md
generated
vendored
4
vendor/github.com/google/go-containerregistry/pkg/authn/README.md
generated
vendored
@ -110,8 +110,8 @@ For example:
|
|||||||
kc := authn.NewMultiKeychain(
|
kc := authn.NewMultiKeychain(
|
||||||
authn.DefaultKeychain,
|
authn.DefaultKeychain,
|
||||||
google.Keychain,
|
google.Keychain,
|
||||||
authn.NewFromHelper(ecr.ECRHelper{ClientFactory: api.DefaultClientFactory{}}),
|
authn.NewKeychainFromHelper(ecr.ECRHelper{ClientFactory: api.DefaultClientFactory{}}),
|
||||||
authn.NewFromHelper(acr.ACRCredHelper{}),
|
authn.NewKeychainFromHelper(acr.ACRCredHelper{}),
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
14
vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go
generated
vendored
14
vendor/github.com/google/go-containerregistry/pkg/authn/keychain.go
generated
vendored
@ -75,15 +75,11 @@ func (dk *defaultKeychain) Resolve(target Resource) (Authenticator, error) {
|
|||||||
foundDockerConfig := false
|
foundDockerConfig := false
|
||||||
home, err := homedir.Dir()
|
home, err := homedir.Dir()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if _, err := os.Stat(filepath.Join(home, ".docker/config.json")); err == nil {
|
foundDockerConfig = fileExists(filepath.Join(home, ".docker/config.json"))
|
||||||
foundDockerConfig = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// If $HOME/.docker/config.json isn't found, check $DOCKER_CONFIG (if set)
|
// If $HOME/.docker/config.json isn't found, check $DOCKER_CONFIG (if set)
|
||||||
if !foundDockerConfig && os.Getenv("DOCKER_CONFIG") != "" {
|
if !foundDockerConfig && os.Getenv("DOCKER_CONFIG") != "" {
|
||||||
if _, err := os.Stat(filepath.Join(os.Getenv("DOCKER_CONFIG"), "config.json")); err == nil {
|
foundDockerConfig = fileExists(filepath.Join(os.Getenv("DOCKER_CONFIG"), "config.json"))
|
||||||
foundDockerConfig = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// If either of those locations are found, load it using Docker's
|
// If either of those locations are found, load it using Docker's
|
||||||
// config.Load, which may fail if the config can't be parsed.
|
// config.Load, which may fail if the config can't be parsed.
|
||||||
@ -144,6 +140,12 @@ func (dk *defaultKeychain) Resolve(target Resource) (Authenticator, error) {
|
|||||||
}), nil
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fileExists returns true if the given path exists and is not a directory.
|
||||||
|
func fileExists(path string) bool {
|
||||||
|
fi, err := os.Stat(path)
|
||||||
|
return err == nil && !fi.IsDir()
|
||||||
|
}
|
||||||
|
|
||||||
// Helper is a subset of the Docker credential helper credentials.Helper
|
// Helper is a subset of the Docker credential helper credentials.Helper
|
||||||
// interface used by NewKeychainFromHelper.
|
// interface used by NewKeychainFromHelper.
|
||||||
//
|
//
|
||||||
|
28
vendor/github.com/google/go-containerregistry/pkg/crane/append.go
generated
vendored
28
vendor/github.com/google/go-containerregistry/pkg/crane/append.go
generated
vendored
@ -23,12 +23,10 @@ import (
|
|||||||
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
"github.com/google/go-containerregistry/pkg/v1/mutate"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/stream"
|
"github.com/google/go-containerregistry/pkg/v1/stream"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||||
|
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func isWindows(img v1.Image) (bool, error) {
|
func isWindows(img v1.Image) (bool, error) {
|
||||||
if img == nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
cfg, err := img.ConfigFile()
|
cfg, err := img.ConfigFile()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@ -42,14 +40,30 @@ func isWindows(img v1.Image) (bool, error) {
|
|||||||
// "windows"), the contents of the tarballs will be modified to be suitable for
|
// "windows"), the contents of the tarballs will be modified to be suitable for
|
||||||
// a Windows container image.`,
|
// a Windows container image.`,
|
||||||
func Append(base v1.Image, paths ...string) (v1.Image, error) {
|
func Append(base v1.Image, paths ...string) (v1.Image, error) {
|
||||||
|
if base == nil {
|
||||||
|
return nil, fmt.Errorf("invalid argument: base")
|
||||||
|
}
|
||||||
|
|
||||||
win, err := isWindows(base)
|
win, err := isWindows(base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("getting base image: %w", err)
|
return nil, fmt.Errorf("getting base image: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
baseMediaType, err := base.MediaType()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("getting base image media type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
layerType := types.DockerLayer
|
||||||
|
|
||||||
|
if baseMediaType == types.OCIManifestSchema1 {
|
||||||
|
layerType = types.OCILayer
|
||||||
|
}
|
||||||
|
|
||||||
layers := make([]v1.Layer, 0, len(paths))
|
layers := make([]v1.Layer, 0, len(paths))
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
layer, err := getLayer(path)
|
layer, err := getLayer(path, layerType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("reading layer %q: %w", path, err)
|
return nil, fmt.Errorf("reading layer %q: %w", path, err)
|
||||||
}
|
}
|
||||||
@ -67,16 +81,16 @@ func Append(base v1.Image, paths ...string) (v1.Image, error) {
|
|||||||
return mutate.AppendLayers(base, layers...)
|
return mutate.AppendLayers(base, layers...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLayer(path string) (v1.Layer, error) {
|
func getLayer(path string, layerType types.MediaType) (v1.Layer, error) {
|
||||||
f, err := streamFile(path)
|
f, err := streamFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if f != nil {
|
if f != nil {
|
||||||
return stream.NewLayer(f), nil
|
return stream.NewLayer(f, stream.WithMediaType(layerType)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return tarball.LayerFromFile(path)
|
return tarball.LayerFromFile(path, tarball.WithMediaType(layerType))
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're dealing with a named pipe, trying to open it multiple times will
|
// If we're dealing with a named pipe, trying to open it multiple times will
|
||||||
|
3
vendor/github.com/google/go-containerregistry/pkg/crane/options.go
generated
vendored
3
vendor/github.com/google/go-containerregistry/pkg/crane/options.go
generated
vendored
@ -29,6 +29,7 @@ type Options struct {
|
|||||||
Name []name.Option
|
Name []name.Option
|
||||||
Remote []remote.Option
|
Remote []remote.Option
|
||||||
Platform *v1.Platform
|
Platform *v1.Platform
|
||||||
|
Keychain authn.Keychain
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOptions exposes the underlying []remote.Option, []name.Option, and
|
// GetOptions exposes the underlying []remote.Option, []name.Option, and
|
||||||
@ -44,6 +45,7 @@ func makeOptions(opts ...Option) Options {
|
|||||||
Remote: []remote.Option{
|
Remote: []remote.Option{
|
||||||
remote.WithAuthFromKeychain(authn.DefaultKeychain),
|
remote.WithAuthFromKeychain(authn.DefaultKeychain),
|
||||||
},
|
},
|
||||||
|
Keychain: authn.DefaultKeychain,
|
||||||
}
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&opt)
|
o(&opt)
|
||||||
@ -86,6 +88,7 @@ func WithAuthFromKeychain(keys authn.Keychain) Option {
|
|||||||
return func(o *Options) {
|
return func(o *Options) {
|
||||||
// Replace the default keychain at position 0.
|
// Replace the default keychain at position 0.
|
||||||
o.Remote[0] = remote.WithAuthFromKeychain(keys)
|
o.Remote[0] = remote.WithAuthFromKeychain(keys)
|
||||||
|
o.Keychain = keys
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
6
vendor/github.com/google/go-containerregistry/pkg/name/errors.go
generated
vendored
6
vendor/github.com/google/go-containerregistry/pkg/name/errors.go
generated
vendored
@ -28,6 +28,12 @@ func (e *ErrBadName) Error() string {
|
|||||||
return e.info
|
return e.info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is reports whether target is an error of type ErrBadName
|
||||||
|
func (e *ErrBadName) Is(target error) bool {
|
||||||
|
var berr *ErrBadName
|
||||||
|
return errors.As(target, &berr)
|
||||||
|
}
|
||||||
|
|
||||||
// newErrBadName returns a ErrBadName which returns the given formatted string from Error().
|
// newErrBadName returns a ErrBadName which returns the given formatted string from Error().
|
||||||
func newErrBadName(fmtStr string, args ...interface{}) *ErrBadName {
|
func newErrBadName(fmtStr string, args ...interface{}) *ErrBadName {
|
||||||
return &ErrBadName{fmt.Sprintf(fmtStr, args...)}
|
return &ErrBadName{fmt.Sprintf(fmtStr, args...)}
|
||||||
|
38
vendor/github.com/google/go-containerregistry/pkg/registry/blobs.go
generated
vendored
38
vendor/github.com/google/go-containerregistry/pkg/registry/blobs.go
generated
vendored
@ -76,6 +76,13 @@ type blobPutHandler interface {
|
|||||||
Put(ctx context.Context, repo string, h v1.Hash, rc io.ReadCloser) error
|
Put(ctx context.Context, repo string, h v1.Hash, rc io.ReadCloser) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// blobDeleteHandler is an extension interface representing a blob storage
|
||||||
|
// backend that can delete blob contents.
|
||||||
|
type blobDeleteHandler interface {
|
||||||
|
// Delete the blob contents.
|
||||||
|
Delete(ctx context.Context, repo string, h v1.Hash) error
|
||||||
|
}
|
||||||
|
|
||||||
// redirectError represents a signal that the blob handler doesn't have the blob
|
// redirectError represents a signal that the blob handler doesn't have the blob
|
||||||
// contents, but that those contents are at another location which registry
|
// contents, but that those contents are at another location which registry
|
||||||
// clients should redirect to.
|
// clients should redirect to.
|
||||||
@ -129,6 +136,17 @@ func (m *memHandler) Put(_ context.Context, _ string, h v1.Hash, rc io.ReadClose
|
|||||||
m.m[h.String()] = all
|
m.m[h.String()] = all
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
func (m *memHandler) Delete(_ context.Context, _ string, h v1.Hash) error {
|
||||||
|
m.lock.Lock()
|
||||||
|
defer m.lock.Unlock()
|
||||||
|
|
||||||
|
if _, found := m.m[h.String()]; !found {
|
||||||
|
return errNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(m.m, h.String())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// blobs
|
// blobs
|
||||||
type blobs struct {
|
type blobs struct {
|
||||||
@ -435,6 +453,26 @@ func (b *blobs) handle(resp http.ResponseWriter, req *http.Request) *regError {
|
|||||||
resp.WriteHeader(http.StatusCreated)
|
resp.WriteHeader(http.StatusCreated)
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
|
case http.MethodDelete:
|
||||||
|
bdh, ok := b.blobHandler.(blobDeleteHandler)
|
||||||
|
if !ok {
|
||||||
|
return regErrUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
h, err := v1.NewHash(target)
|
||||||
|
if err != nil {
|
||||||
|
return ®Error{
|
||||||
|
Status: http.StatusBadRequest,
|
||||||
|
Code: "NAME_INVALID",
|
||||||
|
Message: "invalid digest",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := bdh.Delete(req.Context(), repo, h); err != nil {
|
||||||
|
return regErrInternal(err)
|
||||||
|
}
|
||||||
|
resp.WriteHeader(http.StatusAccepted)
|
||||||
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return ®Error{
|
return ®Error{
|
||||||
Status: http.StatusBadRequest,
|
Status: http.StatusBadRequest,
|
||||||
|
36
vendor/github.com/google/go-containerregistry/pkg/registry/manifest.go
generated
vendored
36
vendor/github.com/google/go-containerregistry/pkg/registry/manifest.go
generated
vendored
@ -237,12 +237,6 @@ func (m *manifests) handleTags(resp http.ResponseWriter, req *http.Request) *reg
|
|||||||
elem := strings.Split(req.URL.Path, "/")
|
elem := strings.Split(req.URL.Path, "/")
|
||||||
elem = elem[1:]
|
elem = elem[1:]
|
||||||
repo := strings.Join(elem[1:len(elem)-2], "/")
|
repo := strings.Join(elem[1:len(elem)-2], "/")
|
||||||
query := req.URL.Query()
|
|
||||||
nStr := query.Get("n")
|
|
||||||
n := 1000
|
|
||||||
if nStr != "" {
|
|
||||||
n, _ = strconv.Atoi(nStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Method == "GET" {
|
if req.Method == "GET" {
|
||||||
m.lock.Lock()
|
m.lock.Lock()
|
||||||
@ -258,19 +252,37 @@ func (m *manifests) handleTags(resp http.ResponseWriter, req *http.Request) *reg
|
|||||||
}
|
}
|
||||||
|
|
||||||
var tags []string
|
var tags []string
|
||||||
countTags := 0
|
|
||||||
// TODO: implement pagination https://github.com/opencontainers/distribution-spec/blob/b505e9cc53ec499edbd9c1be32298388921bb705/detail.md#tags-paginated
|
|
||||||
for tag := range c {
|
for tag := range c {
|
||||||
if countTags >= n {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
countTags++
|
|
||||||
if !strings.Contains(tag, "sha256:") {
|
if !strings.Contains(tag, "sha256:") {
|
||||||
tags = append(tags, tag)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sort.Strings(tags)
|
sort.Strings(tags)
|
||||||
|
|
||||||
|
// https://github.com/opencontainers/distribution-spec/blob/b505e9cc53ec499edbd9c1be32298388921bb705/detail.md#tags-paginated
|
||||||
|
// Offset using last query parameter.
|
||||||
|
if last := req.URL.Query().Get("last"); last != "" {
|
||||||
|
for i, t := range tags {
|
||||||
|
if t > last {
|
||||||
|
tags = tags[i:]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit using n query parameter.
|
||||||
|
if ns := req.URL.Query().Get("n"); ns != "" {
|
||||||
|
if n, err := strconv.Atoi(ns); err != nil {
|
||||||
|
return ®Error{
|
||||||
|
Status: http.StatusBadRequest,
|
||||||
|
Code: "BAD_REQUEST",
|
||||||
|
Message: fmt.Sprintf("parsing n: %v", err),
|
||||||
|
}
|
||||||
|
} else if n < len(tags) {
|
||||||
|
tags = tags[:n]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tagsToList := listTags{
|
tagsToList := listTags{
|
||||||
Name: repo,
|
Name: repo,
|
||||||
Tags: tags,
|
Tags: tags,
|
||||||
|
9
vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go
generated
vendored
9
vendor/github.com/google/go-containerregistry/pkg/v1/mutate/mutate.go
generated
vendored
@ -244,6 +244,7 @@ func extract(img v1.Image, w io.Writer) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("retrieving image layers: %w", err)
|
return fmt.Errorf("retrieving image layers: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// we iterate through the layers in reverse order because it makes handling
|
// we iterate through the layers in reverse order because it makes handling
|
||||||
// whiteout layers more efficient, since we can just keep track of the removed
|
// whiteout layers more efficient, since we can just keep track of the removed
|
||||||
// files as we see .wh. layers and ignore those in previous layers.
|
// files as we see .wh. layers and ignore those in previous layers.
|
||||||
@ -267,6 +268,10 @@ func extract(img v1.Image, w io.Writer) error {
|
|||||||
// Some tools prepend everything with "./", so if we don't Clean the
|
// Some tools prepend everything with "./", so if we don't Clean the
|
||||||
// name, we may have duplicate entries, which angers tar-split.
|
// name, we may have duplicate entries, which angers tar-split.
|
||||||
header.Name = filepath.Clean(header.Name)
|
header.Name = filepath.Clean(header.Name)
|
||||||
|
// force PAX format to remove Name/Linkname length limit of 100 characters
|
||||||
|
// required by USTAR and to not depend on internal tar package guess which
|
||||||
|
// prefers USTAR over PAX
|
||||||
|
header.Format = tar.FormatPAX
|
||||||
|
|
||||||
basename := filepath.Base(header.Name)
|
basename := filepath.Base(header.Name)
|
||||||
dirname := filepath.Dir(header.Name)
|
dirname := filepath.Dir(header.Name)
|
||||||
@ -297,7 +302,9 @@ func extract(img v1.Image, w io.Writer) error {
|
|||||||
// any entries with a matching (or child) name
|
// any entries with a matching (or child) name
|
||||||
fileMap[name] = tombstone || !(header.Typeflag == tar.TypeDir)
|
fileMap[name] = tombstone || !(header.Typeflag == tar.TypeDir)
|
||||||
if !tombstone {
|
if !tombstone {
|
||||||
tarWriter.WriteHeader(header)
|
if err := tarWriter.WriteHeader(header); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if header.Size > 0 {
|
if header.Size > 0 {
|
||||||
if _, err := io.CopyN(tarWriter, tarReader, header.Size); err != nil {
|
if _, err := io.CopyN(tarWriter, tarReader, header.Size); err != nil {
|
||||||
return err
|
return err
|
||||||
|
4
vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go
generated
vendored
4
vendor/github.com/google/go-containerregistry/pkg/v1/remote/options.go
generated
vendored
@ -59,7 +59,7 @@ type Backoff = retry.Backoff
|
|||||||
var defaultRetryPredicate retry.Predicate = func(err error) bool {
|
var defaultRetryPredicate retry.Predicate = func(err error) bool {
|
||||||
// Various failure modes here, as we're often reading from and writing to
|
// Various failure modes here, as we're often reading from and writing to
|
||||||
// the network.
|
// the network.
|
||||||
if retry.IsTemporary(err) || errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) || errors.Is(err, syscall.EPIPE) {
|
if retry.IsTemporary(err) || errors.Is(err, io.ErrUnexpectedEOF) || errors.Is(err, io.EOF) || errors.Is(err, syscall.EPIPE) || errors.Is(err, syscall.ECONNRESET) {
|
||||||
logs.Warn.Printf("retrying %v", err)
|
logs.Warn.Printf("retrying %v", err)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -84,7 +84,7 @@ const (
|
|||||||
|
|
||||||
// DefaultTransport is based on http.DefaultTransport with modifications
|
// DefaultTransport is based on http.DefaultTransport with modifications
|
||||||
// documented inline below.
|
// documented inline below.
|
||||||
var DefaultTransport = &http.Transport{
|
var DefaultTransport http.RoundTripper = &http.Transport{
|
||||||
Proxy: http.ProxyFromEnvironment,
|
Proxy: http.ProxyFromEnvironment,
|
||||||
DialContext: (&net.Dialer{
|
DialContext: (&net.Dialer{
|
||||||
// By default we wrap the transport in retries, so reduce the
|
// By default we wrap the transport in retries, so reduce the
|
||||||
|
15
vendor/github.com/google/go-containerregistry/pkg/v1/stream/layer.go
generated
vendored
15
vendor/github.com/google/go-containerregistry/pkg/v1/stream/layer.go
generated
vendored
@ -48,6 +48,7 @@ type Layer struct {
|
|||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
digest, diffID *v1.Hash
|
digest, diffID *v1.Hash
|
||||||
size int64
|
size int64
|
||||||
|
mediaType types.MediaType
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ v1.Layer = (*Layer)(nil)
|
var _ v1.Layer = (*Layer)(nil)
|
||||||
@ -62,11 +63,21 @@ func WithCompressionLevel(level int) LayerOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithMediaType is a functional option for overriding the layer's media type.
|
||||||
|
func WithMediaType(mt types.MediaType) LayerOption {
|
||||||
|
return func(l *Layer) {
|
||||||
|
l.mediaType = mt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewLayer creates a Layer from an io.ReadCloser.
|
// NewLayer creates a Layer from an io.ReadCloser.
|
||||||
func NewLayer(rc io.ReadCloser, opts ...LayerOption) *Layer {
|
func NewLayer(rc io.ReadCloser, opts ...LayerOption) *Layer {
|
||||||
layer := &Layer{
|
layer := &Layer{
|
||||||
blob: rc,
|
blob: rc,
|
||||||
compression: gzip.BestSpeed,
|
compression: gzip.BestSpeed,
|
||||||
|
// We use DockerLayer for now as uncompressed layers
|
||||||
|
// are unimplemented
|
||||||
|
mediaType: types.DockerLayer,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
@ -108,9 +119,7 @@ func (l *Layer) Size() (int64, error) {
|
|||||||
|
|
||||||
// MediaType implements v1.Layer
|
// MediaType implements v1.Layer
|
||||||
func (l *Layer) MediaType() (types.MediaType, error) {
|
func (l *Layer) MediaType() (types.MediaType, error) {
|
||||||
// We return DockerLayer for now as uncompressed layers
|
return l.mediaType, nil
|
||||||
// are unimplemented
|
|
||||||
return types.DockerLayer, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uncompressed implements v1.Layer.
|
// Uncompressed implements v1.Layer.
|
||||||
|
9
vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go
generated
vendored
9
vendor/github.com/opencontainers/image-spec/specs-go/v1/annotations.go
generated
vendored
@ -59,4 +59,13 @@ const (
|
|||||||
|
|
||||||
// AnnotationBaseImageName is the annotation key for the image reference of the image's base image.
|
// AnnotationBaseImageName is the annotation key for the image reference of the image's base image.
|
||||||
AnnotationBaseImageName = "org.opencontainers.image.base.name"
|
AnnotationBaseImageName = "org.opencontainers.image.base.name"
|
||||||
|
|
||||||
|
// AnnotationArtifactCreated is the annotation key for the date and time on which the artifact was built, conforming to RFC 3339.
|
||||||
|
AnnotationArtifactCreated = "org.opencontainers.artifact.created"
|
||||||
|
|
||||||
|
// AnnotationArtifactDescription is the annotation key for the human readable description for the artifact.
|
||||||
|
AnnotationArtifactDescription = "org.opencontainers.artifact.description"
|
||||||
|
|
||||||
|
// AnnotationReferrersFiltersApplied is the annotation key for the comma separated list of filters applied by the registry in the referrers listing.
|
||||||
|
AnnotationReferrersFiltersApplied = "org.opencontainers.referrers.filtersApplied"
|
||||||
)
|
)
|
||||||
|
34
vendor/github.com/opencontainers/image-spec/specs-go/v1/artifact.go
generated
vendored
Normal file
34
vendor/github.com/opencontainers/image-spec/specs-go/v1/artifact.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2022 The Linux Foundation
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package v1
|
||||||
|
|
||||||
|
// Artifact describes an artifact manifest.
|
||||||
|
// This structure provides `application/vnd.oci.artifact.manifest.v1+json` mediatype when marshalled to JSON.
|
||||||
|
type Artifact struct {
|
||||||
|
// MediaType is the media type of the object this schema refers to.
|
||||||
|
MediaType string `json:"mediaType"`
|
||||||
|
|
||||||
|
// ArtifactType is the IANA media type of the artifact this schema refers to.
|
||||||
|
ArtifactType string `json:"artifactType"`
|
||||||
|
|
||||||
|
// Blobs is a collection of blobs referenced by this manifest.
|
||||||
|
Blobs []Descriptor `json:"blobs,omitempty"`
|
||||||
|
|
||||||
|
// Subject (reference) is an optional link from the artifact to another manifest forming an association between the artifact and the other manifest.
|
||||||
|
Subject *Descriptor `json:"subject,omitempty"`
|
||||||
|
|
||||||
|
// Annotations contains arbitrary metadata for the artifact manifest.
|
||||||
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
}
|
10
vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go
generated
vendored
10
vendor/github.com/opencontainers/image-spec/specs-go/v1/descriptor.go
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2016 The Linux Foundation
|
// Copyright 2016-2022 The Linux Foundation
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -35,10 +35,18 @@ type Descriptor struct {
|
|||||||
// Annotations contains arbitrary metadata relating to the targeted content.
|
// Annotations contains arbitrary metadata relating to the targeted content.
|
||||||
Annotations map[string]string `json:"annotations,omitempty"`
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
|
|
||||||
|
// Data is an embedding of the targeted content. This is encoded as a base64
|
||||||
|
// string when marshalled to JSON (automatically, by encoding/json). If
|
||||||
|
// present, Data can be used directly to avoid fetching the targeted content.
|
||||||
|
Data []byte `json:"data,omitempty"`
|
||||||
|
|
||||||
// Platform describes the platform which the image in the manifest runs on.
|
// Platform describes the platform which the image in the manifest runs on.
|
||||||
//
|
//
|
||||||
// This should only be used when referring to a manifest.
|
// This should only be used when referring to a manifest.
|
||||||
Platform *Platform `json:"platform,omitempty"`
|
Platform *Platform `json:"platform,omitempty"`
|
||||||
|
|
||||||
|
// ArtifactType is the IANA media type of this artifact.
|
||||||
|
ArtifactType string `json:"artifactType,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Platform describes the platform which the image in the manifest runs on.
|
// Platform describes the platform which the image in the manifest runs on.
|
||||||
|
5
vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go
generated
vendored
5
vendor/github.com/opencontainers/image-spec/specs-go/v1/manifest.go
generated
vendored
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2016 The Linux Foundation
|
// Copyright 2016-2022 The Linux Foundation
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@ -30,6 +30,9 @@ type Manifest struct {
|
|||||||
// Layers is an indexed list of layers referenced by the manifest.
|
// Layers is an indexed list of layers referenced by the manifest.
|
||||||
Layers []Descriptor `json:"layers"`
|
Layers []Descriptor `json:"layers"`
|
||||||
|
|
||||||
|
// Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.
|
||||||
|
Subject *Descriptor `json:"subject,omitempty"`
|
||||||
|
|
||||||
// Annotations contains arbitrary metadata for the image manifest.
|
// Annotations contains arbitrary metadata for the image manifest.
|
||||||
Annotations map[string]string `json:"annotations,omitempty"`
|
Annotations map[string]string `json:"annotations,omitempty"`
|
||||||
}
|
}
|
||||||
|
3
vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go
generated
vendored
3
vendor/github.com/opencontainers/image-spec/specs-go/v1/mediatype.go
generated
vendored
@ -54,4 +54,7 @@ const (
|
|||||||
|
|
||||||
// MediaTypeImageConfig specifies the media type for the image configuration.
|
// MediaTypeImageConfig specifies the media type for the image configuration.
|
||||||
MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"
|
MediaTypeImageConfig = "application/vnd.oci.image.config.v1+json"
|
||||||
|
|
||||||
|
// MediaTypeArtifactManifest specifies the media type for a content descriptor.
|
||||||
|
MediaTypeArtifactManifest = "application/vnd.oci.artifact.manifest.v1+json"
|
||||||
)
|
)
|
||||||
|
6
vendor/github.com/opencontainers/image-spec/specs-go/version.go
generated
vendored
6
vendor/github.com/opencontainers/image-spec/specs-go/version.go
generated
vendored
@ -20,12 +20,12 @@ const (
|
|||||||
// VersionMajor is for an API incompatible changes
|
// VersionMajor is for an API incompatible changes
|
||||||
VersionMajor = 1
|
VersionMajor = 1
|
||||||
// VersionMinor is for functionality in a backwards-compatible manner
|
// VersionMinor is for functionality in a backwards-compatible manner
|
||||||
VersionMinor = 0
|
VersionMinor = 1
|
||||||
// VersionPatch is for backwards-compatible bug fixes
|
// VersionPatch is for backwards-compatible bug fixes
|
||||||
VersionPatch = 2
|
VersionPatch = 0
|
||||||
|
|
||||||
// VersionDev indicates development branch. Releases will be empty string.
|
// VersionDev indicates development branch. Releases will be empty string.
|
||||||
VersionDev = "-dev"
|
VersionDev = "-rc2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version is the specification version that the package types support.
|
// Version is the specification version that the package types support.
|
||||||
|
658
vendor/golang.org/x/tools/cmd/stringer/stringer.go
generated
vendored
Normal file
658
vendor/golang.org/x/tools/cmd/stringer/stringer.go
generated
vendored
Normal file
@ -0,0 +1,658 @@
|
|||||||
|
// 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"
|
||||||
|
"io/ioutil"
|
||||||
|
"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 := ioutil.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) + ")"
|
||||||
|
}
|
||||||
|
`
|
22
vendor/modules.txt
vendored
22
vendor/modules.txt
vendored
@ -37,9 +37,10 @@ github.com/Azure/go-autorest/tracing
|
|||||||
## explicit; go 1.16
|
## explicit; go 1.16
|
||||||
github.com/BurntSushi/toml
|
github.com/BurntSushi/toml
|
||||||
github.com/BurntSushi/toml/internal
|
github.com/BurntSushi/toml/internal
|
||||||
# github.com/Microsoft/go-winio v0.5.2
|
# github.com/Microsoft/go-winio v0.6.0
|
||||||
## explicit; go 1.13
|
## explicit; go 1.17
|
||||||
github.com/Microsoft/go-winio
|
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/guid
|
||||||
# github.com/alessio/shellescape v1.4.1
|
# github.com/alessio/shellescape v1.4.1
|
||||||
## explicit; go 1.14
|
## explicit; go 1.14
|
||||||
@ -162,7 +163,7 @@ github.com/cpuguy83/go-md2man/v2/md2man
|
|||||||
# github.com/dimchansky/utfbom v1.1.1
|
# github.com/dimchansky/utfbom v1.1.1
|
||||||
## explicit
|
## explicit
|
||||||
github.com/dimchansky/utfbom
|
github.com/dimchansky/utfbom
|
||||||
# github.com/docker/cli v20.10.17+incompatible
|
# github.com/docker/cli v20.10.20+incompatible
|
||||||
## explicit
|
## explicit
|
||||||
github.com/docker/cli/cli/config
|
github.com/docker/cli/cli/config
|
||||||
github.com/docker/cli/cli/config/configfile
|
github.com/docker/cli/cli/config/configfile
|
||||||
@ -194,8 +195,8 @@ github.com/docker/docker/api/types/volume
|
|||||||
github.com/docker/docker/client
|
github.com/docker/docker/client
|
||||||
github.com/docker/docker/errdefs
|
github.com/docker/docker/errdefs
|
||||||
github.com/docker/docker/pkg/homedir
|
github.com/docker/docker/pkg/homedir
|
||||||
# github.com/docker/docker-credential-helpers v0.6.4
|
# github.com/docker/docker-credential-helpers v0.7.0
|
||||||
## explicit; go 1.13
|
## explicit; go 1.18
|
||||||
github.com/docker/docker-credential-helpers/client
|
github.com/docker/docker-credential-helpers/client
|
||||||
github.com/docker/docker-credential-helpers/credentials
|
github.com/docker/docker-credential-helpers/credentials
|
||||||
# github.com/docker/go-connections v0.4.0
|
# github.com/docker/go-connections v0.4.0
|
||||||
@ -203,7 +204,7 @@ github.com/docker/docker-credential-helpers/credentials
|
|||||||
github.com/docker/go-connections/nat
|
github.com/docker/go-connections/nat
|
||||||
github.com/docker/go-connections/sockets
|
github.com/docker/go-connections/sockets
|
||||||
github.com/docker/go-connections/tlsconfig
|
github.com/docker/go-connections/tlsconfig
|
||||||
# github.com/docker/go-units v0.4.0
|
# github.com/docker/go-units v0.5.0
|
||||||
## explicit
|
## explicit
|
||||||
github.com/docker/go-units
|
github.com/docker/go-units
|
||||||
# github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936
|
# github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936
|
||||||
@ -280,7 +281,7 @@ github.com/google/go-cmp/cmp/internal/diff
|
|||||||
github.com/google/go-cmp/cmp/internal/flags
|
github.com/google/go-cmp/cmp/internal/flags
|
||||||
github.com/google/go-cmp/cmp/internal/function
|
github.com/google/go-cmp/cmp/internal/function
|
||||||
github.com/google/go-cmp/cmp/internal/value
|
github.com/google/go-cmp/cmp/internal/value
|
||||||
# github.com/google/go-containerregistry v0.11.0
|
# github.com/google/go-containerregistry v0.12.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
github.com/google/go-containerregistry/cmd/crane/cmd
|
github.com/google/go-containerregistry/cmd/crane/cmd
|
||||||
github.com/google/go-containerregistry/internal/and
|
github.com/google/go-containerregistry/internal/and
|
||||||
@ -387,8 +388,8 @@ github.com/oklog/ulid
|
|||||||
# github.com/opencontainers/go-digest v1.0.0
|
# github.com/opencontainers/go-digest v1.0.0
|
||||||
## explicit; go 1.13
|
## explicit; go 1.13
|
||||||
github.com/opencontainers/go-digest
|
github.com/opencontainers/go-digest
|
||||||
# github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198
|
# github.com/opencontainers/image-spec v1.1.0-rc2
|
||||||
## explicit; go 1.11
|
## explicit; go 1.17
|
||||||
github.com/opencontainers/image-spec/specs-go
|
github.com/opencontainers/image-spec/specs-go
|
||||||
github.com/opencontainers/image-spec/specs-go/v1
|
github.com/opencontainers/image-spec/specs-go/v1
|
||||||
# github.com/pelletier/go-toml v1.9.5
|
# github.com/pelletier/go-toml v1.9.5
|
||||||
@ -509,7 +510,7 @@ golang.org/x/net/internal/socks
|
|||||||
golang.org/x/net/internal/timeseries
|
golang.org/x/net/internal/timeseries
|
||||||
golang.org/x/net/proxy
|
golang.org/x/net/proxy
|
||||||
golang.org/x/net/trace
|
golang.org/x/net/trace
|
||||||
# golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783
|
# golang.org/x/oauth2 v0.1.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
golang.org/x/oauth2
|
golang.org/x/oauth2
|
||||||
golang.org/x/oauth2/authhandler
|
golang.org/x/oauth2/authhandler
|
||||||
@ -542,6 +543,7 @@ golang.org/x/text/unicode/bidi
|
|||||||
golang.org/x/text/unicode/norm
|
golang.org/x/text/unicode/norm
|
||||||
# golang.org/x/tools v0.2.0
|
# golang.org/x/tools v0.2.0
|
||||||
## explicit; go 1.18
|
## explicit; go 1.18
|
||||||
|
golang.org/x/tools/cmd/stringer
|
||||||
golang.org/x/tools/go/gcexportdata
|
golang.org/x/tools/go/gcexportdata
|
||||||
golang.org/x/tools/go/internal/gcimporter
|
golang.org/x/tools/go/internal/gcimporter
|
||||||
golang.org/x/tools/go/internal/packagesdriver
|
golang.org/x/tools/go/internal/packagesdriver
|
||||||
|
Reference in New Issue
Block a user