1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -2,3 +2,4 @@ bin
 | 
			
		||||
dist
 | 
			
		||||
_output
 | 
			
		||||
.idea
 | 
			
		||||
/vendor/
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,4 @@
 | 
			
		||||
run:
 | 
			
		||||
    skip-dirs:
 | 
			
		||||
        - vendor
 | 
			
		||||
 | 
			
		||||
    timeout: 2m
 | 
			
		||||
 | 
			
		||||
linters-settings:
 | 
			
		||||
 
 | 
			
		||||
@@ -41,8 +41,6 @@ $ protoc --go_out=import_path=dexapi:. api.proto
 | 
			
		||||
 | 
			
		||||
Client programs can then be written using the generated code. A Go client which uses dex's internally generated code might look like the following:
 | 
			
		||||
 | 
			
		||||
__NOTE:__ Because dex has the `google.golang.org/grpc` package in its `vendor` directory, gRPC code in `github.com/dexidp/dex/api` refers to the vendored copy, not copies in a developers GOPATH. Clients must either regenerate the gRPC Go code or vendor dex and remove its `vendor` directory to run this program.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
## Go modules
 | 
			
		||||
 | 
			
		||||
Dex uses [Go modules][go-modules] to manage its [`vendor` directory][go-vendor]. Go 1.11 or higher is recommended. While Go 1.12 is expected to finalize the Go modules feature, with Go 1.11 you should [activate the Go modules feature][go-modules-activate] before interacting with Go modules.
 | 
			
		||||
Dex uses [Go modules][go-modules] to manage its dependencies. Go 1.11 or higher is recommended. While Go 1.12 is expected to finalize the Go modules feature, with Go 1.11 you should [activate the Go modules feature][go-modules-activate] before interacting with Go modules.
 | 
			
		||||
 | 
			
		||||
Here is one way to activate the Go modules feature with Go 1.11.
 | 
			
		||||
 | 
			
		||||
@@ -21,22 +21,9 @@ To add a new dependency to dex or update an existing one:
 | 
			
		||||
  * Run `go mod tidy -v`. This is a good option if you do not wish to immediately pin to a specific Semantic Version or commit.
 | 
			
		||||
  * Run, for example, `go get <package-name>@<commit-hash>`. This is a good option when you want to immediately pin to a specific Semantic Version or commit.
 | 
			
		||||
  * Manually update `go.mod`.  If one of the two options above doesn't suit you, do this -- but very carefully.
 | 
			
		||||
3. Create a git commit to reflect your code (not vendor) changes. See below for tips on composing commits.
 | 
			
		||||
4. Once `go.mod` describes the desired state and you've create a commit for that change, run `make revendor` to update `go.mod`, `go.sum` and `vendor`. This calls `go mod tidy -v`, `go mod vendor -v` and `go mod verify`.
 | 
			
		||||
5. Create a git commit to reflect the changes made by `make revendor`. Again, see below for tips on composing commits.
 | 
			
		||||
3. Create a git commit to reflect your code changes.
 | 
			
		||||
 | 
			
		||||
## Composing commits
 | 
			
		||||
 | 
			
		||||
When composing commits make sure that updates to `vendor` are in a separate commit from the main changes. GitHub's UI makes commits with a large number of changes unreviewable.
 | 
			
		||||
 | 
			
		||||
Commit histories should look like the following:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
connector/ldap: add a LDAP connector
 | 
			
		||||
vendor: revendor
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[go-modules]: https://github.com/golang/go/wiki/Modules
 | 
			
		||||
[go-modules-activate]: https://github.com/golang/go/wiki/Modules#how-to-install-and-activate-module-support
 | 
			
		||||
[go-vendor]: https://golang.org/cmd/go/#hdr-Vendor_Directories
 | 
			
		||||
[module-aware-go-get]: https://tip.golang.org/cmd/go/#hdr-Module_aware_go_get
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								Makefile
									
									
									
									
									
								
							@@ -35,12 +35,6 @@ bin/grpc-client:
 | 
			
		||||
release-binary:
 | 
			
		||||
	@go build -o /go/bin/dex -v -ldflags $(LD_FLAGS) $(REPO_PATH)/cmd/dex
 | 
			
		||||
 | 
			
		||||
.PHONY: revendor
 | 
			
		||||
revendor:
 | 
			
		||||
	@go mod tidy -v
 | 
			
		||||
	@go mod vendor -v
 | 
			
		||||
	@go mod verify
 | 
			
		||||
 | 
			
		||||
test: bin/test/kube-apiserver bin/test/etcd
 | 
			
		||||
	@go test -v ./...
 | 
			
		||||
 | 
			
		||||
@@ -91,7 +85,7 @@ bin/protoc: scripts/get-protoc
 | 
			
		||||
	@./scripts/get-protoc bin/protoc
 | 
			
		||||
 | 
			
		||||
bin/protoc-gen-go:
 | 
			
		||||
	@go install -v $(REPO_PATH)/vendor/github.com/golang/protobuf/protoc-gen-go
 | 
			
		||||
	@go install -v github.com/golang/protobuf/protoc-gen-go
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	@rm -rf bin/
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor.go
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								vendor.go
									
									
									
									
									
								
							@@ -1,14 +0,0 @@
 | 
			
		||||
// +build vendor
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
// This file exists to trick "go mod vendor" to include "main" packages.
 | 
			
		||||
// It is not expected to build, the build tag above is only to prevent this
 | 
			
		||||
// file from being included in builds.
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
        _ "github.com/golang/protobuf/protoc-gen-go"
 | 
			
		||||
        _ "golang.org/x/lint/golint"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {}
 | 
			
		||||
							
								
								
									
										202
									
								
								vendor/cloud.google.com/go/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										202
									
								
								vendor/cloud.google.com/go/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,202 +0,0 @@
 | 
			
		||||
 | 
			
		||||
                                 Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
   1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
   END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
   APPENDIX: How to apply the Apache License to your work.
 | 
			
		||||
 | 
			
		||||
      To apply the Apache License to your work, attach the following
 | 
			
		||||
      boilerplate notice, with the fields enclosed by brackets "[]"
 | 
			
		||||
      replaced with your own identifying information. (Don't include
 | 
			
		||||
      the brackets!)  The text should be enclosed in the appropriate
 | 
			
		||||
      comment syntax for the file format. We also recommend that a
 | 
			
		||||
      file or class name and description of purpose be included on the
 | 
			
		||||
      same "printed page" as the copyright notice for easier
 | 
			
		||||
      identification within third-party archives.
 | 
			
		||||
 | 
			
		||||
   Copyright [yyyy] [name of copyright owner]
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
							
								
								
									
										513
									
								
								vendor/cloud.google.com/go/compute/metadata/metadata.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										513
									
								
								vendor/cloud.google.com/go/compute/metadata/metadata.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,513 +0,0 @@
 | 
			
		||||
// Copyright 2014 Google LLC
 | 
			
		||||
//
 | 
			
		||||
// 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 metadata provides access to Google Compute Engine (GCE)
 | 
			
		||||
// metadata and API service accounts.
 | 
			
		||||
//
 | 
			
		||||
// This package is a wrapper around the GCE metadata service,
 | 
			
		||||
// as documented at https://developers.google.com/compute/docs/metadata.
 | 
			
		||||
package metadata // import "cloud.google.com/go/compute/metadata"
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// metadataIP is the documented metadata server IP address.
 | 
			
		||||
	metadataIP = "169.254.169.254"
 | 
			
		||||
 | 
			
		||||
	// metadataHostEnv is the environment variable specifying the
 | 
			
		||||
	// GCE metadata hostname.  If empty, the default value of
 | 
			
		||||
	// metadataIP ("169.254.169.254") is used instead.
 | 
			
		||||
	// This is variable name is not defined by any spec, as far as
 | 
			
		||||
	// I know; it was made up for the Go package.
 | 
			
		||||
	metadataHostEnv = "GCE_METADATA_HOST"
 | 
			
		||||
 | 
			
		||||
	userAgent = "gcloud-golang/0.1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type cachedValue struct {
 | 
			
		||||
	k    string
 | 
			
		||||
	trim bool
 | 
			
		||||
	mu   sync.Mutex
 | 
			
		||||
	v    string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	projID  = &cachedValue{k: "project/project-id", trim: true}
 | 
			
		||||
	projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
 | 
			
		||||
	instID  = &cachedValue{k: "instance/id", trim: true}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	defaultClient = &Client{hc: &http.Client{
 | 
			
		||||
		Transport: &http.Transport{
 | 
			
		||||
			Dial: (&net.Dialer{
 | 
			
		||||
				Timeout:   2 * time.Second,
 | 
			
		||||
				KeepAlive: 30 * time.Second,
 | 
			
		||||
			}).Dial,
 | 
			
		||||
			ResponseHeaderTimeout: 2 * time.Second,
 | 
			
		||||
		},
 | 
			
		||||
	}}
 | 
			
		||||
	subscribeClient = &Client{hc: &http.Client{
 | 
			
		||||
		Transport: &http.Transport{
 | 
			
		||||
			Dial: (&net.Dialer{
 | 
			
		||||
				Timeout:   2 * time.Second,
 | 
			
		||||
				KeepAlive: 30 * time.Second,
 | 
			
		||||
			}).Dial,
 | 
			
		||||
		},
 | 
			
		||||
	}}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NotDefinedError is returned when requested metadata is not defined.
 | 
			
		||||
//
 | 
			
		||||
// The underlying string is the suffix after "/computeMetadata/v1/".
 | 
			
		||||
//
 | 
			
		||||
// This error is not returned if the value is defined to be the empty
 | 
			
		||||
// string.
 | 
			
		||||
type NotDefinedError string
 | 
			
		||||
 | 
			
		||||
func (suffix NotDefinedError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *cachedValue) get(cl *Client) (v string, err error) {
 | 
			
		||||
	defer c.mu.Unlock()
 | 
			
		||||
	c.mu.Lock()
 | 
			
		||||
	if c.v != "" {
 | 
			
		||||
		return c.v, nil
 | 
			
		||||
	}
 | 
			
		||||
	if c.trim {
 | 
			
		||||
		v, err = cl.getTrimmed(c.k)
 | 
			
		||||
	} else {
 | 
			
		||||
		v, err = cl.Get(c.k)
 | 
			
		||||
	}
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		c.v = v
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	onGCEOnce sync.Once
 | 
			
		||||
	onGCE     bool
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// OnGCE reports whether this process is running on Google Compute Engine.
 | 
			
		||||
func OnGCE() bool {
 | 
			
		||||
	onGCEOnce.Do(initOnGCE)
 | 
			
		||||
	return onGCE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initOnGCE() {
 | 
			
		||||
	onGCE = testOnGCE()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func testOnGCE() bool {
 | 
			
		||||
	// The user explicitly said they're on GCE, so trust them.
 | 
			
		||||
	if os.Getenv(metadataHostEnv) != "" {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx, cancel := context.WithCancel(context.Background())
 | 
			
		||||
	defer cancel()
 | 
			
		||||
 | 
			
		||||
	resc := make(chan bool, 2)
 | 
			
		||||
 | 
			
		||||
	// Try two strategies in parallel.
 | 
			
		||||
	// See https://github.com/googleapis/google-cloud-go/issues/194
 | 
			
		||||
	go func() {
 | 
			
		||||
		req, _ := http.NewRequest("GET", "http://"+metadataIP, nil)
 | 
			
		||||
		req.Header.Set("User-Agent", userAgent)
 | 
			
		||||
		res, err := defaultClient.hc.Do(req.WithContext(ctx))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			resc <- false
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		defer res.Body.Close()
 | 
			
		||||
		resc <- res.Header.Get("Metadata-Flavor") == "Google"
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		addrs, err := net.LookupHost("metadata.google.internal")
 | 
			
		||||
		if err != nil || len(addrs) == 0 {
 | 
			
		||||
			resc <- false
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		resc <- strsContains(addrs, metadataIP)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	tryHarder := systemInfoSuggestsGCE()
 | 
			
		||||
	if tryHarder {
 | 
			
		||||
		res := <-resc
 | 
			
		||||
		if res {
 | 
			
		||||
			// The first strategy succeeded, so let's use it.
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		// Wait for either the DNS or metadata server probe to
 | 
			
		||||
		// contradict the other one and say we are running on
 | 
			
		||||
		// GCE. Give it a lot of time to do so, since the system
 | 
			
		||||
		// info already suggests we're running on a GCE BIOS.
 | 
			
		||||
		timer := time.NewTimer(5 * time.Second)
 | 
			
		||||
		defer timer.Stop()
 | 
			
		||||
		select {
 | 
			
		||||
		case res = <-resc:
 | 
			
		||||
			return res
 | 
			
		||||
		case <-timer.C:
 | 
			
		||||
			// Too slow. Who knows what this system is.
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// There's no hint from the system info that we're running on
 | 
			
		||||
	// GCE, so use the first probe's result as truth, whether it's
 | 
			
		||||
	// true or false. The goal here is to optimize for speed for
 | 
			
		||||
	// users who are NOT running on GCE. We can't assume that
 | 
			
		||||
	// either a DNS lookup or an HTTP request to a blackholed IP
 | 
			
		||||
	// address is fast. Worst case this should return when the
 | 
			
		||||
	// metaClient's Transport.ResponseHeaderTimeout or
 | 
			
		||||
	// Transport.Dial.Timeout fires (in two seconds).
 | 
			
		||||
	return <-resc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// systemInfoSuggestsGCE reports whether the local system (without
 | 
			
		||||
// doing network requests) suggests that we're running on GCE. If this
 | 
			
		||||
// returns true, testOnGCE tries a bit harder to reach its metadata
 | 
			
		||||
// server.
 | 
			
		||||
func systemInfoSuggestsGCE() bool {
 | 
			
		||||
	if runtime.GOOS != "linux" {
 | 
			
		||||
		// We don't have any non-Linux clues available, at least yet.
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
 | 
			
		||||
	name := strings.TrimSpace(string(slurp))
 | 
			
		||||
	return name == "Google" || name == "Google Compute Engine"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Subscribe calls Client.Subscribe on a client designed for subscribing (one with no
 | 
			
		||||
// ResponseHeaderTimeout).
 | 
			
		||||
func Subscribe(suffix string, fn func(v string, ok bool) error) error {
 | 
			
		||||
	return subscribeClient.Subscribe(suffix, fn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get calls Client.Get on the default client.
 | 
			
		||||
func Get(suffix string) (string, error) { return defaultClient.Get(suffix) }
 | 
			
		||||
 | 
			
		||||
// ProjectID returns the current instance's project ID string.
 | 
			
		||||
func ProjectID() (string, error) { return defaultClient.ProjectID() }
 | 
			
		||||
 | 
			
		||||
// NumericProjectID returns the current instance's numeric project ID.
 | 
			
		||||
func NumericProjectID() (string, error) { return defaultClient.NumericProjectID() }
 | 
			
		||||
 | 
			
		||||
// InternalIP returns the instance's primary internal IP address.
 | 
			
		||||
func InternalIP() (string, error) { return defaultClient.InternalIP() }
 | 
			
		||||
 | 
			
		||||
// ExternalIP returns the instance's primary external (public) IP address.
 | 
			
		||||
func ExternalIP() (string, error) { return defaultClient.ExternalIP() }
 | 
			
		||||
 | 
			
		||||
// Hostname returns the instance's hostname. This will be of the form
 | 
			
		||||
// "<instanceID>.c.<projID>.internal".
 | 
			
		||||
func Hostname() (string, error) { return defaultClient.Hostname() }
 | 
			
		||||
 | 
			
		||||
// InstanceTags returns the list of user-defined instance tags,
 | 
			
		||||
// assigned when initially creating a GCE instance.
 | 
			
		||||
func InstanceTags() ([]string, error) { return defaultClient.InstanceTags() }
 | 
			
		||||
 | 
			
		||||
// InstanceID returns the current VM's numeric instance ID.
 | 
			
		||||
func InstanceID() (string, error) { return defaultClient.InstanceID() }
 | 
			
		||||
 | 
			
		||||
// InstanceName returns the current VM's instance ID string.
 | 
			
		||||
func InstanceName() (string, error) { return defaultClient.InstanceName() }
 | 
			
		||||
 | 
			
		||||
// Zone returns the current VM's zone, such as "us-central1-b".
 | 
			
		||||
func Zone() (string, error) { return defaultClient.Zone() }
 | 
			
		||||
 | 
			
		||||
// InstanceAttributes calls Client.InstanceAttributes on the default client.
 | 
			
		||||
func InstanceAttributes() ([]string, error) { return defaultClient.InstanceAttributes() }
 | 
			
		||||
 | 
			
		||||
// ProjectAttributes calls Client.ProjectAttributes on the default client.
 | 
			
		||||
func ProjectAttributes() ([]string, error) { return defaultClient.ProjectAttributes() }
 | 
			
		||||
 | 
			
		||||
// InstanceAttributeValue calls Client.InstanceAttributeValue on the default client.
 | 
			
		||||
func InstanceAttributeValue(attr string) (string, error) {
 | 
			
		||||
	return defaultClient.InstanceAttributeValue(attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ProjectAttributeValue calls Client.ProjectAttributeValue on the default client.
 | 
			
		||||
func ProjectAttributeValue(attr string) (string, error) {
 | 
			
		||||
	return defaultClient.ProjectAttributeValue(attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Scopes calls Client.Scopes on the default client.
 | 
			
		||||
func Scopes(serviceAccount string) ([]string, error) { return defaultClient.Scopes(serviceAccount) }
 | 
			
		||||
 | 
			
		||||
func strsContains(ss []string, s string) bool {
 | 
			
		||||
	for _, v := range ss {
 | 
			
		||||
		if v == s {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A Client provides metadata.
 | 
			
		||||
type Client struct {
 | 
			
		||||
	hc *http.Client
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewClient returns a Client that can be used to fetch metadata. All HTTP requests
 | 
			
		||||
// will use the given http.Client instead of the default client.
 | 
			
		||||
func NewClient(c *http.Client) *Client {
 | 
			
		||||
	return &Client{hc: c}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getETag returns a value from the metadata service as well as the associated ETag.
 | 
			
		||||
// This func is otherwise equivalent to Get.
 | 
			
		||||
func (c *Client) getETag(suffix string) (value, etag string, err error) {
 | 
			
		||||
	// Using a fixed IP makes it very difficult to spoof the metadata service in
 | 
			
		||||
	// a container, which is an important use-case for local testing of cloud
 | 
			
		||||
	// deployments. To enable spoofing of the metadata service, the environment
 | 
			
		||||
	// variable GCE_METADATA_HOST is first inspected to decide where metadata
 | 
			
		||||
	// requests shall go.
 | 
			
		||||
	host := os.Getenv(metadataHostEnv)
 | 
			
		||||
	if host == "" {
 | 
			
		||||
		// Using 169.254.169.254 instead of "metadata" here because Go
 | 
			
		||||
		// binaries built with the "netgo" tag and without cgo won't
 | 
			
		||||
		// know the search suffix for "metadata" is
 | 
			
		||||
		// ".google.internal", and this IP address is documented as
 | 
			
		||||
		// being stable anyway.
 | 
			
		||||
		host = metadataIP
 | 
			
		||||
	}
 | 
			
		||||
	u := "http://" + host + "/computeMetadata/v1/" + suffix
 | 
			
		||||
	req, _ := http.NewRequest("GET", u, nil)
 | 
			
		||||
	req.Header.Set("Metadata-Flavor", "Google")
 | 
			
		||||
	req.Header.Set("User-Agent", userAgent)
 | 
			
		||||
	res, err := c.hc.Do(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
	defer res.Body.Close()
 | 
			
		||||
	if res.StatusCode == http.StatusNotFound {
 | 
			
		||||
		return "", "", NotDefinedError(suffix)
 | 
			
		||||
	}
 | 
			
		||||
	all, err := ioutil.ReadAll(res.Body)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", "", err
 | 
			
		||||
	}
 | 
			
		||||
	if res.StatusCode != 200 {
 | 
			
		||||
		return "", "", &Error{Code: res.StatusCode, Message: string(all)}
 | 
			
		||||
	}
 | 
			
		||||
	return string(all), res.Header.Get("Etag"), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get returns a value from the metadata service.
 | 
			
		||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
 | 
			
		||||
//
 | 
			
		||||
// If the GCE_METADATA_HOST environment variable is not defined, a default of
 | 
			
		||||
// 169.254.169.254 will be used instead.
 | 
			
		||||
//
 | 
			
		||||
// If the requested metadata is not defined, the returned error will
 | 
			
		||||
// be of type NotDefinedError.
 | 
			
		||||
func (c *Client) Get(suffix string) (string, error) {
 | 
			
		||||
	val, _, err := c.getETag(suffix)
 | 
			
		||||
	return val, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) getTrimmed(suffix string) (s string, err error) {
 | 
			
		||||
	s, err = c.Get(suffix)
 | 
			
		||||
	s = strings.TrimSpace(s)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Client) lines(suffix string) ([]string, error) {
 | 
			
		||||
	j, err := c.Get(suffix)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	s := strings.Split(strings.TrimSpace(j), "\n")
 | 
			
		||||
	for i := range s {
 | 
			
		||||
		s[i] = strings.TrimSpace(s[i])
 | 
			
		||||
	}
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ProjectID returns the current instance's project ID string.
 | 
			
		||||
func (c *Client) ProjectID() (string, error) { return projID.get(c) }
 | 
			
		||||
 | 
			
		||||
// NumericProjectID returns the current instance's numeric project ID.
 | 
			
		||||
func (c *Client) NumericProjectID() (string, error) { return projNum.get(c) }
 | 
			
		||||
 | 
			
		||||
// InstanceID returns the current VM's numeric instance ID.
 | 
			
		||||
func (c *Client) InstanceID() (string, error) { return instID.get(c) }
 | 
			
		||||
 | 
			
		||||
// InternalIP returns the instance's primary internal IP address.
 | 
			
		||||
func (c *Client) InternalIP() (string, error) {
 | 
			
		||||
	return c.getTrimmed("instance/network-interfaces/0/ip")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ExternalIP returns the instance's primary external (public) IP address.
 | 
			
		||||
func (c *Client) ExternalIP() (string, error) {
 | 
			
		||||
	return c.getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Hostname returns the instance's hostname. This will be of the form
 | 
			
		||||
// "<instanceID>.c.<projID>.internal".
 | 
			
		||||
func (c *Client) Hostname() (string, error) {
 | 
			
		||||
	return c.getTrimmed("instance/hostname")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InstanceTags returns the list of user-defined instance tags,
 | 
			
		||||
// assigned when initially creating a GCE instance.
 | 
			
		||||
func (c *Client) InstanceTags() ([]string, error) {
 | 
			
		||||
	var s []string
 | 
			
		||||
	j, err := c.Get("instance/tags")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return s, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InstanceName returns the current VM's instance ID string.
 | 
			
		||||
func (c *Client) InstanceName() (string, error) {
 | 
			
		||||
	host, err := c.Hostname()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return strings.Split(host, ".")[0], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Zone returns the current VM's zone, such as "us-central1-b".
 | 
			
		||||
func (c *Client) Zone() (string, error) {
 | 
			
		||||
	zone, err := c.getTrimmed("instance/zone")
 | 
			
		||||
	// zone is of the form "projects/<projNum>/zones/<zoneName>".
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return zone[strings.LastIndex(zone, "/")+1:], nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// InstanceAttributes returns the list of user-defined attributes,
 | 
			
		||||
// assigned when initially creating a GCE VM instance. The value of an
 | 
			
		||||
// attribute can be obtained with InstanceAttributeValue.
 | 
			
		||||
func (c *Client) InstanceAttributes() ([]string, error) { return c.lines("instance/attributes/") }
 | 
			
		||||
 | 
			
		||||
// ProjectAttributes returns the list of user-defined attributes
 | 
			
		||||
// applying to the project as a whole, not just this VM.  The value of
 | 
			
		||||
// an attribute can be obtained with ProjectAttributeValue.
 | 
			
		||||
func (c *Client) ProjectAttributes() ([]string, error) { return c.lines("project/attributes/") }
 | 
			
		||||
 | 
			
		||||
// InstanceAttributeValue returns the value of the provided VM
 | 
			
		||||
// instance attribute.
 | 
			
		||||
//
 | 
			
		||||
// If the requested attribute is not defined, the returned error will
 | 
			
		||||
// be of type NotDefinedError.
 | 
			
		||||
//
 | 
			
		||||
// InstanceAttributeValue may return ("", nil) if the attribute was
 | 
			
		||||
// defined to be the empty string.
 | 
			
		||||
func (c *Client) InstanceAttributeValue(attr string) (string, error) {
 | 
			
		||||
	return c.Get("instance/attributes/" + attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ProjectAttributeValue returns the value of the provided
 | 
			
		||||
// project attribute.
 | 
			
		||||
//
 | 
			
		||||
// If the requested attribute is not defined, the returned error will
 | 
			
		||||
// be of type NotDefinedError.
 | 
			
		||||
//
 | 
			
		||||
// ProjectAttributeValue may return ("", nil) if the attribute was
 | 
			
		||||
// defined to be the empty string.
 | 
			
		||||
func (c *Client) ProjectAttributeValue(attr string) (string, error) {
 | 
			
		||||
	return c.Get("project/attributes/" + attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Scopes returns the service account scopes for the given account.
 | 
			
		||||
// The account may be empty or the string "default" to use the instance's
 | 
			
		||||
// main account.
 | 
			
		||||
func (c *Client) Scopes(serviceAccount string) ([]string, error) {
 | 
			
		||||
	if serviceAccount == "" {
 | 
			
		||||
		serviceAccount = "default"
 | 
			
		||||
	}
 | 
			
		||||
	return c.lines("instance/service-accounts/" + serviceAccount + "/scopes")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Subscribe subscribes to a value from the metadata service.
 | 
			
		||||
// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
 | 
			
		||||
// The suffix may contain query parameters.
 | 
			
		||||
//
 | 
			
		||||
// Subscribe calls fn with the latest metadata value indicated by the provided
 | 
			
		||||
// suffix. If the metadata value is deleted, fn is called with the empty string
 | 
			
		||||
// and ok false. Subscribe blocks until fn returns a non-nil error or the value
 | 
			
		||||
// is deleted. Subscribe returns the error value returned from the last call to
 | 
			
		||||
// fn, which may be nil when ok == false.
 | 
			
		||||
func (c *Client) Subscribe(suffix string, fn func(v string, ok bool) error) error {
 | 
			
		||||
	const failedSubscribeSleep = time.Second * 5
 | 
			
		||||
 | 
			
		||||
	// First check to see if the metadata value exists at all.
 | 
			
		||||
	val, lastETag, err := c.getETag(suffix)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := fn(val, true); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ok := true
 | 
			
		||||
	if strings.ContainsRune(suffix, '?') {
 | 
			
		||||
		suffix += "&wait_for_change=true&last_etag="
 | 
			
		||||
	} else {
 | 
			
		||||
		suffix += "?wait_for_change=true&last_etag="
 | 
			
		||||
	}
 | 
			
		||||
	for {
 | 
			
		||||
		val, etag, err := c.getETag(suffix + url.QueryEscape(lastETag))
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if _, deleted := err.(NotDefinedError); !deleted {
 | 
			
		||||
				time.Sleep(failedSubscribeSleep)
 | 
			
		||||
				continue // Retry on other errors.
 | 
			
		||||
			}
 | 
			
		||||
			ok = false
 | 
			
		||||
		}
 | 
			
		||||
		lastETag = etag
 | 
			
		||||
 | 
			
		||||
		if err := fn(val, ok); err != nil || !ok {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Error contains an error response from the server.
 | 
			
		||||
type Error struct {
 | 
			
		||||
	// Code is the HTTP response status code.
 | 
			
		||||
	Code int
 | 
			
		||||
	// Message is the server response message.
 | 
			
		||||
	Message string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *Error) Error() string {
 | 
			
		||||
	return fmt.Sprintf("compute: Received %d `%s`", e.Code, e.Message)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/Microsoft/go-winio/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1 +0,0 @@
 | 
			
		||||
*.exe
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,22 +0,0 @@
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2015 Microsoft
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/Microsoft/go-winio/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,22 +0,0 @@
 | 
			
		||||
# go-winio
 | 
			
		||||
 | 
			
		||||
This repository contains utilities for efficiently performing Win32 IO operations in
 | 
			
		||||
Go. Currently, this is focused on accessing named pipes and other file handles, and
 | 
			
		||||
for using named pipes as a net transport.
 | 
			
		||||
 | 
			
		||||
This code relies on IO completion ports to avoid blocking IO on system threads, allowing Go
 | 
			
		||||
to reuse the thread to schedule another goroutine. This limits support to Windows Vista and
 | 
			
		||||
newer operating systems. This is similar to the implementation of network sockets in Go's net
 | 
			
		||||
package.
 | 
			
		||||
 | 
			
		||||
Please see the LICENSE file for licensing information.
 | 
			
		||||
 | 
			
		||||
This project has adopted the [Microsoft Open Source Code of
 | 
			
		||||
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information
 | 
			
		||||
see the [Code of Conduct
 | 
			
		||||
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact
 | 
			
		||||
[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional
 | 
			
		||||
questions or comments.
 | 
			
		||||
 | 
			
		||||
Thanks to natefinch for the inspiration for this library. See https://github.com/natefinch/npipe
 | 
			
		||||
for another named pipe implementation.
 | 
			
		||||
							
								
								
									
										280
									
								
								vendor/github.com/Microsoft/go-winio/backup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										280
									
								
								vendor/github.com/Microsoft/go-winio/backup.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,280 +0,0 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unicode/utf16"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
 | 
			
		||||
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	BackupData = uint32(iota + 1)
 | 
			
		||||
	BackupEaData
 | 
			
		||||
	BackupSecurity
 | 
			
		||||
	BackupAlternateData
 | 
			
		||||
	BackupLink
 | 
			
		||||
	BackupPropertyData
 | 
			
		||||
	BackupObjectId
 | 
			
		||||
	BackupReparseData
 | 
			
		||||
	BackupSparseBlock
 | 
			
		||||
	BackupTxfsData
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	StreamSparseAttributes = uint32(8)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	WRITE_DAC              = 0x40000
 | 
			
		||||
	WRITE_OWNER            = 0x80000
 | 
			
		||||
	ACCESS_SYSTEM_SECURITY = 0x1000000
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// BackupHeader represents a backup stream of a file.
 | 
			
		||||
type BackupHeader struct {
 | 
			
		||||
	Id         uint32 // The backup stream ID
 | 
			
		||||
	Attributes uint32 // Stream attributes
 | 
			
		||||
	Size       int64  // The size of the stream in bytes
 | 
			
		||||
	Name       string // The name of the stream (for BackupAlternateData only).
 | 
			
		||||
	Offset     int64  // The offset of the stream in the file (for BackupSparseBlock only).
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type win32StreamId struct {
 | 
			
		||||
	StreamId   uint32
 | 
			
		||||
	Attributes uint32
 | 
			
		||||
	Size       uint64
 | 
			
		||||
	NameSize   uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupStreamReader reads from a stream produced by the BackupRead Win32 API and produces a series
 | 
			
		||||
// of BackupHeader values.
 | 
			
		||||
type BackupStreamReader struct {
 | 
			
		||||
	r         io.Reader
 | 
			
		||||
	bytesLeft int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBackupStreamReader produces a BackupStreamReader from any io.Reader.
 | 
			
		||||
func NewBackupStreamReader(r io.Reader) *BackupStreamReader {
 | 
			
		||||
	return &BackupStreamReader{r, 0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Next returns the next backup stream and prepares for calls to Read(). It skips the remainder of the current stream if
 | 
			
		||||
// it was not completely read.
 | 
			
		||||
func (r *BackupStreamReader) Next() (*BackupHeader, error) {
 | 
			
		||||
	if r.bytesLeft > 0 {
 | 
			
		||||
		if s, ok := r.r.(io.Seeker); ok {
 | 
			
		||||
			// Make sure Seek on io.SeekCurrent sometimes succeeds
 | 
			
		||||
			// before trying the actual seek.
 | 
			
		||||
			if _, err := s.Seek(0, io.SeekCurrent); err == nil {
 | 
			
		||||
				if _, err = s.Seek(r.bytesLeft, io.SeekCurrent); err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				r.bytesLeft = 0
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if _, err := io.Copy(ioutil.Discard, r); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	var wsi win32StreamId
 | 
			
		||||
	if err := binary.Read(r.r, binary.LittleEndian, &wsi); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	hdr := &BackupHeader{
 | 
			
		||||
		Id:         wsi.StreamId,
 | 
			
		||||
		Attributes: wsi.Attributes,
 | 
			
		||||
		Size:       int64(wsi.Size),
 | 
			
		||||
	}
 | 
			
		||||
	if wsi.NameSize != 0 {
 | 
			
		||||
		name := make([]uint16, int(wsi.NameSize/2))
 | 
			
		||||
		if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		hdr.Name = syscall.UTF16ToString(name)
 | 
			
		||||
	}
 | 
			
		||||
	if wsi.StreamId == BackupSparseBlock {
 | 
			
		||||
		if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		hdr.Size -= 8
 | 
			
		||||
	}
 | 
			
		||||
	r.bytesLeft = hdr.Size
 | 
			
		||||
	return hdr, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads from the current backup stream.
 | 
			
		||||
func (r *BackupStreamReader) Read(b []byte) (int, error) {
 | 
			
		||||
	if r.bytesLeft == 0 {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	if int64(len(b)) > r.bytesLeft {
 | 
			
		||||
		b = b[:r.bytesLeft]
 | 
			
		||||
	}
 | 
			
		||||
	n, err := r.r.Read(b)
 | 
			
		||||
	r.bytesLeft -= int64(n)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		err = io.ErrUnexpectedEOF
 | 
			
		||||
	} else if r.bytesLeft == 0 && err == nil {
 | 
			
		||||
		err = io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupStreamWriter writes a stream compatible with the BackupWrite Win32 API.
 | 
			
		||||
type BackupStreamWriter struct {
 | 
			
		||||
	w         io.Writer
 | 
			
		||||
	bytesLeft int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBackupStreamWriter produces a BackupStreamWriter on top of an io.Writer.
 | 
			
		||||
func NewBackupStreamWriter(w io.Writer) *BackupStreamWriter {
 | 
			
		||||
	return &BackupStreamWriter{w, 0}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteHeader writes the next backup stream header and prepares for calls to Write().
 | 
			
		||||
func (w *BackupStreamWriter) WriteHeader(hdr *BackupHeader) error {
 | 
			
		||||
	if w.bytesLeft != 0 {
 | 
			
		||||
		return fmt.Errorf("missing %d bytes", w.bytesLeft)
 | 
			
		||||
	}
 | 
			
		||||
	name := utf16.Encode([]rune(hdr.Name))
 | 
			
		||||
	wsi := win32StreamId{
 | 
			
		||||
		StreamId:   hdr.Id,
 | 
			
		||||
		Attributes: hdr.Attributes,
 | 
			
		||||
		Size:       uint64(hdr.Size),
 | 
			
		||||
		NameSize:   uint32(len(name) * 2),
 | 
			
		||||
	}
 | 
			
		||||
	if hdr.Id == BackupSparseBlock {
 | 
			
		||||
		// Include space for the int64 block offset
 | 
			
		||||
		wsi.Size += 8
 | 
			
		||||
	}
 | 
			
		||||
	if err := binary.Write(w.w, binary.LittleEndian, &wsi); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if len(name) != 0 {
 | 
			
		||||
		if err := binary.Write(w.w, binary.LittleEndian, name); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if hdr.Id == BackupSparseBlock {
 | 
			
		||||
		if err := binary.Write(w.w, binary.LittleEndian, hdr.Offset); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	w.bytesLeft = hdr.Size
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write writes to the current backup stream.
 | 
			
		||||
func (w *BackupStreamWriter) Write(b []byte) (int, error) {
 | 
			
		||||
	if w.bytesLeft < int64(len(b)) {
 | 
			
		||||
		return 0, fmt.Errorf("too many bytes by %d", int64(len(b))-w.bytesLeft)
 | 
			
		||||
	}
 | 
			
		||||
	n, err := w.w.Write(b)
 | 
			
		||||
	w.bytesLeft -= int64(n)
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupFileReader provides an io.ReadCloser interface on top of the BackupRead Win32 API.
 | 
			
		||||
type BackupFileReader struct {
 | 
			
		||||
	f               *os.File
 | 
			
		||||
	includeSecurity bool
 | 
			
		||||
	ctx             uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBackupFileReader returns a new BackupFileReader from a file handle. If includeSecurity is true,
 | 
			
		||||
// Read will attempt to read the security descriptor of the file.
 | 
			
		||||
func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
 | 
			
		||||
	r := &BackupFileReader{f, includeSecurity, 0}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
 | 
			
		||||
func (r *BackupFileReader) Read(b []byte) (int, error) {
 | 
			
		||||
	var bytesRead uint32
 | 
			
		||||
	err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{"BackupRead", r.f.Name(), err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(r.f)
 | 
			
		||||
	if bytesRead == 0 {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	return int(bytesRead), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close frees Win32 resources associated with the BackupFileReader. It does not close
 | 
			
		||||
// the underlying file.
 | 
			
		||||
func (r *BackupFileReader) Close() error {
 | 
			
		||||
	if r.ctx != 0 {
 | 
			
		||||
		backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
 | 
			
		||||
		runtime.KeepAlive(r.f)
 | 
			
		||||
		r.ctx = 0
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BackupFileWriter provides an io.WriteCloser interface on top of the BackupWrite Win32 API.
 | 
			
		||||
type BackupFileWriter struct {
 | 
			
		||||
	f               *os.File
 | 
			
		||||
	includeSecurity bool
 | 
			
		||||
	ctx             uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewBackupFileWriter returns a new BackupFileWriter from a file handle. If includeSecurity is true,
 | 
			
		||||
// Write() will attempt to restore the security descriptor from the stream.
 | 
			
		||||
func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
 | 
			
		||||
	w := &BackupFileWriter{f, includeSecurity, 0}
 | 
			
		||||
	return w
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write restores a portion of the file using the provided backup stream.
 | 
			
		||||
func (w *BackupFileWriter) Write(b []byte) (int, error) {
 | 
			
		||||
	var bytesWritten uint32
 | 
			
		||||
	err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(w.f)
 | 
			
		||||
	if int(bytesWritten) != len(b) {
 | 
			
		||||
		return int(bytesWritten), errors.New("not all bytes could be written")
 | 
			
		||||
	}
 | 
			
		||||
	return len(b), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close frees Win32 resources associated with the BackupFileWriter. It does not
 | 
			
		||||
// close the underlying file.
 | 
			
		||||
func (w *BackupFileWriter) Close() error {
 | 
			
		||||
	if w.ctx != 0 {
 | 
			
		||||
		backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
 | 
			
		||||
		runtime.KeepAlive(w.f)
 | 
			
		||||
		w.ctx = 0
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OpenForBackup opens a file or directory, potentially skipping access checks if the backup
 | 
			
		||||
// or restore privileges have been acquired.
 | 
			
		||||
//
 | 
			
		||||
// If the file opened was a directory, it cannot be used with Readdir().
 | 
			
		||||
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
 | 
			
		||||
	winPath, err := syscall.UTF16FromString(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OPEN_REPARSE_POINT, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return os.NewFile(uintptr(h), path), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										137
									
								
								vendor/github.com/Microsoft/go-winio/ea.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										137
									
								
								vendor/github.com/Microsoft/go-winio/ea.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,137 +0,0 @@
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type fileFullEaInformation struct {
 | 
			
		||||
	NextEntryOffset uint32
 | 
			
		||||
	Flags           uint8
 | 
			
		||||
	NameLength      uint8
 | 
			
		||||
	ValueLength     uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	fileFullEaInformationSize = binary.Size(&fileFullEaInformation{})
 | 
			
		||||
 | 
			
		||||
	errInvalidEaBuffer = errors.New("invalid extended attribute buffer")
 | 
			
		||||
	errEaNameTooLarge  = errors.New("extended attribute name too large")
 | 
			
		||||
	errEaValueTooLarge = errors.New("extended attribute value too large")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ExtendedAttribute represents a single Windows EA.
 | 
			
		||||
type ExtendedAttribute struct {
 | 
			
		||||
	Name  string
 | 
			
		||||
	Value []byte
 | 
			
		||||
	Flags uint8
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseEa(b []byte) (ea ExtendedAttribute, nb []byte, err error) {
 | 
			
		||||
	var info fileFullEaInformation
 | 
			
		||||
	err = binary.Read(bytes.NewReader(b), binary.LittleEndian, &info)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		err = errInvalidEaBuffer
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	nameOffset := fileFullEaInformationSize
 | 
			
		||||
	nameLen := int(info.NameLength)
 | 
			
		||||
	valueOffset := nameOffset + int(info.NameLength) + 1
 | 
			
		||||
	valueLen := int(info.ValueLength)
 | 
			
		||||
	nextOffset := int(info.NextEntryOffset)
 | 
			
		||||
	if valueLen+valueOffset > len(b) || nextOffset < 0 || nextOffset > len(b) {
 | 
			
		||||
		err = errInvalidEaBuffer
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ea.Name = string(b[nameOffset : nameOffset+nameLen])
 | 
			
		||||
	ea.Value = b[valueOffset : valueOffset+valueLen]
 | 
			
		||||
	ea.Flags = info.Flags
 | 
			
		||||
	if info.NextEntryOffset != 0 {
 | 
			
		||||
		nb = b[info.NextEntryOffset:]
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecodeExtendedAttributes decodes a list of EAs from a FILE_FULL_EA_INFORMATION
 | 
			
		||||
// buffer retrieved from BackupRead, ZwQueryEaFile, etc.
 | 
			
		||||
func DecodeExtendedAttributes(b []byte) (eas []ExtendedAttribute, err error) {
 | 
			
		||||
	for len(b) != 0 {
 | 
			
		||||
		ea, nb, err := parseEa(b)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		eas = append(eas, ea)
 | 
			
		||||
		b = nb
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeEa(buf *bytes.Buffer, ea *ExtendedAttribute, last bool) error {
 | 
			
		||||
	if int(uint8(len(ea.Name))) != len(ea.Name) {
 | 
			
		||||
		return errEaNameTooLarge
 | 
			
		||||
	}
 | 
			
		||||
	if int(uint16(len(ea.Value))) != len(ea.Value) {
 | 
			
		||||
		return errEaValueTooLarge
 | 
			
		||||
	}
 | 
			
		||||
	entrySize := uint32(fileFullEaInformationSize + len(ea.Name) + 1 + len(ea.Value))
 | 
			
		||||
	withPadding := (entrySize + 3) &^ 3
 | 
			
		||||
	nextOffset := uint32(0)
 | 
			
		||||
	if !last {
 | 
			
		||||
		nextOffset = withPadding
 | 
			
		||||
	}
 | 
			
		||||
	info := fileFullEaInformation{
 | 
			
		||||
		NextEntryOffset: nextOffset,
 | 
			
		||||
		Flags:           ea.Flags,
 | 
			
		||||
		NameLength:      uint8(len(ea.Name)),
 | 
			
		||||
		ValueLength:     uint16(len(ea.Value)),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := binary.Write(buf, binary.LittleEndian, &info)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = buf.Write([]byte(ea.Name))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = buf.WriteByte(0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = buf.Write(ea.Value)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err = buf.Write([]byte{0, 0, 0}[0 : withPadding-entrySize])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodeExtendedAttributes encodes a list of EAs into a FILE_FULL_EA_INFORMATION
 | 
			
		||||
// buffer for use with BackupWrite, ZwSetEaFile, etc.
 | 
			
		||||
func EncodeExtendedAttributes(eas []ExtendedAttribute) ([]byte, error) {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	for i := range eas {
 | 
			
		||||
		last := false
 | 
			
		||||
		if i == len(eas)-1 {
 | 
			
		||||
			last = true
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err := writeEa(&buf, &eas[i], last)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return buf.Bytes(), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										323
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										323
									
								
								vendor/github.com/Microsoft/go-winio/file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,323 +0,0 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"io"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"sync/atomic"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
 | 
			
		||||
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
 | 
			
		||||
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
 | 
			
		||||
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
 | 
			
		||||
//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
 | 
			
		||||
 | 
			
		||||
type atomicBool int32
 | 
			
		||||
 | 
			
		||||
func (b *atomicBool) isSet() bool { return atomic.LoadInt32((*int32)(b)) != 0 }
 | 
			
		||||
func (b *atomicBool) setFalse()   { atomic.StoreInt32((*int32)(b), 0) }
 | 
			
		||||
func (b *atomicBool) setTrue()    { atomic.StoreInt32((*int32)(b), 1) }
 | 
			
		||||
func (b *atomicBool) swap(new bool) bool {
 | 
			
		||||
	var newInt int32
 | 
			
		||||
	if new {
 | 
			
		||||
		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 (
 | 
			
		||||
	ErrFileClosed = errors.New("file has already been closed")
 | 
			
		||||
	ErrTimeout    = &timeoutError{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type timeoutError struct{}
 | 
			
		||||
 | 
			
		||||
func (e *timeoutError) Error() string   { return "i/o timeout" }
 | 
			
		||||
func (e *timeoutError) Timeout() bool   { return true }
 | 
			
		||||
func (e *timeoutError) Temporary() bool { return true }
 | 
			
		||||
 | 
			
		||||
type timeoutChan chan struct{}
 | 
			
		||||
 | 
			
		||||
var ioInitOnce sync.Once
 | 
			
		||||
var ioCompletionPort syscall.Handle
 | 
			
		||||
 | 
			
		||||
// ioResult contains the result of an asynchronous IO operation
 | 
			
		||||
type ioResult struct {
 | 
			
		||||
	bytes uint32
 | 
			
		||||
	err   error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ioOperation represents an outstanding asynchronous Win32 IO
 | 
			
		||||
type ioOperation struct {
 | 
			
		||||
	o  syscall.Overlapped
 | 
			
		||||
	ch chan ioResult
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func initIo() {
 | 
			
		||||
	h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	ioCompletionPort = h
 | 
			
		||||
	go ioCompletionProcessor(h)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
 | 
			
		||||
// It takes ownership of this handle and will close it if it is garbage collected.
 | 
			
		||||
type win32File struct {
 | 
			
		||||
	handle        syscall.Handle
 | 
			
		||||
	wg            sync.WaitGroup
 | 
			
		||||
	wgLock        sync.RWMutex
 | 
			
		||||
	closing       atomicBool
 | 
			
		||||
	socket        bool
 | 
			
		||||
	readDeadline  deadlineHandler
 | 
			
		||||
	writeDeadline deadlineHandler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type deadlineHandler struct {
 | 
			
		||||
	setLock     sync.Mutex
 | 
			
		||||
	channel     timeoutChan
 | 
			
		||||
	channelLock sync.RWMutex
 | 
			
		||||
	timer       *time.Timer
 | 
			
		||||
	timedout    atomicBool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// makeWin32File makes a new win32File from an existing file handle
 | 
			
		||||
func makeWin32File(h syscall.Handle) (*win32File, error) {
 | 
			
		||||
	f := &win32File{handle: h}
 | 
			
		||||
	ioInitOnce.Do(initIo)
 | 
			
		||||
	_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	f.readDeadline.channel = make(timeoutChan)
 | 
			
		||||
	f.writeDeadline.channel = make(timeoutChan)
 | 
			
		||||
	return f, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
 | 
			
		||||
	// If we return the result of makeWin32File directly, it can result in an
 | 
			
		||||
	// interface-wrapped nil, rather than a nil interface value.
 | 
			
		||||
	f, err := makeWin32File(h)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return f, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// closeHandle closes the resources associated with a Win32 handle
 | 
			
		||||
func (f *win32File) closeHandle() {
 | 
			
		||||
	f.wgLock.Lock()
 | 
			
		||||
	// Atomically set that we are closing, releasing the resources only once.
 | 
			
		||||
	if !f.closing.swap(true) {
 | 
			
		||||
		f.wgLock.Unlock()
 | 
			
		||||
		// cancel all IO and wait for it to complete
 | 
			
		||||
		cancelIoEx(f.handle, nil)
 | 
			
		||||
		f.wg.Wait()
 | 
			
		||||
		// at this point, no new IO can start
 | 
			
		||||
		syscall.Close(f.handle)
 | 
			
		||||
		f.handle = 0
 | 
			
		||||
	} else {
 | 
			
		||||
		f.wgLock.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes a win32File.
 | 
			
		||||
func (f *win32File) Close() error {
 | 
			
		||||
	f.closeHandle()
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// prepareIo prepares for a new IO operation.
 | 
			
		||||
// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning.
 | 
			
		||||
func (f *win32File) prepareIo() (*ioOperation, error) {
 | 
			
		||||
	f.wgLock.RLock()
 | 
			
		||||
	if f.closing.isSet() {
 | 
			
		||||
		f.wgLock.RUnlock()
 | 
			
		||||
		return nil, ErrFileClosed
 | 
			
		||||
	}
 | 
			
		||||
	f.wg.Add(1)
 | 
			
		||||
	f.wgLock.RUnlock()
 | 
			
		||||
	c := &ioOperation{}
 | 
			
		||||
	c.ch = make(chan ioResult)
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ioCompletionProcessor processes completed async IOs forever
 | 
			
		||||
func ioCompletionProcessor(h syscall.Handle) {
 | 
			
		||||
	for {
 | 
			
		||||
		var bytes uint32
 | 
			
		||||
		var key uintptr
 | 
			
		||||
		var op *ioOperation
 | 
			
		||||
		err := getQueuedCompletionStatus(h, &bytes, &key, &op, syscall.INFINITE)
 | 
			
		||||
		if op == nil {
 | 
			
		||||
			panic(err)
 | 
			
		||||
		}
 | 
			
		||||
		op.ch <- ioResult{bytes, err}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// asyncIo processes the return value from ReadFile or WriteFile, blocking until
 | 
			
		||||
// the operation has actually completed.
 | 
			
		||||
func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, err error) (int, error) {
 | 
			
		||||
	if err != syscall.ERROR_IO_PENDING {
 | 
			
		||||
		return int(bytes), err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if f.closing.isSet() {
 | 
			
		||||
		cancelIoEx(f.handle, &c.o)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var timeout timeoutChan
 | 
			
		||||
	if d != nil {
 | 
			
		||||
		d.channelLock.Lock()
 | 
			
		||||
		timeout = d.channel
 | 
			
		||||
		d.channelLock.Unlock()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var r ioResult
 | 
			
		||||
	select {
 | 
			
		||||
	case r = <-c.ch:
 | 
			
		||||
		err = r.err
 | 
			
		||||
		if err == syscall.ERROR_OPERATION_ABORTED {
 | 
			
		||||
			if f.closing.isSet() {
 | 
			
		||||
				err = ErrFileClosed
 | 
			
		||||
			}
 | 
			
		||||
		} else if err != nil && f.socket {
 | 
			
		||||
			// err is from Win32. Query the overlapped structure to get the winsock error.
 | 
			
		||||
			var bytes, flags uint32
 | 
			
		||||
			err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
 | 
			
		||||
		}
 | 
			
		||||
	case <-timeout:
 | 
			
		||||
		cancelIoEx(f.handle, &c.o)
 | 
			
		||||
		r = <-c.ch
 | 
			
		||||
		err = r.err
 | 
			
		||||
		if err == syscall.ERROR_OPERATION_ABORTED {
 | 
			
		||||
			err = ErrTimeout
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// runtime.KeepAlive is needed, as c is passed via native
 | 
			
		||||
	// code to ioCompletionProcessor, c must remain alive
 | 
			
		||||
	// until the channel read is complete.
 | 
			
		||||
	runtime.KeepAlive(c)
 | 
			
		||||
	return int(r.bytes), err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads from a file handle.
 | 
			
		||||
func (f *win32File) Read(b []byte) (int, error) {
 | 
			
		||||
	c, err := f.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.wg.Done()
 | 
			
		||||
 | 
			
		||||
	if f.readDeadline.timedout.isSet() {
 | 
			
		||||
		return 0, ErrTimeout
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
 | 
			
		||||
	n, err := f.asyncIo(c, &f.readDeadline, bytes, err)
 | 
			
		||||
	runtime.KeepAlive(b)
 | 
			
		||||
 | 
			
		||||
	// Handle EOF conditions.
 | 
			
		||||
	if err == nil && n == 0 && len(b) != 0 {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	} else if err == syscall.ERROR_BROKEN_PIPE {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	} else {
 | 
			
		||||
		return n, err
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write writes to a file handle.
 | 
			
		||||
func (f *win32File) Write(b []byte) (int, error) {
 | 
			
		||||
	c, err := f.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f.wg.Done()
 | 
			
		||||
 | 
			
		||||
	if f.writeDeadline.timedout.isSet() {
 | 
			
		||||
		return 0, ErrTimeout
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
 | 
			
		||||
	n, err := f.asyncIo(c, &f.writeDeadline, bytes, err)
 | 
			
		||||
	runtime.KeepAlive(b)
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32File) SetReadDeadline(deadline time.Time) error {
 | 
			
		||||
	return f.readDeadline.set(deadline)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32File) SetWriteDeadline(deadline time.Time) error {
 | 
			
		||||
	return f.writeDeadline.set(deadline)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32File) Flush() error {
 | 
			
		||||
	return syscall.FlushFileBuffers(f.handle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32File) Fd() uintptr {
 | 
			
		||||
	return uintptr(f.handle)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *deadlineHandler) set(deadline time.Time) error {
 | 
			
		||||
	d.setLock.Lock()
 | 
			
		||||
	defer d.setLock.Unlock()
 | 
			
		||||
 | 
			
		||||
	if d.timer != nil {
 | 
			
		||||
		if !d.timer.Stop() {
 | 
			
		||||
			<-d.channel
 | 
			
		||||
		}
 | 
			
		||||
		d.timer = nil
 | 
			
		||||
	}
 | 
			
		||||
	d.timedout.setFalse()
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case <-d.channel:
 | 
			
		||||
		d.channelLock.Lock()
 | 
			
		||||
		d.channel = make(chan struct{})
 | 
			
		||||
		d.channelLock.Unlock()
 | 
			
		||||
	default:
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if deadline.IsZero() {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timeoutIO := func() {
 | 
			
		||||
		d.timedout.setTrue()
 | 
			
		||||
		close(d.channel)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	now := time.Now()
 | 
			
		||||
	duration := deadline.Sub(now)
 | 
			
		||||
	if deadline.After(now) {
 | 
			
		||||
		// Deadline is in the future, set a timer to wait
 | 
			
		||||
		d.timer = time.AfterFunc(duration, timeoutIO)
 | 
			
		||||
	} else {
 | 
			
		||||
		// Deadline is in the past. Cancel all pending IO now.
 | 
			
		||||
		timeoutIO()
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										61
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										61
									
								
								vendor/github.com/Microsoft/go-winio/fileinfo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,61 +0,0 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = GetFileInformationByHandleEx
 | 
			
		||||
//sys setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) = SetFileInformationByHandle
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	fileBasicInfo = 0
 | 
			
		||||
	fileIDInfo    = 0x12
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// FileBasicInfo contains file access time and file attributes information.
 | 
			
		||||
type FileBasicInfo struct {
 | 
			
		||||
	CreationTime, LastAccessTime, LastWriteTime, ChangeTime syscall.Filetime
 | 
			
		||||
	FileAttributes                                          uint32
 | 
			
		||||
	pad                                                     uint32 // padding
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetFileBasicInfo retrieves times and attributes for a file.
 | 
			
		||||
func GetFileBasicInfo(f *os.File) (*FileBasicInfo, error) {
 | 
			
		||||
	bi := &FileBasicInfo{}
 | 
			
		||||
	if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
 | 
			
		||||
		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
	return bi, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetFileBasicInfo sets times and attributes for a file.
 | 
			
		||||
func SetFileBasicInfo(f *os.File, bi *FileBasicInfo) error {
 | 
			
		||||
	if err := setFileInformationByHandle(syscall.Handle(f.Fd()), fileBasicInfo, (*byte)(unsafe.Pointer(bi)), uint32(unsafe.Sizeof(*bi))); err != nil {
 | 
			
		||||
		return &os.PathError{Op: "SetFileInformationByHandle", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FileIDInfo contains the volume serial number and file ID for a file. This pair should be
 | 
			
		||||
// unique on a system.
 | 
			
		||||
type FileIDInfo struct {
 | 
			
		||||
	VolumeSerialNumber uint64
 | 
			
		||||
	FileID             [16]byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetFileID retrieves the unique (volume, file ID) pair for a file.
 | 
			
		||||
func GetFileID(f *os.File) (*FileIDInfo, error) {
 | 
			
		||||
	fileID := &FileIDInfo{}
 | 
			
		||||
	if err := getFileInformationByHandleEx(syscall.Handle(f.Fd()), fileIDInfo, (*byte)(unsafe.Pointer(fileID)), uint32(unsafe.Sizeof(*fileID))); err != nil {
 | 
			
		||||
		return nil, &os.PathError{Op: "GetFileInformationByHandleEx", Path: f.Name(), Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	runtime.KeepAlive(f)
 | 
			
		||||
	return fileID, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								vendor/github.com/Microsoft/go-winio/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/Microsoft/go-winio/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,9 +0,0 @@
 | 
			
		||||
module github.com/Microsoft/go-winio
 | 
			
		||||
 | 
			
		||||
go 1.12
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/pkg/errors v0.8.1
 | 
			
		||||
	github.com/sirupsen/logrus v1.4.1
 | 
			
		||||
	golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										18
									
								
								vendor/github.com/Microsoft/go-winio/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/Microsoft/go-winio/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,18 +0,0 @@
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
 | 
			
		||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 | 
			
		||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 | 
			
		||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 | 
			
		||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 | 
			
		||||
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
 | 
			
		||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 | 
			
		||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
			
		||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
 | 
			
		||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b h1:ag/x1USPSsqHud38I9BAC88qdNLDHHtQ4mlgQIZPPNA=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
							
								
								
									
										305
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										305
									
								
								vendor/github.com/Microsoft/go-winio/hvsock.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,305 +0,0 @@
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
 | 
			
		||||
	"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
 | 
			
		||||
 | 
			
		||||
	socketError = ^uintptr(0)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// An HvsockAddr is an address for a AF_HYPERV socket.
 | 
			
		||||
type HvsockAddr struct {
 | 
			
		||||
	VMID      guid.GUID
 | 
			
		||||
	ServiceID guid.GUID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type rawHvsockAddr struct {
 | 
			
		||||
	Family    uint16
 | 
			
		||||
	_         uint16
 | 
			
		||||
	VMID      guid.GUID
 | 
			
		||||
	ServiceID guid.GUID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Network returns the address's network name, "hvsock".
 | 
			
		||||
func (addr *HvsockAddr) Network() string {
 | 
			
		||||
	return "hvsock"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (addr *HvsockAddr) String() string {
 | 
			
		||||
	return fmt.Sprintf("%s:%s", &addr.VMID, &addr.ServiceID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// VsockServiceID returns an hvsock service ID corresponding to the specified AF_VSOCK port.
 | 
			
		||||
func VsockServiceID(port uint32) guid.GUID {
 | 
			
		||||
	g, _ := guid.FromString("00000000-facb-11e6-bd58-64006a7986d3")
 | 
			
		||||
	g.Data1 = port
 | 
			
		||||
	return g
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (addr *HvsockAddr) raw() rawHvsockAddr {
 | 
			
		||||
	return rawHvsockAddr{
 | 
			
		||||
		Family:    afHvSock,
 | 
			
		||||
		VMID:      addr.VMID,
 | 
			
		||||
		ServiceID: addr.ServiceID,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (addr *HvsockAddr) fromRaw(raw *rawHvsockAddr) {
 | 
			
		||||
	addr.VMID = raw.VMID
 | 
			
		||||
	addr.ServiceID = raw.ServiceID
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockListener is a socket listener for the AF_HYPERV address family.
 | 
			
		||||
type HvsockListener struct {
 | 
			
		||||
	sock *win32File
 | 
			
		||||
	addr HvsockAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HvsockConn is a connected socket of the AF_HYPERV address family.
 | 
			
		||||
type HvsockConn struct {
 | 
			
		||||
	sock          *win32File
 | 
			
		||||
	local, remote HvsockAddr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newHvSocket() (*win32File, error) {
 | 
			
		||||
	fd, err := syscall.Socket(afHvSock, syscall.SOCK_STREAM, 1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, os.NewSyscallError("socket", err)
 | 
			
		||||
	}
 | 
			
		||||
	f, err := makeWin32File(fd)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		syscall.Close(fd)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	f.socket = true
 | 
			
		||||
	return f, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListenHvsock listens for connections on the specified hvsock address.
 | 
			
		||||
func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
 | 
			
		||||
	l := &HvsockListener{addr: *addr}
 | 
			
		||||
	sock, err := newHvSocket()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("listen", err)
 | 
			
		||||
	}
 | 
			
		||||
	sa := addr.raw()
 | 
			
		||||
	err = bind(sock.handle, unsafe.Pointer(&sa), int32(unsafe.Sizeof(sa)))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("listen", os.NewSyscallError("socket", err))
 | 
			
		||||
	}
 | 
			
		||||
	err = syscall.Listen(sock.handle, 16)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("listen", os.NewSyscallError("listen", err))
 | 
			
		||||
	}
 | 
			
		||||
	return &HvsockListener{sock: sock, addr: *addr}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *HvsockListener) opErr(op string, err error) error {
 | 
			
		||||
	return &net.OpError{Op: op, Net: "hvsock", Addr: &l.addr, Err: err}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Addr returns the listener's network address.
 | 
			
		||||
func (l *HvsockListener) Addr() net.Addr {
 | 
			
		||||
	return &l.addr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Accept waits for the next connection and returns it.
 | 
			
		||||
func (l *HvsockListener) Accept() (_ net.Conn, err error) {
 | 
			
		||||
	sock, err := newHvSocket()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("accept", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if sock != nil {
 | 
			
		||||
			sock.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	c, err := l.sock.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("accept", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer l.sock.wg.Done()
 | 
			
		||||
 | 
			
		||||
	// AcceptEx, per documentation, requires an extra 16 bytes per address.
 | 
			
		||||
	const addrlen = uint32(16 + unsafe.Sizeof(rawHvsockAddr{}))
 | 
			
		||||
	var addrbuf [addrlen * 2]byte
 | 
			
		||||
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
 | 
			
		||||
	_, err = l.sock.asyncIo(c, nil, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
 | 
			
		||||
	}
 | 
			
		||||
	conn := &HvsockConn{
 | 
			
		||||
		sock: sock,
 | 
			
		||||
	}
 | 
			
		||||
	conn.local.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[0])))
 | 
			
		||||
	conn.remote.fromRaw((*rawHvsockAddr)(unsafe.Pointer(&addrbuf[addrlen])))
 | 
			
		||||
	sock = nil
 | 
			
		||||
	return conn, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes the listener, causing any pending Accept calls to fail.
 | 
			
		||||
func (l *HvsockListener) Close() error {
 | 
			
		||||
	return l.sock.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Need to finish ConnectEx handling
 | 
			
		||||
func DialHvsock(ctx context.Context, addr *HvsockAddr) (*HvsockConn, error) {
 | 
			
		||||
	sock, err := newHvSocket()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if sock != nil {
 | 
			
		||||
			sock.Close()
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
	c, err := sock.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	defer sock.wg.Done()
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = windows.ConnectEx(windows.Handle(sock.handle), sa, nil, 0, &bytes, &c.o)
 | 
			
		||||
	_, err = sock.asyncIo(ctx, c, nil, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	conn := &HvsockConn{
 | 
			
		||||
		sock:   sock,
 | 
			
		||||
		remote: *addr,
 | 
			
		||||
	}
 | 
			
		||||
	sock = nil
 | 
			
		||||
	return conn, nil
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) opErr(op string, err error) error {
 | 
			
		||||
	return &net.OpError{Op: op, Net: "hvsock", Source: &conn.local, Addr: &conn.remote, Err: err}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) Read(b []byte) (int, error) {
 | 
			
		||||
	c, err := conn.sock.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, conn.opErr("read", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer conn.sock.wg.Done()
 | 
			
		||||
	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
 | 
			
		||||
	var flags, bytes uint32
 | 
			
		||||
	err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
 | 
			
		||||
	n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if _, ok := err.(syscall.Errno); ok {
 | 
			
		||||
			err = os.NewSyscallError("wsarecv", err)
 | 
			
		||||
		}
 | 
			
		||||
		return 0, conn.opErr("read", err)
 | 
			
		||||
	} else if n == 0 {
 | 
			
		||||
		err = io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) Write(b []byte) (int, error) {
 | 
			
		||||
	t := 0
 | 
			
		||||
	for len(b) != 0 {
 | 
			
		||||
		n, err := conn.write(b)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return t + n, err
 | 
			
		||||
		}
 | 
			
		||||
		t += n
 | 
			
		||||
		b = b[n:]
 | 
			
		||||
	}
 | 
			
		||||
	return t, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) write(b []byte) (int, error) {
 | 
			
		||||
	c, err := conn.sock.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, conn.opErr("write", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer conn.sock.wg.Done()
 | 
			
		||||
	buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
 | 
			
		||||
	var bytes uint32
 | 
			
		||||
	err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
 | 
			
		||||
	n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if _, ok := err.(syscall.Errno); ok {
 | 
			
		||||
			err = os.NewSyscallError("wsasend", err)
 | 
			
		||||
		}
 | 
			
		||||
		return 0, conn.opErr("write", err)
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Close closes the socket connection, failing any pending read or write calls.
 | 
			
		||||
func (conn *HvsockConn) Close() error {
 | 
			
		||||
	return conn.sock.Close()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (conn *HvsockConn) shutdown(how int) error {
 | 
			
		||||
	err := syscall.Shutdown(conn.sock.handle, syscall.SHUT_RD)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return os.NewSyscallError("shutdown", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloseRead shuts down the read end of the socket.
 | 
			
		||||
func (conn *HvsockConn) CloseRead() error {
 | 
			
		||||
	err := conn.shutdown(syscall.SHUT_RD)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return conn.opErr("close", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloseWrite shuts down the write end of the socket, notifying the other endpoint that
 | 
			
		||||
// no more data will be written.
 | 
			
		||||
func (conn *HvsockConn) CloseWrite() error {
 | 
			
		||||
	err := conn.shutdown(syscall.SHUT_WR)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return conn.opErr("close", err)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LocalAddr returns the local address of the connection.
 | 
			
		||||
func (conn *HvsockConn) LocalAddr() net.Addr {
 | 
			
		||||
	return &conn.local
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoteAddr returns the remote address of the connection.
 | 
			
		||||
func (conn *HvsockConn) RemoteAddr() net.Addr {
 | 
			
		||||
	return &conn.remote
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetDeadline implements the net.Conn SetDeadline method.
 | 
			
		||||
func (conn *HvsockConn) SetDeadline(t time.Time) error {
 | 
			
		||||
	conn.SetReadDeadline(t)
 | 
			
		||||
	conn.SetWriteDeadline(t)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetReadDeadline implements the net.Conn SetReadDeadline method.
 | 
			
		||||
func (conn *HvsockConn) SetReadDeadline(t time.Time) error {
 | 
			
		||||
	return conn.sock.SetReadDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SetWriteDeadline implements the net.Conn SetWriteDeadline method.
 | 
			
		||||
func (conn *HvsockConn) SetWriteDeadline(t time.Time) error {
 | 
			
		||||
	return conn.sock.SetWriteDeadline(t)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										510
									
								
								vendor/github.com/Microsoft/go-winio/pipe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										510
									
								
								vendor/github.com/Microsoft/go-winio/pipe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,510 +0,0 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net"
 | 
			
		||||
	"os"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
 | 
			
		||||
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error)  [failretval==syscall.InvalidHandle] = CreateNamedPipeW
 | 
			
		||||
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
 | 
			
		||||
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
 | 
			
		||||
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
 | 
			
		||||
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
 | 
			
		||||
//sys ntCreateNamedPipeFile(pipe *syscall.Handle, access uint32, oa *objectAttributes, iosb *ioStatusBlock, share uint32, disposition uint32, options uint32, typ uint32, readMode uint32, completionMode uint32, maxInstances uint32, inboundQuota uint32, outputQuota uint32, timeout *int64) (status ntstatus) = ntdll.NtCreateNamedPipeFile
 | 
			
		||||
//sys rtlNtStatusToDosError(status ntstatus) (winerr error) = ntdll.RtlNtStatusToDosErrorNoTeb
 | 
			
		||||
//sys rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) = ntdll.RtlDosPathNameToNtPathName_U
 | 
			
		||||
//sys rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) = ntdll.RtlDefaultNpAcl
 | 
			
		||||
 | 
			
		||||
type ioStatusBlock struct {
 | 
			
		||||
	Status, Information uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type objectAttributes struct {
 | 
			
		||||
	Length             uintptr
 | 
			
		||||
	RootDirectory      uintptr
 | 
			
		||||
	ObjectName         *unicodeString
 | 
			
		||||
	Attributes         uintptr
 | 
			
		||||
	SecurityDescriptor *securityDescriptor
 | 
			
		||||
	SecurityQoS        uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type unicodeString struct {
 | 
			
		||||
	Length        uint16
 | 
			
		||||
	MaximumLength uint16
 | 
			
		||||
	Buffer        uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type securityDescriptor struct {
 | 
			
		||||
	Revision byte
 | 
			
		||||
	Sbz1     byte
 | 
			
		||||
	Control  uint16
 | 
			
		||||
	Owner    uintptr
 | 
			
		||||
	Group    uintptr
 | 
			
		||||
	Sacl     uintptr
 | 
			
		||||
	Dacl     uintptr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ntstatus int32
 | 
			
		||||
 | 
			
		||||
func (status ntstatus) Err() error {
 | 
			
		||||
	if status >= 0 {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return rtlNtStatusToDosError(status)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	cERROR_PIPE_BUSY      = syscall.Errno(231)
 | 
			
		||||
	cERROR_NO_DATA        = syscall.Errno(232)
 | 
			
		||||
	cERROR_PIPE_CONNECTED = syscall.Errno(535)
 | 
			
		||||
	cERROR_SEM_TIMEOUT    = syscall.Errno(121)
 | 
			
		||||
 | 
			
		||||
	cSECURITY_SQOS_PRESENT = 0x100000
 | 
			
		||||
	cSECURITY_ANONYMOUS    = 0
 | 
			
		||||
 | 
			
		||||
	cPIPE_TYPE_MESSAGE = 4
 | 
			
		||||
 | 
			
		||||
	cPIPE_READMODE_MESSAGE = 2
 | 
			
		||||
 | 
			
		||||
	cFILE_OPEN   = 1
 | 
			
		||||
	cFILE_CREATE = 2
 | 
			
		||||
 | 
			
		||||
	cFILE_PIPE_MESSAGE_TYPE          = 1
 | 
			
		||||
	cFILE_PIPE_REJECT_REMOTE_CLIENTS = 2
 | 
			
		||||
 | 
			
		||||
	cSE_DACL_PRESENT = 4
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// ErrPipeListenerClosed is returned for pipe operations on listeners that have been closed.
 | 
			
		||||
	// This error should match net.errClosing since docker takes a dependency on its text.
 | 
			
		||||
	ErrPipeListenerClosed = errors.New("use of closed network connection")
 | 
			
		||||
 | 
			
		||||
	errPipeWriteClosed = errors.New("pipe has been closed for write")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type win32Pipe struct {
 | 
			
		||||
	*win32File
 | 
			
		||||
	path string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type win32MessageBytePipe struct {
 | 
			
		||||
	win32Pipe
 | 
			
		||||
	writeClosed bool
 | 
			
		||||
	readEOF     bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type pipeAddress string
 | 
			
		||||
 | 
			
		||||
func (f *win32Pipe) LocalAddr() net.Addr {
 | 
			
		||||
	return pipeAddress(f.path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32Pipe) RemoteAddr() net.Addr {
 | 
			
		||||
	return pipeAddress(f.path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *win32Pipe) SetDeadline(t time.Time) error {
 | 
			
		||||
	f.SetReadDeadline(t)
 | 
			
		||||
	f.SetWriteDeadline(t)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CloseWrite closes the write side of a message pipe in byte mode.
 | 
			
		||||
func (f *win32MessageBytePipe) CloseWrite() error {
 | 
			
		||||
	if f.writeClosed {
 | 
			
		||||
		return errPipeWriteClosed
 | 
			
		||||
	}
 | 
			
		||||
	err := f.win32File.Flush()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	_, err = f.win32File.Write(nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	f.writeClosed = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Write writes bytes to a message pipe in byte mode. Zero-byte writes are ignored, since
 | 
			
		||||
// they are used to implement CloseWrite().
 | 
			
		||||
func (f *win32MessageBytePipe) Write(b []byte) (int, error) {
 | 
			
		||||
	if f.writeClosed {
 | 
			
		||||
		return 0, errPipeWriteClosed
 | 
			
		||||
	}
 | 
			
		||||
	if len(b) == 0 {
 | 
			
		||||
		return 0, nil
 | 
			
		||||
	}
 | 
			
		||||
	return f.win32File.Write(b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read reads bytes from a message pipe in byte mode. A read of a zero-byte message on a message
 | 
			
		||||
// mode pipe will return io.EOF, as will all subsequent reads.
 | 
			
		||||
func (f *win32MessageBytePipe) Read(b []byte) (int, error) {
 | 
			
		||||
	if f.readEOF {
 | 
			
		||||
		return 0, io.EOF
 | 
			
		||||
	}
 | 
			
		||||
	n, err := f.win32File.Read(b)
 | 
			
		||||
	if err == io.EOF {
 | 
			
		||||
		// If this was the result of a zero-byte read, then
 | 
			
		||||
		// it is possible that the read was due to a zero-size
 | 
			
		||||
		// message. Since we are simulating CloseWrite with a
 | 
			
		||||
		// zero-byte message, ensure that all future Read() calls
 | 
			
		||||
		// also return EOF.
 | 
			
		||||
		f.readEOF = true
 | 
			
		||||
	} else if err == syscall.ERROR_MORE_DATA {
 | 
			
		||||
		// ERROR_MORE_DATA indicates that the pipe's read mode is message mode
 | 
			
		||||
		// and the message still has more bytes. Treat this as a success, since
 | 
			
		||||
		// this package presents all named pipes as byte streams.
 | 
			
		||||
		err = nil
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s pipeAddress) Network() string {
 | 
			
		||||
	return "pipe"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s pipeAddress) String() string {
 | 
			
		||||
	return string(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
 | 
			
		||||
func tryDialPipe(ctx context.Context, path *string) (syscall.Handle, error) {
 | 
			
		||||
	for {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			return syscall.Handle(0), ctx.Err()
 | 
			
		||||
		default:
 | 
			
		||||
			h, err := createFile(*path, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_OVERLAPPED|cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				return h, nil
 | 
			
		||||
			}
 | 
			
		||||
			if err != cERROR_PIPE_BUSY {
 | 
			
		||||
				return h, &os.PathError{Err: err, Op: "open", Path: *path}
 | 
			
		||||
			}
 | 
			
		||||
			// Wait 10 msec and try again. This is a rather simplistic
 | 
			
		||||
			// view, as we always try each 10 milliseconds.
 | 
			
		||||
			time.Sleep(time.Millisecond * 10)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialPipe connects to a named pipe by path, timing out if the connection
 | 
			
		||||
// takes longer than the specified duration. If timeout is nil, then we use
 | 
			
		||||
// a default timeout of 2 seconds.  (We do not use WaitNamedPipe.)
 | 
			
		||||
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
 | 
			
		||||
	var absTimeout time.Time
 | 
			
		||||
	if timeout != nil {
 | 
			
		||||
		absTimeout = time.Now().Add(*timeout)
 | 
			
		||||
	} else {
 | 
			
		||||
		absTimeout = time.Now().Add(time.Second * 2)
 | 
			
		||||
	}
 | 
			
		||||
	ctx, _ := context.WithDeadline(context.Background(), absTimeout)
 | 
			
		||||
	conn, err := DialPipeContext(ctx, path)
 | 
			
		||||
	if err == context.DeadlineExceeded {
 | 
			
		||||
		return nil, ErrTimeout
 | 
			
		||||
	}
 | 
			
		||||
	return conn, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DialPipeContext attempts to connect to a named pipe by `path` until `ctx`
 | 
			
		||||
// cancellation or timeout.
 | 
			
		||||
func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
 | 
			
		||||
	var err error
 | 
			
		||||
	var h syscall.Handle
 | 
			
		||||
	h, err = tryDialPipe(ctx, &path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var flags uint32
 | 
			
		||||
	err = getNamedPipeInfo(h, &flags, nil, nil, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f, err := makeWin32File(h)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		syscall.Close(h)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If the pipe is in message mode, return a message byte pipe, which
 | 
			
		||||
	// supports CloseWrite().
 | 
			
		||||
	if flags&cPIPE_TYPE_MESSAGE != 0 {
 | 
			
		||||
		return &win32MessageBytePipe{
 | 
			
		||||
			win32Pipe: win32Pipe{win32File: f, path: path},
 | 
			
		||||
		}, nil
 | 
			
		||||
	}
 | 
			
		||||
	return &win32Pipe{win32File: f, path: path}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type acceptResponse struct {
 | 
			
		||||
	f   *win32File
 | 
			
		||||
	err error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type win32PipeListener struct {
 | 
			
		||||
	firstHandle syscall.Handle
 | 
			
		||||
	path        string
 | 
			
		||||
	config      PipeConfig
 | 
			
		||||
	acceptCh    chan (chan acceptResponse)
 | 
			
		||||
	closeCh     chan int
 | 
			
		||||
	doneCh      chan int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (syscall.Handle, error) {
 | 
			
		||||
	path16, err := syscall.UTF16FromString(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var oa objectAttributes
 | 
			
		||||
	oa.Length = unsafe.Sizeof(oa)
 | 
			
		||||
 | 
			
		||||
	var ntPath unicodeString
 | 
			
		||||
	if err := rtlDosPathNameToNtPathName(&path16[0], &ntPath, 0, 0).Err(); err != nil {
 | 
			
		||||
		return 0, &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
	defer localFree(ntPath.Buffer)
 | 
			
		||||
	oa.ObjectName = &ntPath
 | 
			
		||||
 | 
			
		||||
	// The security descriptor is only needed for the first pipe.
 | 
			
		||||
	if first {
 | 
			
		||||
		if sd != nil {
 | 
			
		||||
			len := uint32(len(sd))
 | 
			
		||||
			sdb := localAlloc(0, len)
 | 
			
		||||
			defer localFree(sdb)
 | 
			
		||||
			copy((*[0xffff]byte)(unsafe.Pointer(sdb))[:], sd)
 | 
			
		||||
			oa.SecurityDescriptor = (*securityDescriptor)(unsafe.Pointer(sdb))
 | 
			
		||||
		} else {
 | 
			
		||||
			// Construct the default named pipe security descriptor.
 | 
			
		||||
			var dacl uintptr
 | 
			
		||||
			if err := rtlDefaultNpAcl(&dacl).Err(); err != nil {
 | 
			
		||||
				return 0, fmt.Errorf("getting default named pipe ACL: %s", err)
 | 
			
		||||
			}
 | 
			
		||||
			defer localFree(dacl)
 | 
			
		||||
 | 
			
		||||
			sdb := &securityDescriptor{
 | 
			
		||||
				Revision: 1,
 | 
			
		||||
				Control:  cSE_DACL_PRESENT,
 | 
			
		||||
				Dacl:     dacl,
 | 
			
		||||
			}
 | 
			
		||||
			oa.SecurityDescriptor = sdb
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	typ := uint32(cFILE_PIPE_REJECT_REMOTE_CLIENTS)
 | 
			
		||||
	if c.MessageMode {
 | 
			
		||||
		typ |= cFILE_PIPE_MESSAGE_TYPE
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disposition := uint32(cFILE_OPEN)
 | 
			
		||||
	access := uint32(syscall.GENERIC_READ | syscall.GENERIC_WRITE | syscall.SYNCHRONIZE)
 | 
			
		||||
	if first {
 | 
			
		||||
		disposition = cFILE_CREATE
 | 
			
		||||
		// By not asking for read or write access, the named pipe file system
 | 
			
		||||
		// will put this pipe into an initially disconnected state, blocking
 | 
			
		||||
		// client connections until the next call with first == false.
 | 
			
		||||
		access = syscall.SYNCHRONIZE
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timeout := int64(-50 * 10000) // 50ms
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		h    syscall.Handle
 | 
			
		||||
		iosb ioStatusBlock
 | 
			
		||||
	)
 | 
			
		||||
	err = ntCreateNamedPipeFile(&h, access, &oa, &iosb, syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE, disposition, 0, typ, 0, 0, 0xffffffff, uint32(c.InputBufferSize), uint32(c.OutputBufferSize), &timeout).Err()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, &os.PathError{Op: "open", Path: path, Err: err}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	runtime.KeepAlive(ntPath)
 | 
			
		||||
	return h, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) makeServerPipe() (*win32File, error) {
 | 
			
		||||
	h, err := makeServerPipeHandle(l.path, nil, &l.config, false)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	f, err := makeWin32File(h)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		syscall.Close(h)
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return f, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) makeConnectedServerPipe() (*win32File, error) {
 | 
			
		||||
	p, err := l.makeServerPipe()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Wait for the client to connect.
 | 
			
		||||
	ch := make(chan error)
 | 
			
		||||
	go func(p *win32File) {
 | 
			
		||||
		ch <- connectPipe(p)
 | 
			
		||||
	}(p)
 | 
			
		||||
 | 
			
		||||
	select {
 | 
			
		||||
	case err = <-ch:
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			p.Close()
 | 
			
		||||
			p = nil
 | 
			
		||||
		}
 | 
			
		||||
	case <-l.closeCh:
 | 
			
		||||
		// Abort the connect request by closing the handle.
 | 
			
		||||
		p.Close()
 | 
			
		||||
		p = nil
 | 
			
		||||
		err = <-ch
 | 
			
		||||
		if err == nil || err == ErrFileClosed {
 | 
			
		||||
			err = ErrPipeListenerClosed
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return p, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) listenerRoutine() {
 | 
			
		||||
	closed := false
 | 
			
		||||
	for !closed {
 | 
			
		||||
		select {
 | 
			
		||||
		case <-l.closeCh:
 | 
			
		||||
			closed = true
 | 
			
		||||
		case responseCh := <-l.acceptCh:
 | 
			
		||||
			var (
 | 
			
		||||
				p   *win32File
 | 
			
		||||
				err error
 | 
			
		||||
			)
 | 
			
		||||
			for {
 | 
			
		||||
				p, err = l.makeConnectedServerPipe()
 | 
			
		||||
				// If the connection was immediately closed by the client, try
 | 
			
		||||
				// again.
 | 
			
		||||
				if err != cERROR_NO_DATA {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			responseCh <- acceptResponse{p, err}
 | 
			
		||||
			closed = err == ErrPipeListenerClosed
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	syscall.Close(l.firstHandle)
 | 
			
		||||
	l.firstHandle = 0
 | 
			
		||||
	// Notify Close() and Accept() callers that the handle has been closed.
 | 
			
		||||
	close(l.doneCh)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PipeConfig contain configuration for the pipe listener.
 | 
			
		||||
type PipeConfig struct {
 | 
			
		||||
	// SecurityDescriptor contains a Windows security descriptor in SDDL format.
 | 
			
		||||
	SecurityDescriptor string
 | 
			
		||||
 | 
			
		||||
	// MessageMode determines whether the pipe is in byte or message mode. In either
 | 
			
		||||
	// case the pipe is read in byte mode by default. The only practical difference in
 | 
			
		||||
	// this implementation is that CloseWrite() is only supported for message mode pipes;
 | 
			
		||||
	// CloseWrite() is implemented as a zero-byte write, but zero-byte writes are only
 | 
			
		||||
	// transferred to the reader (and returned as io.EOF in this implementation)
 | 
			
		||||
	// when the pipe is in message mode.
 | 
			
		||||
	MessageMode bool
 | 
			
		||||
 | 
			
		||||
	// InputBufferSize specifies the size the input buffer, in bytes.
 | 
			
		||||
	InputBufferSize int32
 | 
			
		||||
 | 
			
		||||
	// OutputBufferSize specifies the size the input buffer, in bytes.
 | 
			
		||||
	OutputBufferSize int32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListenPipe creates a listener on a Windows named pipe path, e.g. \\.\pipe\mypipe.
 | 
			
		||||
// The pipe must not already exist.
 | 
			
		||||
func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		sd  []byte
 | 
			
		||||
		err error
 | 
			
		||||
	)
 | 
			
		||||
	if c == nil {
 | 
			
		||||
		c = &PipeConfig{}
 | 
			
		||||
	}
 | 
			
		||||
	if c.SecurityDescriptor != "" {
 | 
			
		||||
		sd, err = SddlToSecurityDescriptor(c.SecurityDescriptor)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	h, err := makeServerPipeHandle(path, sd, c, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	l := &win32PipeListener{
 | 
			
		||||
		firstHandle: h,
 | 
			
		||||
		path:        path,
 | 
			
		||||
		config:      *c,
 | 
			
		||||
		acceptCh:    make(chan (chan acceptResponse)),
 | 
			
		||||
		closeCh:     make(chan int),
 | 
			
		||||
		doneCh:      make(chan int),
 | 
			
		||||
	}
 | 
			
		||||
	go l.listenerRoutine()
 | 
			
		||||
	return l, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func connectPipe(p *win32File) error {
 | 
			
		||||
	c, err := p.prepareIo()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer p.wg.Done()
 | 
			
		||||
 | 
			
		||||
	err = connectNamedPipe(p.handle, &c.o)
 | 
			
		||||
	_, err = p.asyncIo(c, nil, 0, err)
 | 
			
		||||
	if err != nil && err != cERROR_PIPE_CONNECTED {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) Accept() (net.Conn, error) {
 | 
			
		||||
	ch := make(chan acceptResponse)
 | 
			
		||||
	select {
 | 
			
		||||
	case l.acceptCh <- ch:
 | 
			
		||||
		response := <-ch
 | 
			
		||||
		err := response.err
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		if l.config.MessageMode {
 | 
			
		||||
			return &win32MessageBytePipe{
 | 
			
		||||
				win32Pipe: win32Pipe{win32File: response.f, path: l.path},
 | 
			
		||||
			}, nil
 | 
			
		||||
		}
 | 
			
		||||
		return &win32Pipe{win32File: response.f, path: l.path}, nil
 | 
			
		||||
	case <-l.doneCh:
 | 
			
		||||
		return nil, ErrPipeListenerClosed
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) Close() error {
 | 
			
		||||
	select {
 | 
			
		||||
	case l.closeCh <- 1:
 | 
			
		||||
		<-l.doneCh
 | 
			
		||||
	case <-l.doneCh:
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (l *win32PipeListener) Addr() net.Addr {
 | 
			
		||||
	return pipeAddress(l.path)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										235
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										235
									
								
								vendor/github.com/Microsoft/go-winio/pkg/guid/guid.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,235 +0,0 @@
 | 
			
		||||
// Package guid provides a GUID type. The backing structure for a GUID is
 | 
			
		||||
// identical to that used by the golang.org/x/sys/windows GUID type.
 | 
			
		||||
// There are two main binary encodings used for a GUID, the big-endian encoding,
 | 
			
		||||
// and the Windows (mixed-endian) encoding. See here for details:
 | 
			
		||||
// https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding
 | 
			
		||||
package guid
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"crypto/sha1"
 | 
			
		||||
	"encoding"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Variant specifies which GUID variant (or "type") of the GUID. It determines
 | 
			
		||||
// how the entirety of the rest of the GUID is interpreted.
 | 
			
		||||
type Variant uint8
 | 
			
		||||
 | 
			
		||||
// The variants specified by RFC 4122.
 | 
			
		||||
const (
 | 
			
		||||
	// VariantUnknown specifies a GUID variant which does not conform to one of
 | 
			
		||||
	// the variant encodings specified in RFC 4122.
 | 
			
		||||
	VariantUnknown Variant = iota
 | 
			
		||||
	VariantNCS
 | 
			
		||||
	VariantRFC4122
 | 
			
		||||
	VariantMicrosoft
 | 
			
		||||
	VariantFuture
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Version specifies how the bits in the GUID were generated. For instance, a
 | 
			
		||||
// version 4 GUID is randomly generated, and a version 5 is generated from the
 | 
			
		||||
// hash of an input string.
 | 
			
		||||
type Version uint8
 | 
			
		||||
 | 
			
		||||
var _ = (encoding.TextMarshaler)(GUID{})
 | 
			
		||||
var _ = (encoding.TextUnmarshaler)(&GUID{})
 | 
			
		||||
 | 
			
		||||
// GUID represents a GUID/UUID. It has the same structure as
 | 
			
		||||
// golang.org/x/sys/windows.GUID so that it can be used with functions expecting
 | 
			
		||||
// that type. It is defined as its own type so that stringification and
 | 
			
		||||
// marshaling can be supported. The representation matches that used by native
 | 
			
		||||
// Windows code.
 | 
			
		||||
type GUID windows.GUID
 | 
			
		||||
 | 
			
		||||
// NewV4 returns a new version 4 (pseudorandom) GUID, as defined by RFC 4122.
 | 
			
		||||
func NewV4() (GUID, error) {
 | 
			
		||||
	var b [16]byte
 | 
			
		||||
	if _, err := rand.Read(b[:]); err != nil {
 | 
			
		||||
		return GUID{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	g := FromArray(b)
 | 
			
		||||
	g.setVersion(4) // Version 4 means randomly generated.
 | 
			
		||||
	g.setVariant(VariantRFC4122)
 | 
			
		||||
 | 
			
		||||
	return g, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewV5 returns a new version 5 (generated from a string via SHA-1 hashing)
 | 
			
		||||
// GUID, as defined by RFC 4122. The RFC is unclear on the encoding of the name,
 | 
			
		||||
// and the sample code treats it as a series of bytes, so we do the same here.
 | 
			
		||||
//
 | 
			
		||||
// Some implementations, such as those found on Windows, treat the name as a
 | 
			
		||||
// big-endian UTF16 stream of bytes. If that is desired, the string can be
 | 
			
		||||
// encoded as such before being passed to this function.
 | 
			
		||||
func NewV5(namespace GUID, name []byte) (GUID, error) {
 | 
			
		||||
	b := sha1.New()
 | 
			
		||||
	namespaceBytes := namespace.ToArray()
 | 
			
		||||
	b.Write(namespaceBytes[:])
 | 
			
		||||
	b.Write(name)
 | 
			
		||||
 | 
			
		||||
	a := [16]byte{}
 | 
			
		||||
	copy(a[:], b.Sum(nil))
 | 
			
		||||
 | 
			
		||||
	g := FromArray(a)
 | 
			
		||||
	g.setVersion(5) // Version 5 means generated from a string.
 | 
			
		||||
	g.setVariant(VariantRFC4122)
 | 
			
		||||
 | 
			
		||||
	return g, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fromArray(b [16]byte, order binary.ByteOrder) GUID {
 | 
			
		||||
	var g GUID
 | 
			
		||||
	g.Data1 = order.Uint32(b[0:4])
 | 
			
		||||
	g.Data2 = order.Uint16(b[4:6])
 | 
			
		||||
	g.Data3 = order.Uint16(b[6:8])
 | 
			
		||||
	copy(g.Data4[:], b[8:16])
 | 
			
		||||
	return g
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g GUID) toArray(order binary.ByteOrder) [16]byte {
 | 
			
		||||
	b := [16]byte{}
 | 
			
		||||
	order.PutUint32(b[0:4], g.Data1)
 | 
			
		||||
	order.PutUint16(b[4:6], g.Data2)
 | 
			
		||||
	order.PutUint16(b[6:8], g.Data3)
 | 
			
		||||
	copy(b[8:16], g.Data4[:])
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromArray constructs a GUID from a big-endian encoding array of 16 bytes.
 | 
			
		||||
func FromArray(b [16]byte) GUID {
 | 
			
		||||
	return fromArray(b, binary.BigEndian)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToArray returns an array of 16 bytes representing the GUID in big-endian
 | 
			
		||||
// encoding.
 | 
			
		||||
func (g GUID) ToArray() [16]byte {
 | 
			
		||||
	return g.toArray(binary.BigEndian)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromWindowsArray constructs a GUID from a Windows encoding array of bytes.
 | 
			
		||||
func FromWindowsArray(b [16]byte) GUID {
 | 
			
		||||
	return fromArray(b, binary.LittleEndian)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToWindowsArray returns an array of 16 bytes representing the GUID in Windows
 | 
			
		||||
// encoding.
 | 
			
		||||
func (g GUID) ToWindowsArray() [16]byte {
 | 
			
		||||
	return g.toArray(binary.LittleEndian)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g GUID) String() string {
 | 
			
		||||
	return fmt.Sprintf(
 | 
			
		||||
		"%08x-%04x-%04x-%04x-%012x",
 | 
			
		||||
		g.Data1,
 | 
			
		||||
		g.Data2,
 | 
			
		||||
		g.Data3,
 | 
			
		||||
		g.Data4[:2],
 | 
			
		||||
		g.Data4[2:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FromString parses a string containing a GUID and returns the GUID. The only
 | 
			
		||||
// format currently supported is the `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
 | 
			
		||||
// format.
 | 
			
		||||
func FromString(s string) (GUID, error) {
 | 
			
		||||
	if len(s) != 36 {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
	if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var g GUID
 | 
			
		||||
 | 
			
		||||
	data1, err := strconv.ParseUint(s[0:8], 16, 32)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
	g.Data1 = uint32(data1)
 | 
			
		||||
 | 
			
		||||
	data2, err := strconv.ParseUint(s[9:13], 16, 16)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
	g.Data2 = uint16(data2)
 | 
			
		||||
 | 
			
		||||
	data3, err := strconv.ParseUint(s[14:18], 16, 16)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
	}
 | 
			
		||||
	g.Data3 = uint16(data3)
 | 
			
		||||
 | 
			
		||||
	for i, x := range []int{19, 21, 24, 26, 28, 30, 32, 34} {
 | 
			
		||||
		v, err := strconv.ParseUint(s[x:x+2], 16, 8)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return GUID{}, fmt.Errorf("invalid GUID %q", s)
 | 
			
		||||
		}
 | 
			
		||||
		g.Data4[i] = uint8(v)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return g, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *GUID) setVariant(v Variant) {
 | 
			
		||||
	d := g.Data4[0]
 | 
			
		||||
	switch v {
 | 
			
		||||
	case VariantNCS:
 | 
			
		||||
		d = (d & 0x7f)
 | 
			
		||||
	case VariantRFC4122:
 | 
			
		||||
		d = (d & 0x3f) | 0x80
 | 
			
		||||
	case VariantMicrosoft:
 | 
			
		||||
		d = (d & 0x1f) | 0xc0
 | 
			
		||||
	case VariantFuture:
 | 
			
		||||
		d = (d & 0x0f) | 0xe0
 | 
			
		||||
	case VariantUnknown:
 | 
			
		||||
		fallthrough
 | 
			
		||||
	default:
 | 
			
		||||
		panic(fmt.Sprintf("invalid variant: %d", v))
 | 
			
		||||
	}
 | 
			
		||||
	g.Data4[0] = d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Variant returns the GUID variant, as defined in RFC 4122.
 | 
			
		||||
func (g GUID) Variant() Variant {
 | 
			
		||||
	b := g.Data4[0]
 | 
			
		||||
	if b&0x80 == 0 {
 | 
			
		||||
		return VariantNCS
 | 
			
		||||
	} else if b&0xc0 == 0x80 {
 | 
			
		||||
		return VariantRFC4122
 | 
			
		||||
	} else if b&0xe0 == 0xc0 {
 | 
			
		||||
		return VariantMicrosoft
 | 
			
		||||
	} else if b&0xe0 == 0xe0 {
 | 
			
		||||
		return VariantFuture
 | 
			
		||||
	}
 | 
			
		||||
	return VariantUnknown
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (g *GUID) setVersion(v Version) {
 | 
			
		||||
	g.Data3 = (g.Data3 & 0x0fff) | (uint16(v) << 12)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Version returns the GUID version, as defined in RFC 4122.
 | 
			
		||||
func (g GUID) Version() Version {
 | 
			
		||||
	return Version((g.Data3 & 0xF000) >> 12)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalText returns the textual representation of the GUID.
 | 
			
		||||
func (g GUID) MarshalText() ([]byte, error) {
 | 
			
		||||
	return []byte(g.String()), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalText takes the textual representation of a GUID, and unmarhals it
 | 
			
		||||
// into this GUID.
 | 
			
		||||
func (g *GUID) UnmarshalText(text []byte) error {
 | 
			
		||||
	g2, err := FromString(string(text))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	*g = g2
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										202
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										202
									
								
								vendor/github.com/Microsoft/go-winio/privilege.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,202 +0,0 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unicode/utf16"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) [true] = advapi32.AdjustTokenPrivileges
 | 
			
		||||
//sys impersonateSelf(level uint32) (err error) = advapi32.ImpersonateSelf
 | 
			
		||||
//sys revertToSelf() (err error) = advapi32.RevertToSelf
 | 
			
		||||
//sys openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) = advapi32.OpenThreadToken
 | 
			
		||||
//sys getCurrentThread() (h syscall.Handle) = GetCurrentThread
 | 
			
		||||
//sys lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) = advapi32.LookupPrivilegeValueW
 | 
			
		||||
//sys lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) = advapi32.LookupPrivilegeNameW
 | 
			
		||||
//sys lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) = advapi32.LookupPrivilegeDisplayNameW
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	SE_PRIVILEGE_ENABLED = 2
 | 
			
		||||
 | 
			
		||||
	ERROR_NOT_ALL_ASSIGNED syscall.Errno = 1300
 | 
			
		||||
 | 
			
		||||
	SeBackupPrivilege  = "SeBackupPrivilege"
 | 
			
		||||
	SeRestorePrivilege = "SeRestorePrivilege"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	securityAnonymous = iota
 | 
			
		||||
	securityIdentification
 | 
			
		||||
	securityImpersonation
 | 
			
		||||
	securityDelegation
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	privNames     = make(map[string]uint64)
 | 
			
		||||
	privNameMutex sync.Mutex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PrivilegeError represents an error enabling privileges.
 | 
			
		||||
type PrivilegeError struct {
 | 
			
		||||
	privileges []uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *PrivilegeError) Error() string {
 | 
			
		||||
	s := ""
 | 
			
		||||
	if len(e.privileges) > 1 {
 | 
			
		||||
		s = "Could not enable privileges "
 | 
			
		||||
	} else {
 | 
			
		||||
		s = "Could not enable privilege "
 | 
			
		||||
	}
 | 
			
		||||
	for i, p := range e.privileges {
 | 
			
		||||
		if i != 0 {
 | 
			
		||||
			s += ", "
 | 
			
		||||
		}
 | 
			
		||||
		s += `"`
 | 
			
		||||
		s += getPrivilegeName(p)
 | 
			
		||||
		s += `"`
 | 
			
		||||
	}
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunWithPrivilege enables a single privilege for a function call.
 | 
			
		||||
func RunWithPrivilege(name string, fn func() error) error {
 | 
			
		||||
	return RunWithPrivileges([]string{name}, fn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RunWithPrivileges enables privileges for a function call.
 | 
			
		||||
func RunWithPrivileges(names []string, fn func() error) error {
 | 
			
		||||
	privileges, err := mapPrivileges(names)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	runtime.LockOSThread()
 | 
			
		||||
	defer runtime.UnlockOSThread()
 | 
			
		||||
	token, err := newThreadToken()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer releaseThreadToken(token)
 | 
			
		||||
	err = adjustPrivileges(token, privileges, SE_PRIVILEGE_ENABLED)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return fn()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func mapPrivileges(names []string) ([]uint64, error) {
 | 
			
		||||
	var privileges []uint64
 | 
			
		||||
	privNameMutex.Lock()
 | 
			
		||||
	defer privNameMutex.Unlock()
 | 
			
		||||
	for _, name := range names {
 | 
			
		||||
		p, ok := privNames[name]
 | 
			
		||||
		if !ok {
 | 
			
		||||
			err := lookupPrivilegeValue("", name, &p)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			privNames[name] = p
 | 
			
		||||
		}
 | 
			
		||||
		privileges = append(privileges, p)
 | 
			
		||||
	}
 | 
			
		||||
	return privileges, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EnableProcessPrivileges enables privileges globally for the process.
 | 
			
		||||
func EnableProcessPrivileges(names []string) error {
 | 
			
		||||
	return enableDisableProcessPrivilege(names, SE_PRIVILEGE_ENABLED)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DisableProcessPrivileges disables privileges globally for the process.
 | 
			
		||||
func DisableProcessPrivileges(names []string) error {
 | 
			
		||||
	return enableDisableProcessPrivilege(names, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func enableDisableProcessPrivilege(names []string, action uint32) error {
 | 
			
		||||
	privileges, err := mapPrivileges(names)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p, _ := windows.GetCurrentProcess()
 | 
			
		||||
	var token windows.Token
 | 
			
		||||
	err = windows.OpenProcessToken(p, windows.TOKEN_ADJUST_PRIVILEGES|windows.TOKEN_QUERY, &token)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer token.Close()
 | 
			
		||||
	return adjustPrivileges(token, privileges, action)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func adjustPrivileges(token windows.Token, privileges []uint64, action uint32) error {
 | 
			
		||||
	var b bytes.Buffer
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, uint32(len(privileges)))
 | 
			
		||||
	for _, p := range privileges {
 | 
			
		||||
		binary.Write(&b, binary.LittleEndian, p)
 | 
			
		||||
		binary.Write(&b, binary.LittleEndian, action)
 | 
			
		||||
	}
 | 
			
		||||
	prevState := make([]byte, b.Len())
 | 
			
		||||
	reqSize := uint32(0)
 | 
			
		||||
	success, err := adjustTokenPrivileges(token, false, &b.Bytes()[0], uint32(len(prevState)), &prevState[0], &reqSize)
 | 
			
		||||
	if !success {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	if err == ERROR_NOT_ALL_ASSIGNED {
 | 
			
		||||
		return &PrivilegeError{privileges}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getPrivilegeName(luid uint64) string {
 | 
			
		||||
	var nameBuffer [256]uint16
 | 
			
		||||
	bufSize := uint32(len(nameBuffer))
 | 
			
		||||
	err := lookupPrivilegeName("", &luid, &nameBuffer[0], &bufSize)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Sprintf("<unknown privilege %d>", luid)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var displayNameBuffer [256]uint16
 | 
			
		||||
	displayBufSize := uint32(len(displayNameBuffer))
 | 
			
		||||
	var langID uint32
 | 
			
		||||
	err = lookupPrivilegeDisplayName("", &nameBuffer[0], &displayNameBuffer[0], &displayBufSize, &langID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Sprintf("<unknown privilege %s>", string(utf16.Decode(nameBuffer[:bufSize])))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return string(utf16.Decode(displayNameBuffer[:displayBufSize]))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newThreadToken() (windows.Token, error) {
 | 
			
		||||
	err := impersonateSelf(securityImpersonation)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var token windows.Token
 | 
			
		||||
	err = openThreadToken(getCurrentThread(), syscall.TOKEN_ADJUST_PRIVILEGES|syscall.TOKEN_QUERY, false, &token)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		rerr := revertToSelf()
 | 
			
		||||
		if rerr != nil {
 | 
			
		||||
			panic(rerr)
 | 
			
		||||
		}
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
	return token, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func releaseThreadToken(h windows.Token) {
 | 
			
		||||
	err := revertToSelf()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	h.Close()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										128
									
								
								vendor/github.com/Microsoft/go-winio/reparse.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/Microsoft/go-winio/reparse.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,128 +0,0 @@
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf16"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	reparseTagMountPoint = 0xA0000003
 | 
			
		||||
	reparseTagSymlink    = 0xA000000C
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type reparseDataBuffer struct {
 | 
			
		||||
	ReparseTag           uint32
 | 
			
		||||
	ReparseDataLength    uint16
 | 
			
		||||
	Reserved             uint16
 | 
			
		||||
	SubstituteNameOffset uint16
 | 
			
		||||
	SubstituteNameLength uint16
 | 
			
		||||
	PrintNameOffset      uint16
 | 
			
		||||
	PrintNameLength      uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ReparsePoint describes a Win32 symlink or mount point.
 | 
			
		||||
type ReparsePoint struct {
 | 
			
		||||
	Target       string
 | 
			
		||||
	IsMountPoint bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnsupportedReparsePointError is returned when trying to decode a non-symlink or
 | 
			
		||||
// mount point reparse point.
 | 
			
		||||
type UnsupportedReparsePointError struct {
 | 
			
		||||
	Tag uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *UnsupportedReparsePointError) Error() string {
 | 
			
		||||
	return fmt.Sprintf("unsupported reparse point %x", e.Tag)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecodeReparsePoint decodes a Win32 REPARSE_DATA_BUFFER structure containing either a symlink
 | 
			
		||||
// or a mount point.
 | 
			
		||||
func DecodeReparsePoint(b []byte) (*ReparsePoint, error) {
 | 
			
		||||
	tag := binary.LittleEndian.Uint32(b[0:4])
 | 
			
		||||
	return DecodeReparsePointData(tag, b[8:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DecodeReparsePointData(tag uint32, b []byte) (*ReparsePoint, error) {
 | 
			
		||||
	isMountPoint := false
 | 
			
		||||
	switch tag {
 | 
			
		||||
	case reparseTagMountPoint:
 | 
			
		||||
		isMountPoint = true
 | 
			
		||||
	case reparseTagSymlink:
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, &UnsupportedReparsePointError{tag}
 | 
			
		||||
	}
 | 
			
		||||
	nameOffset := 8 + binary.LittleEndian.Uint16(b[4:6])
 | 
			
		||||
	if !isMountPoint {
 | 
			
		||||
		nameOffset += 4
 | 
			
		||||
	}
 | 
			
		||||
	nameLength := binary.LittleEndian.Uint16(b[6:8])
 | 
			
		||||
	name := make([]uint16, nameLength/2)
 | 
			
		||||
	err := binary.Read(bytes.NewReader(b[nameOffset:nameOffset+nameLength]), binary.LittleEndian, &name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &ReparsePoint{string(utf16.Decode(name)), isMountPoint}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isDriveLetter(c byte) bool {
 | 
			
		||||
	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EncodeReparsePoint encodes a Win32 REPARSE_DATA_BUFFER structure describing a symlink or
 | 
			
		||||
// mount point.
 | 
			
		||||
func EncodeReparsePoint(rp *ReparsePoint) []byte {
 | 
			
		||||
	// Generate an NT path and determine if this is a relative path.
 | 
			
		||||
	var ntTarget string
 | 
			
		||||
	relative := false
 | 
			
		||||
	if strings.HasPrefix(rp.Target, `\\?\`) {
 | 
			
		||||
		ntTarget = `\??\` + rp.Target[4:]
 | 
			
		||||
	} else if strings.HasPrefix(rp.Target, `\\`) {
 | 
			
		||||
		ntTarget = `\??\UNC\` + rp.Target[2:]
 | 
			
		||||
	} else if len(rp.Target) >= 2 && isDriveLetter(rp.Target[0]) && rp.Target[1] == ':' {
 | 
			
		||||
		ntTarget = `\??\` + rp.Target
 | 
			
		||||
	} else {
 | 
			
		||||
		ntTarget = rp.Target
 | 
			
		||||
		relative = true
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The paths must be NUL-terminated even though they are counted strings.
 | 
			
		||||
	target16 := utf16.Encode([]rune(rp.Target + "\x00"))
 | 
			
		||||
	ntTarget16 := utf16.Encode([]rune(ntTarget + "\x00"))
 | 
			
		||||
 | 
			
		||||
	size := int(unsafe.Sizeof(reparseDataBuffer{})) - 8
 | 
			
		||||
	size += len(ntTarget16)*2 + len(target16)*2
 | 
			
		||||
 | 
			
		||||
	tag := uint32(reparseTagMountPoint)
 | 
			
		||||
	if !rp.IsMountPoint {
 | 
			
		||||
		tag = reparseTagSymlink
 | 
			
		||||
		size += 4 // Add room for symlink flags
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data := reparseDataBuffer{
 | 
			
		||||
		ReparseTag:           tag,
 | 
			
		||||
		ReparseDataLength:    uint16(size),
 | 
			
		||||
		SubstituteNameOffset: 0,
 | 
			
		||||
		SubstituteNameLength: uint16((len(ntTarget16) - 1) * 2),
 | 
			
		||||
		PrintNameOffset:      uint16(len(ntTarget16) * 2),
 | 
			
		||||
		PrintNameLength:      uint16((len(target16) - 1) * 2),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var b bytes.Buffer
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, &data)
 | 
			
		||||
	if !rp.IsMountPoint {
 | 
			
		||||
		flags := uint32(0)
 | 
			
		||||
		if relative {
 | 
			
		||||
			flags |= 1
 | 
			
		||||
		}
 | 
			
		||||
		binary.Write(&b, binary.LittleEndian, flags)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, ntTarget16)
 | 
			
		||||
	binary.Write(&b, binary.LittleEndian, target16)
 | 
			
		||||
	return b.Bytes()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								vendor/github.com/Microsoft/go-winio/sd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										98
									
								
								vendor/github.com/Microsoft/go-winio/sd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,98 +0,0 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//sys lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) = advapi32.LookupAccountNameW
 | 
			
		||||
//sys convertSidToStringSid(sid *byte, str **uint16) (err error) = advapi32.ConvertSidToStringSidW
 | 
			
		||||
//sys convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW
 | 
			
		||||
//sys convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) = advapi32.ConvertSecurityDescriptorToStringSecurityDescriptorW
 | 
			
		||||
//sys localFree(mem uintptr) = LocalFree
 | 
			
		||||
//sys getSecurityDescriptorLength(sd uintptr) (len uint32) = advapi32.GetSecurityDescriptorLength
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	cERROR_NONE_MAPPED = syscall.Errno(1332)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type AccountLookupError struct {
 | 
			
		||||
	Name string
 | 
			
		||||
	Err  error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *AccountLookupError) Error() string {
 | 
			
		||||
	if e.Name == "" {
 | 
			
		||||
		return "lookup account: empty account name specified"
 | 
			
		||||
	}
 | 
			
		||||
	var s string
 | 
			
		||||
	switch e.Err {
 | 
			
		||||
	case cERROR_NONE_MAPPED:
 | 
			
		||||
		s = "not found"
 | 
			
		||||
	default:
 | 
			
		||||
		s = e.Err.Error()
 | 
			
		||||
	}
 | 
			
		||||
	return "lookup account " + e.Name + ": " + s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SddlConversionError struct {
 | 
			
		||||
	Sddl string
 | 
			
		||||
	Err  error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *SddlConversionError) Error() string {
 | 
			
		||||
	return "convert " + e.Sddl + ": " + e.Err.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LookupSidByName looks up the SID of an account by name
 | 
			
		||||
func LookupSidByName(name string) (sid string, err error) {
 | 
			
		||||
	if name == "" {
 | 
			
		||||
		return "", &AccountLookupError{name, cERROR_NONE_MAPPED}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var sidSize, sidNameUse, refDomainSize uint32
 | 
			
		||||
	err = lookupAccountName(nil, name, nil, &sidSize, nil, &refDomainSize, &sidNameUse)
 | 
			
		||||
	if err != nil && err != syscall.ERROR_INSUFFICIENT_BUFFER {
 | 
			
		||||
		return "", &AccountLookupError{name, err}
 | 
			
		||||
	}
 | 
			
		||||
	sidBuffer := make([]byte, sidSize)
 | 
			
		||||
	refDomainBuffer := make([]uint16, refDomainSize)
 | 
			
		||||
	err = lookupAccountName(nil, name, &sidBuffer[0], &sidSize, &refDomainBuffer[0], &refDomainSize, &sidNameUse)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", &AccountLookupError{name, err}
 | 
			
		||||
	}
 | 
			
		||||
	var strBuffer *uint16
 | 
			
		||||
	err = convertSidToStringSid(&sidBuffer[0], &strBuffer)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", &AccountLookupError{name, err}
 | 
			
		||||
	}
 | 
			
		||||
	sid = syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(strBuffer))[:])
 | 
			
		||||
	localFree(uintptr(unsafe.Pointer(strBuffer)))
 | 
			
		||||
	return sid, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SddlToSecurityDescriptor(sddl string) ([]byte, error) {
 | 
			
		||||
	var sdBuffer uintptr
 | 
			
		||||
	err := convertStringSecurityDescriptorToSecurityDescriptor(sddl, 1, &sdBuffer, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, &SddlConversionError{sddl, err}
 | 
			
		||||
	}
 | 
			
		||||
	defer localFree(sdBuffer)
 | 
			
		||||
	sd := make([]byte, getSecurityDescriptorLength(sdBuffer))
 | 
			
		||||
	copy(sd, (*[0xffff]byte)(unsafe.Pointer(sdBuffer))[:len(sd)])
 | 
			
		||||
	return sd, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SecurityDescriptorToSddl(sd []byte) (string, error) {
 | 
			
		||||
	var sddl *uint16
 | 
			
		||||
	// The returned string length seems to including an aribtrary number of terminating NULs.
 | 
			
		||||
	// Don't use it.
 | 
			
		||||
	err := convertSecurityDescriptorToStringSecurityDescriptor(&sd[0], 1, 0xff, &sddl, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	defer localFree(uintptr(unsafe.Pointer(sddl)))
 | 
			
		||||
	return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(sddl))[:]), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/Microsoft/go-winio/syscall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +0,0 @@
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go file.go pipe.go sd.go fileinfo.go privilege.go backup.go hvsock.go
 | 
			
		||||
							
								
								
									
										562
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										562
									
								
								vendor/github.com/Microsoft/go-winio/zsyscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,562 +0,0 @@
 | 
			
		||||
// Code generated by 'go generate'; DO NOT EDIT.
 | 
			
		||||
 | 
			
		||||
package winio
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// errnoErr returns common boxed Errno values, to prevent
 | 
			
		||||
// allocations at runtime.
 | 
			
		||||
func errnoErr(e syscall.Errno) error {
 | 
			
		||||
	switch e {
 | 
			
		||||
	case 0:
 | 
			
		||||
		return nil
 | 
			
		||||
	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 (
 | 
			
		||||
	modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
 | 
			
		||||
	modws2_32   = windows.NewLazySystemDLL("ws2_32.dll")
 | 
			
		||||
	modntdll    = windows.NewLazySystemDLL("ntdll.dll")
 | 
			
		||||
	modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
 | 
			
		||||
 | 
			
		||||
	procCancelIoEx                                           = modkernel32.NewProc("CancelIoEx")
 | 
			
		||||
	procCreateIoCompletionPort                               = modkernel32.NewProc("CreateIoCompletionPort")
 | 
			
		||||
	procGetQueuedCompletionStatus                            = modkernel32.NewProc("GetQueuedCompletionStatus")
 | 
			
		||||
	procSetFileCompletionNotificationModes                   = modkernel32.NewProc("SetFileCompletionNotificationModes")
 | 
			
		||||
	procWSAGetOverlappedResult                               = modws2_32.NewProc("WSAGetOverlappedResult")
 | 
			
		||||
	procConnectNamedPipe                                     = modkernel32.NewProc("ConnectNamedPipe")
 | 
			
		||||
	procCreateNamedPipeW                                     = modkernel32.NewProc("CreateNamedPipeW")
 | 
			
		||||
	procCreateFileW                                          = modkernel32.NewProc("CreateFileW")
 | 
			
		||||
	procGetNamedPipeInfo                                     = modkernel32.NewProc("GetNamedPipeInfo")
 | 
			
		||||
	procGetNamedPipeHandleStateW                             = modkernel32.NewProc("GetNamedPipeHandleStateW")
 | 
			
		||||
	procLocalAlloc                                           = modkernel32.NewProc("LocalAlloc")
 | 
			
		||||
	procNtCreateNamedPipeFile                                = modntdll.NewProc("NtCreateNamedPipeFile")
 | 
			
		||||
	procRtlNtStatusToDosErrorNoTeb                           = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
 | 
			
		||||
	procRtlDosPathNameToNtPathName_U                         = modntdll.NewProc("RtlDosPathNameToNtPathName_U")
 | 
			
		||||
	procRtlDefaultNpAcl                                      = modntdll.NewProc("RtlDefaultNpAcl")
 | 
			
		||||
	procLookupAccountNameW                                   = modadvapi32.NewProc("LookupAccountNameW")
 | 
			
		||||
	procConvertSidToStringSidW                               = modadvapi32.NewProc("ConvertSidToStringSidW")
 | 
			
		||||
	procConvertStringSecurityDescriptorToSecurityDescriptorW = modadvapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW")
 | 
			
		||||
	procConvertSecurityDescriptorToStringSecurityDescriptorW = modadvapi32.NewProc("ConvertSecurityDescriptorToStringSecurityDescriptorW")
 | 
			
		||||
	procLocalFree                                            = modkernel32.NewProc("LocalFree")
 | 
			
		||||
	procGetSecurityDescriptorLength                          = modadvapi32.NewProc("GetSecurityDescriptorLength")
 | 
			
		||||
	procGetFileInformationByHandleEx                         = modkernel32.NewProc("GetFileInformationByHandleEx")
 | 
			
		||||
	procSetFileInformationByHandle                           = modkernel32.NewProc("SetFileInformationByHandle")
 | 
			
		||||
	procAdjustTokenPrivileges                                = modadvapi32.NewProc("AdjustTokenPrivileges")
 | 
			
		||||
	procImpersonateSelf                                      = modadvapi32.NewProc("ImpersonateSelf")
 | 
			
		||||
	procRevertToSelf                                         = modadvapi32.NewProc("RevertToSelf")
 | 
			
		||||
	procOpenThreadToken                                      = modadvapi32.NewProc("OpenThreadToken")
 | 
			
		||||
	procGetCurrentThread                                     = modkernel32.NewProc("GetCurrentThread")
 | 
			
		||||
	procLookupPrivilegeValueW                                = modadvapi32.NewProc("LookupPrivilegeValueW")
 | 
			
		||||
	procLookupPrivilegeNameW                                 = modadvapi32.NewProc("LookupPrivilegeNameW")
 | 
			
		||||
	procLookupPrivilegeDisplayNameW                          = modadvapi32.NewProc("LookupPrivilegeDisplayNameW")
 | 
			
		||||
	procBackupRead                                           = modkernel32.NewProc("BackupRead")
 | 
			
		||||
	procBackupWrite                                          = modkernel32.NewProc("BackupWrite")
 | 
			
		||||
	procbind                                                 = modws2_32.NewProc("bind")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(file), uintptr(unsafe.Pointer(o)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
 | 
			
		||||
	r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
 | 
			
		||||
	newport = syscall.Handle(r0)
 | 
			
		||||
	if newport == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procGetQueuedCompletionStatus.Addr(), 5, uintptr(port), uintptr(unsafe.Pointer(bytes)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(o)), uintptr(timeout), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procSetFileCompletionNotificationModes.Addr(), 2, uintptr(h), uintptr(flags), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) {
 | 
			
		||||
	var _p0 uint32
 | 
			
		||||
	if wait {
 | 
			
		||||
		_p0 = 1
 | 
			
		||||
	} else {
 | 
			
		||||
		_p0 = 0
 | 
			
		||||
	}
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procWSAGetOverlappedResult.Addr(), 5, uintptr(h), uintptr(unsafe.Pointer(o)), uintptr(unsafe.Pointer(bytes)), uintptr(_p0), uintptr(unsafe.Pointer(flags)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(o)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _createNamedPipe(_p0, flags, pipeMode, maxInstances, outSize, inSize, defaultTimeout, sa)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _createNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) {
 | 
			
		||||
	r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(flags), uintptr(pipeMode), uintptr(maxInstances), uintptr(outSize), uintptr(inSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0)
 | 
			
		||||
	handle = syscall.Handle(r0)
 | 
			
		||||
	if handle == syscall.InvalidHandle {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
 | 
			
		||||
	r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
 | 
			
		||||
	handle = syscall.Handle(r0)
 | 
			
		||||
	if handle == syscall.InvalidHandle {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procGetNamedPipeInfo.Addr(), 5, uintptr(pipe), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(outSize)), uintptr(unsafe.Pointer(inSize)), uintptr(unsafe.Pointer(maxInstances)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func localAlloc(uFlags uint32, length uint32) (ptr uintptr) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procLocalAlloc.Addr(), 2, uintptr(uFlags), uintptr(length), 0)
 | 
			
		||||
	ptr = uintptr(r0)
 | 
			
		||||
	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) {
 | 
			
		||||
	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)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rtlNtStatusToDosError(status ntstatus) (winerr error) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(status), 0, 0)
 | 
			
		||||
	if r0 != 0 {
 | 
			
		||||
		winerr = syscall.Errno(r0)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rtlDosPathNameToNtPathName(name *uint16, ntName *unicodeString, filePart uintptr, reserved uintptr) (status ntstatus) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall6(procRtlDosPathNameToNtPathName_U.Addr(), 4, uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(ntName)), uintptr(filePart), uintptr(reserved), 0, 0)
 | 
			
		||||
	status = ntstatus(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rtlDefaultNpAcl(dacl *uintptr) (status ntstatus) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procRtlDefaultNpAcl.Addr(), 1, uintptr(unsafe.Pointer(dacl)), 0, 0)
 | 
			
		||||
	status = ntstatus(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupAccountName(systemName *uint16, accountName string, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(accountName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _lookupAccountName(systemName, _p0, sid, sidSize, refDomain, refDomainSize, sidNameUse)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _lookupAccountName(systemName *uint16, accountName *uint16, sid *byte, sidSize *uint32, refDomain *uint16, refDomainSize *uint32, sidNameUse *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procLookupAccountNameW.Addr(), 7, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(accountName)), uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(sidSize)), uintptr(unsafe.Pointer(refDomain)), uintptr(unsafe.Pointer(refDomainSize)), uintptr(unsafe.Pointer(sidNameUse)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertSidToStringSid(sid *byte, str **uint16) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procConvertSidToStringSidW.Addr(), 2, uintptr(unsafe.Pointer(sid)), uintptr(unsafe.Pointer(str)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertStringSecurityDescriptorToSecurityDescriptor(str string, revision uint32, sd *uintptr, size *uint32) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(str)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _convertStringSecurityDescriptorToSecurityDescriptor(_p0, revision, sd, size)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _convertStringSecurityDescriptorToSecurityDescriptor(str *uint16, revision uint32, sd *uintptr, size *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procConvertStringSecurityDescriptorToSecurityDescriptorW.Addr(), 4, uintptr(unsafe.Pointer(str)), uintptr(revision), uintptr(unsafe.Pointer(sd)), uintptr(unsafe.Pointer(size)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func convertSecurityDescriptorToStringSecurityDescriptor(sd *byte, revision uint32, secInfo uint32, sddl **uint16, sddlSize *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procConvertSecurityDescriptorToStringSecurityDescriptorW.Addr(), 5, uintptr(unsafe.Pointer(sd)), uintptr(revision), uintptr(secInfo), uintptr(unsafe.Pointer(sddl)), uintptr(unsafe.Pointer(sddlSize)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func localFree(mem uintptr) {
 | 
			
		||||
	syscall.Syscall(procLocalFree.Addr(), 1, uintptr(mem), 0, 0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getSecurityDescriptorLength(sd uintptr) (len uint32) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procGetSecurityDescriptorLength.Addr(), 1, uintptr(sd), 0, 0)
 | 
			
		||||
	len = uint32(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getFileInformationByHandleEx(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func setFileInformationByHandle(h syscall.Handle, class uint32, buffer *byte, size uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procSetFileInformationByHandle.Addr(), 4, uintptr(h), uintptr(class), uintptr(unsafe.Pointer(buffer)), uintptr(size), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func adjustTokenPrivileges(token windows.Token, releaseAll bool, input *byte, outputSize uint32, output *byte, requiredSize *uint32) (success bool, err error) {
 | 
			
		||||
	var _p0 uint32
 | 
			
		||||
	if releaseAll {
 | 
			
		||||
		_p0 = 1
 | 
			
		||||
	} else {
 | 
			
		||||
		_p0 = 0
 | 
			
		||||
	}
 | 
			
		||||
	r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(input)), uintptr(outputSize), uintptr(unsafe.Pointer(output)), uintptr(unsafe.Pointer(requiredSize)))
 | 
			
		||||
	success = r0 != 0
 | 
			
		||||
	if true {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func impersonateSelf(level uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(level), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func revertToSelf() (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procRevertToSelf.Addr(), 0, 0, 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func openThreadToken(thread syscall.Handle, accessMask uint32, openAsSelf bool, token *windows.Token) (err error) {
 | 
			
		||||
	var _p0 uint32
 | 
			
		||||
	if openAsSelf {
 | 
			
		||||
		_p0 = 1
 | 
			
		||||
	} else {
 | 
			
		||||
		_p0 = 0
 | 
			
		||||
	}
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(thread), uintptr(accessMask), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getCurrentThread() (h syscall.Handle) {
 | 
			
		||||
	r0, _, _ := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
 | 
			
		||||
	h = syscall.Handle(r0)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupPrivilegeValue(systemName string, name string, luid *uint64) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(systemName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	var _p1 *uint16
 | 
			
		||||
	_p1, err = syscall.UTF16PtrFromString(name)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _lookupPrivilegeValue(_p0, _p1, luid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _lookupPrivilegeValue(systemName *uint16, name *uint16, luid *uint64) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall(procLookupPrivilegeValueW.Addr(), 3, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(luid)))
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupPrivilegeName(systemName string, luid *uint64, buffer *uint16, size *uint32) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(systemName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _lookupPrivilegeName(_p0, luid, buffer, size)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _lookupPrivilegeName(systemName *uint16, luid *uint64, buffer *uint16, size *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeNameW.Addr(), 4, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(luid)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lookupPrivilegeDisplayName(systemName string, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
 | 
			
		||||
	var _p0 *uint16
 | 
			
		||||
	_p0, err = syscall.UTF16PtrFromString(systemName)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return _lookupPrivilegeDisplayName(_p0, name, buffer, size, languageId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func _lookupPrivilegeDisplayName(systemName *uint16, name *uint16, buffer *uint16, size *uint32, languageId *uint32) (err error) {
 | 
			
		||||
	r1, _, e1 := syscall.Syscall6(procLookupPrivilegeDisplayNameW.Addr(), 5, uintptr(unsafe.Pointer(systemName)), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(buffer)), uintptr(unsafe.Pointer(size)), uintptr(unsafe.Pointer(languageId)), 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
 | 
			
		||||
	var _p0 *byte
 | 
			
		||||
	if len(b) > 0 {
 | 
			
		||||
		_p0 = &b[0]
 | 
			
		||||
	}
 | 
			
		||||
	var _p1 uint32
 | 
			
		||||
	if abort {
 | 
			
		||||
		_p1 = 1
 | 
			
		||||
	} else {
 | 
			
		||||
		_p1 = 0
 | 
			
		||||
	}
 | 
			
		||||
	var _p2 uint32
 | 
			
		||||
	if processSecurity {
 | 
			
		||||
		_p2 = 1
 | 
			
		||||
	} else {
 | 
			
		||||
		_p2 = 0
 | 
			
		||||
	}
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procBackupRead.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesRead)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) {
 | 
			
		||||
	var _p0 *byte
 | 
			
		||||
	if len(b) > 0 {
 | 
			
		||||
		_p0 = &b[0]
 | 
			
		||||
	}
 | 
			
		||||
	var _p1 uint32
 | 
			
		||||
	if abort {
 | 
			
		||||
		_p1 = 1
 | 
			
		||||
	} else {
 | 
			
		||||
		_p1 = 0
 | 
			
		||||
	}
 | 
			
		||||
	var _p2 uint32
 | 
			
		||||
	if processSecurity {
 | 
			
		||||
		_p2 = 1
 | 
			
		||||
	} else {
 | 
			
		||||
		_p2 = 0
 | 
			
		||||
	}
 | 
			
		||||
	r1, _, e1 := syscall.Syscall9(procBackupWrite.Addr(), 7, uintptr(h), uintptr(unsafe.Pointer(_p0)), uintptr(len(b)), uintptr(unsafe.Pointer(bytesWritten)), uintptr(_p1), uintptr(_p2), uintptr(unsafe.Pointer(context)), 0, 0)
 | 
			
		||||
	if r1 == 0 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	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 {
 | 
			
		||||
		if e1 != 0 {
 | 
			
		||||
			err = errnoErr(e1)
 | 
			
		||||
		} else {
 | 
			
		||||
			err = syscall.EINVAL
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								vendor/github.com/Microsoft/hcsshim/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/Microsoft/hcsshim/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,21 +0,0 @@
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2015 Microsoft
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
in the Software without restriction, including without limitation the rights
 | 
			
		||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
furnished to do so, subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
SOFTWARE.
 | 
			
		||||
							
								
								
									
										57
									
								
								vendor/github.com/Microsoft/hcsshim/osversion/osversion_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										57
									
								
								vendor/github.com/Microsoft/hcsshim/osversion/osversion_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,57 +0,0 @@
 | 
			
		||||
package osversion
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// OSVersion is a wrapper for Windows version information
 | 
			
		||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
 | 
			
		||||
type OSVersion struct {
 | 
			
		||||
	Version      uint32
 | 
			
		||||
	MajorVersion uint8
 | 
			
		||||
	MinorVersion uint8
 | 
			
		||||
	Build        uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx
 | 
			
		||||
type osVersionInfoEx struct {
 | 
			
		||||
	OSVersionInfoSize uint32
 | 
			
		||||
	MajorVersion      uint32
 | 
			
		||||
	MinorVersion      uint32
 | 
			
		||||
	BuildNumber       uint32
 | 
			
		||||
	PlatformID        uint32
 | 
			
		||||
	CSDVersion        [128]uint16
 | 
			
		||||
	ServicePackMajor  uint16
 | 
			
		||||
	ServicePackMinor  uint16
 | 
			
		||||
	SuiteMask         uint16
 | 
			
		||||
	ProductType       byte
 | 
			
		||||
	Reserve           byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Get gets the operating system version on Windows.
 | 
			
		||||
// The calling application must be manifested to get the correct version information.
 | 
			
		||||
func Get() OSVersion {
 | 
			
		||||
	var err error
 | 
			
		||||
	osv := OSVersion{}
 | 
			
		||||
	osv.Version, err = windows.GetVersion()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// GetVersion never fails.
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	osv.MajorVersion = uint8(osv.Version & 0xFF)
 | 
			
		||||
	osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF)
 | 
			
		||||
	osv.Build = uint16(osv.Version >> 16)
 | 
			
		||||
	return osv
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Build gets the build-number on Windows
 | 
			
		||||
// The calling application must be manifested to get the correct version information.
 | 
			
		||||
func Build() uint16 {
 | 
			
		||||
	return Get().Build
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (osv OSVersion) ToString() string {
 | 
			
		||||
	return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/Microsoft/hcsshim/osversion/windowsbuilds.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,27 +0,0 @@
 | 
			
		||||
package osversion
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// RS1 (version 1607, codename "Redstone 1") corresponds to Windows Server
 | 
			
		||||
	// 2016 (ltsc2016) and Windows 10 (Anniversary Update).
 | 
			
		||||
	RS1 = 14393
 | 
			
		||||
 | 
			
		||||
	// RS2 (version 1703, codename "Redstone 2") was a client-only update, and
 | 
			
		||||
	// corresponds to Windows 10 (Creators Update).
 | 
			
		||||
	RS2 = 15063
 | 
			
		||||
 | 
			
		||||
	// RS3 (version 1709, codename "Redstone 3") corresponds to Windows Server
 | 
			
		||||
	// 1709 (Semi-Annual Channel (SAC)), and Windows 10 (Fall Creators Update).
 | 
			
		||||
	RS3 = 16299
 | 
			
		||||
 | 
			
		||||
	// RS4 (version 1803, codename "Redstone 4") corresponds to Windows Server
 | 
			
		||||
	// 1803 (Semi-Annual Channel (SAC)), and Windows 10 (April 2018 Update).
 | 
			
		||||
	RS4 = 17134
 | 
			
		||||
 | 
			
		||||
	// RS5 (version 1809, codename "Redstone 5") corresponds to Windows Server
 | 
			
		||||
	// 2019 (ltsc2019), and Windows 10 (October 2018 Update).
 | 
			
		||||
	RS5 = 17763
 | 
			
		||||
 | 
			
		||||
	// V19H1 (version 1903) corresponds to Windows Server 1903 (semi-annual
 | 
			
		||||
	// channel).
 | 
			
		||||
	V19H1 = 18362
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor/github.com/beevik/etree/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/beevik/etree/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,14 +0,0 @@
 | 
			
		||||
language: go
 | 
			
		||||
sudo: false
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - 1.11.x
 | 
			
		||||
  - tip
 | 
			
		||||
 | 
			
		||||
matrix:
 | 
			
		||||
  allow_failures:
 | 
			
		||||
    - go: tip
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
  - go vet ./...
 | 
			
		||||
  - go test -v ./...
 | 
			
		||||
							
								
								
									
										10
									
								
								vendor/github.com/beevik/etree/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/beevik/etree/CONTRIBUTORS
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,10 +0,0 @@
 | 
			
		||||
Brett Vickers (beevik)
 | 
			
		||||
Felix Geisendörfer (felixge)
 | 
			
		||||
Kamil Kisiel (kisielk)
 | 
			
		||||
Graham King (grahamking)
 | 
			
		||||
Matt Smith (ma314smith)
 | 
			
		||||
Michal Jemala (michaljemala)
 | 
			
		||||
Nicolas Piganeau (npiganeau)
 | 
			
		||||
Chris Brown (ccbrown)
 | 
			
		||||
Earncef Sequeira (earncef)
 | 
			
		||||
Gabriel de Labachelerie (wuzuf)
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/github.com/beevik/etree/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/beevik/etree/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,24 +0,0 @@
 | 
			
		||||
Copyright 2015-2019 Brett Vickers. All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without
 | 
			
		||||
modification, are permitted provided that the following conditions
 | 
			
		||||
are met:
 | 
			
		||||
 | 
			
		||||
   1. Redistributions of source code must retain the above copyright
 | 
			
		||||
      notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 | 
			
		||||
   2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER ``AS IS'' AND ANY
 | 
			
		||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
			
		||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER OR
 | 
			
		||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
			
		||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
			
		||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 | 
			
		||||
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | 
			
		||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
							
								
								
									
										205
									
								
								vendor/github.com/beevik/etree/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										205
									
								
								vendor/github.com/beevik/etree/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,205 +0,0 @@
 | 
			
		||||
[](https://travis-ci.org/beevik/etree)
 | 
			
		||||
[](https://godoc.org/github.com/beevik/etree)
 | 
			
		||||
 | 
			
		||||
etree
 | 
			
		||||
=====
 | 
			
		||||
 | 
			
		||||
The etree package is a lightweight, pure go package that expresses XML in
 | 
			
		||||
the form of an element tree.  Its design was inspired by the Python
 | 
			
		||||
[ElementTree](http://docs.python.org/2/library/xml.etree.elementtree.html)
 | 
			
		||||
module.
 | 
			
		||||
 | 
			
		||||
Some of the package's capabilities and features:
 | 
			
		||||
 | 
			
		||||
* Represents XML documents as trees of elements for easy traversal.
 | 
			
		||||
* Imports, serializes, modifies or creates XML documents from scratch.
 | 
			
		||||
* Writes and reads XML to/from files, byte slices, strings and io interfaces.
 | 
			
		||||
* Performs simple or complex searches with lightweight XPath-like query APIs.
 | 
			
		||||
* Auto-indents XML using spaces or tabs for better readability.
 | 
			
		||||
* Implemented in pure go; depends only on standard go libraries.
 | 
			
		||||
* Built on top of the go [encoding/xml](http://golang.org/pkg/encoding/xml)
 | 
			
		||||
  package.
 | 
			
		||||
 | 
			
		||||
### Creating an XML document
 | 
			
		||||
 | 
			
		||||
The following example creates an XML document from scratch using the etree
 | 
			
		||||
package and outputs its indented contents to stdout.
 | 
			
		||||
```go
 | 
			
		||||
doc := etree.NewDocument()
 | 
			
		||||
doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`)
 | 
			
		||||
doc.CreateProcInst("xml-stylesheet", `type="text/xsl" href="style.xsl"`)
 | 
			
		||||
 | 
			
		||||
people := doc.CreateElement("People")
 | 
			
		||||
people.CreateComment("These are all known people")
 | 
			
		||||
 | 
			
		||||
jon := people.CreateElement("Person")
 | 
			
		||||
jon.CreateAttr("name", "Jon")
 | 
			
		||||
 | 
			
		||||
sally := people.CreateElement("Person")
 | 
			
		||||
sally.CreateAttr("name", "Sally")
 | 
			
		||||
 | 
			
		||||
doc.Indent(2)
 | 
			
		||||
doc.WriteTo(os.Stdout)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Output:
 | 
			
		||||
```xml
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
 | 
			
		||||
<People>
 | 
			
		||||
  <!--These are all known people-->
 | 
			
		||||
  <Person name="Jon"/>
 | 
			
		||||
  <Person name="Sally"/>
 | 
			
		||||
</People>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Reading an XML file
 | 
			
		||||
 | 
			
		||||
Suppose you have a file on disk called `bookstore.xml` containing the
 | 
			
		||||
following data:
 | 
			
		||||
 | 
			
		||||
```xml
 | 
			
		||||
<bookstore xmlns:p="urn:schemas-books-com:prices">
 | 
			
		||||
 | 
			
		||||
  <book category="COOKING">
 | 
			
		||||
    <title lang="en">Everyday Italian</title>
 | 
			
		||||
    <author>Giada De Laurentiis</author>
 | 
			
		||||
    <year>2005</year>
 | 
			
		||||
    <p:price>30.00</p:price>
 | 
			
		||||
  </book>
 | 
			
		||||
 | 
			
		||||
  <book category="CHILDREN">
 | 
			
		||||
    <title lang="en">Harry Potter</title>
 | 
			
		||||
    <author>J K. Rowling</author>
 | 
			
		||||
    <year>2005</year>
 | 
			
		||||
    <p:price>29.99</p:price>
 | 
			
		||||
  </book>
 | 
			
		||||
 | 
			
		||||
  <book category="WEB">
 | 
			
		||||
    <title lang="en">XQuery Kick Start</title>
 | 
			
		||||
    <author>James McGovern</author>
 | 
			
		||||
    <author>Per Bothner</author>
 | 
			
		||||
    <author>Kurt Cagle</author>
 | 
			
		||||
    <author>James Linn</author>
 | 
			
		||||
    <author>Vaidyanathan Nagarajan</author>
 | 
			
		||||
    <year>2003</year>
 | 
			
		||||
    <p:price>49.99</p:price>
 | 
			
		||||
  </book>
 | 
			
		||||
 | 
			
		||||
  <book category="WEB">
 | 
			
		||||
    <title lang="en">Learning XML</title>
 | 
			
		||||
    <author>Erik T. Ray</author>
 | 
			
		||||
    <year>2003</year>
 | 
			
		||||
    <p:price>39.95</p:price>
 | 
			
		||||
  </book>
 | 
			
		||||
 | 
			
		||||
</bookstore>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This code reads the file's contents into an etree document.
 | 
			
		||||
```go
 | 
			
		||||
doc := etree.NewDocument()
 | 
			
		||||
if err := doc.ReadFromFile("bookstore.xml"); err != nil {
 | 
			
		||||
    panic(err)
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You can also read XML from a string, a byte slice, or an `io.Reader`.
 | 
			
		||||
 | 
			
		||||
### Processing elements and attributes
 | 
			
		||||
 | 
			
		||||
This example illustrates several ways to access elements and attributes using
 | 
			
		||||
etree selection queries.
 | 
			
		||||
```go
 | 
			
		||||
root := doc.SelectElement("bookstore")
 | 
			
		||||
fmt.Println("ROOT element:", root.Tag)
 | 
			
		||||
 | 
			
		||||
for _, book := range root.SelectElements("book") {
 | 
			
		||||
    fmt.Println("CHILD element:", book.Tag)
 | 
			
		||||
    if title := book.SelectElement("title"); title != nil {
 | 
			
		||||
        lang := title.SelectAttrValue("lang", "unknown")
 | 
			
		||||
        fmt.Printf("  TITLE: %s (%s)\n", title.Text(), lang)
 | 
			
		||||
    }
 | 
			
		||||
    for _, attr := range book.Attr {
 | 
			
		||||
        fmt.Printf("  ATTR: %s=%s\n", attr.Key, attr.Value)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
Output:
 | 
			
		||||
```
 | 
			
		||||
ROOT element: bookstore
 | 
			
		||||
CHILD element: book
 | 
			
		||||
  TITLE: Everyday Italian (en)
 | 
			
		||||
  ATTR: category=COOKING
 | 
			
		||||
CHILD element: book
 | 
			
		||||
  TITLE: Harry Potter (en)
 | 
			
		||||
  ATTR: category=CHILDREN
 | 
			
		||||
CHILD element: book
 | 
			
		||||
  TITLE: XQuery Kick Start (en)
 | 
			
		||||
  ATTR: category=WEB
 | 
			
		||||
CHILD element: book
 | 
			
		||||
  TITLE: Learning XML (en)
 | 
			
		||||
  ATTR: category=WEB
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Path queries
 | 
			
		||||
 | 
			
		||||
This example uses etree's path functions to select all book titles that fall
 | 
			
		||||
into the category of 'WEB'.  The double-slash prefix in the path causes the
 | 
			
		||||
search for book elements to occur recursively; book elements may appear at any
 | 
			
		||||
level of the XML hierarchy.
 | 
			
		||||
```go
 | 
			
		||||
for _, t := range doc.FindElements("//book[@category='WEB']/title") {
 | 
			
		||||
    fmt.Println("Title:", t.Text())
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Output:
 | 
			
		||||
```
 | 
			
		||||
Title: XQuery Kick Start
 | 
			
		||||
Title: Learning XML
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This example finds the first book element under the root bookstore element and
 | 
			
		||||
outputs the tag and text of each of its child elements.
 | 
			
		||||
```go
 | 
			
		||||
for _, e := range doc.FindElements("./bookstore/book[1]/*") {
 | 
			
		||||
    fmt.Printf("%s: %s\n", e.Tag, e.Text())
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Output:
 | 
			
		||||
```
 | 
			
		||||
title: Everyday Italian
 | 
			
		||||
author: Giada De Laurentiis
 | 
			
		||||
year: 2005
 | 
			
		||||
price: 30.00
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This example finds all books with a price of 49.99 and outputs their titles.
 | 
			
		||||
```go
 | 
			
		||||
path := etree.MustCompilePath("./bookstore/book[p:price='49.99']/title")
 | 
			
		||||
for _, e := range doc.FindElementsPath(path) {
 | 
			
		||||
    fmt.Println(e.Text())
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Output:
 | 
			
		||||
```
 | 
			
		||||
XQuery Kick Start
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Note that this example uses the FindElementsPath function, which takes as an
 | 
			
		||||
argument a pre-compiled path object. Use precompiled paths when you plan to
 | 
			
		||||
search with the same path more than once.
 | 
			
		||||
 | 
			
		||||
### Other features
 | 
			
		||||
 | 
			
		||||
These are just a few examples of the things the etree package can do. See the
 | 
			
		||||
[documentation](http://godoc.org/github.com/beevik/etree) for a complete
 | 
			
		||||
description of its capabilities.
 | 
			
		||||
 | 
			
		||||
### Contributing
 | 
			
		||||
 | 
			
		||||
This project accepts contributions. Just fork the repo and submit a pull
 | 
			
		||||
request!
 | 
			
		||||
							
								
								
									
										109
									
								
								vendor/github.com/beevik/etree/RELEASE_NOTES.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										109
									
								
								vendor/github.com/beevik/etree/RELEASE_NOTES.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,109 +0,0 @@
 | 
			
		||||
Release v1.1.0
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
**New Features**
 | 
			
		||||
 | 
			
		||||
* New attribute helpers.
 | 
			
		||||
  * Added the `Element.SortAttrs` method, which lexicographically sorts an
 | 
			
		||||
    element's attributes by key.
 | 
			
		||||
* New `ReadSettings` properties.
 | 
			
		||||
  * Added `Entity` for the support of custom entity maps.
 | 
			
		||||
* New `WriteSettings` properties.
 | 
			
		||||
  * Added `UseCRLF` to allow the output of CR-LF newlines instead of the
 | 
			
		||||
    default LF newlines. This is useful on Windows systems.
 | 
			
		||||
* Additional support for text and CDATA sections.
 | 
			
		||||
  * The `Element.Text` method now returns the concatenation of all consecutive
 | 
			
		||||
    character data tokens immediately following an element's opening tag.
 | 
			
		||||
  * Added `Element.SetCData` to replace the character data immediately
 | 
			
		||||
    following an element's opening tag with a CDATA section.
 | 
			
		||||
  * Added `Element.CreateCData` to create and add a CDATA section child
 | 
			
		||||
    `CharData` token to an element.
 | 
			
		||||
  * Added `Element.CreateText` to create and add a child text `CharData` token
 | 
			
		||||
    to an element.
 | 
			
		||||
  * Added `NewCData` to create a parentless CDATA section `CharData` token.
 | 
			
		||||
  * Added `NewText` to create a parentless text `CharData`
 | 
			
		||||
    token.
 | 
			
		||||
  * Added `CharData.IsCData` to detect if the token contains a CDATA section.
 | 
			
		||||
  * Added `CharData.IsWhitespace` to detect if the token contains whitespace
 | 
			
		||||
    inserted by one of the document Indent functions.
 | 
			
		||||
  * Modified `Element.SetText` so that it replaces a run of consecutive
 | 
			
		||||
    character data tokens following the element's opening tag (instead of just
 | 
			
		||||
    the first one).
 | 
			
		||||
* New "tail text" support.
 | 
			
		||||
  * Added the `Element.Tail` method, which returns the text immediately
 | 
			
		||||
    following an element's closing tag.
 | 
			
		||||
  * Added the `Element.SetTail` method, which modifies the text immediately
 | 
			
		||||
    following an element's closing tag.
 | 
			
		||||
* New element child insertion and removal methods.
 | 
			
		||||
  * Added the `Element.InsertChildAt` method, which inserts a new child token
 | 
			
		||||
    before the specified child token index.
 | 
			
		||||
  * Added the `Element.RemoveChildAt` method, which removes the child token at
 | 
			
		||||
    the specified child token index.
 | 
			
		||||
* New element and attribute queries.
 | 
			
		||||
  * Added the `Element.Index` method, which returns the element's index within
 | 
			
		||||
    its parent element's child token list.
 | 
			
		||||
  * Added the `Element.NamespaceURI` method to return the namespace URI
 | 
			
		||||
    associated with an element.
 | 
			
		||||
  * Added the `Attr.NamespaceURI` method to return the namespace URI
 | 
			
		||||
    associated with an element.
 | 
			
		||||
  * Added the `Attr.Element` method to return the element that an attribute
 | 
			
		||||
    belongs to.
 | 
			
		||||
* New Path filter functions.
 | 
			
		||||
  * Added `[local-name()='val']` to keep elements whose unprefixed tag matches
 | 
			
		||||
    the desired value.
 | 
			
		||||
  * Added `[name()='val']` to keep elements whose full tag matches the desired
 | 
			
		||||
    value.
 | 
			
		||||
  * Added `[namespace-prefix()='val']` to keep elements whose namespace prefix
 | 
			
		||||
    matches the desired value.
 | 
			
		||||
  * Added `[namespace-uri()='val']` to keep elements whose namespace URI
 | 
			
		||||
    matches the desired value.
 | 
			
		||||
 | 
			
		||||
**Bug Fixes**
 | 
			
		||||
 | 
			
		||||
* A default XML `CharSetReader` is now used to prevent failed parsing of XML
 | 
			
		||||
  documents using certain encodings.
 | 
			
		||||
  ([Issue](https://github.com/beevik/etree/issues/53)).
 | 
			
		||||
* All characters are now properly escaped according to XML parsing rules.
 | 
			
		||||
  ([Issue](https://github.com/beevik/etree/issues/55)).
 | 
			
		||||
* The `Document.Indent` and `Document.IndentTabs` functions no longer insert
 | 
			
		||||
  empty string `CharData` tokens.
 | 
			
		||||
 | 
			
		||||
**Deprecated**
 | 
			
		||||
 | 
			
		||||
* `Element`
 | 
			
		||||
    * The `InsertChild` method is deprecated. Use `InsertChildAt` instead.
 | 
			
		||||
    * The `CreateCharData` method is deprecated. Use `CreateText` instead.
 | 
			
		||||
* `CharData`
 | 
			
		||||
    * The `NewCharData` method is deprecated. Use `NewText` instead.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Release v1.0.1
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
**Changes**
 | 
			
		||||
 | 
			
		||||
* Added support for absolute etree Path queries. An absolute path begins with
 | 
			
		||||
  `/` or `//` and begins its search from the element's document root.
 | 
			
		||||
* Added [`GetPath`](https://godoc.org/github.com/beevik/etree#Element.GetPath)
 | 
			
		||||
  and [`GetRelativePath`](https://godoc.org/github.com/beevik/etree#Element.GetRelativePath)
 | 
			
		||||
  functions to the [`Element`](https://godoc.org/github.com/beevik/etree#Element)
 | 
			
		||||
  type.
 | 
			
		||||
 | 
			
		||||
**Breaking changes**
 | 
			
		||||
 | 
			
		||||
* A path starting with `//` is now interpreted as an absolute path.
 | 
			
		||||
  Previously, it was interpreted as a relative path starting from the element
 | 
			
		||||
  whose
 | 
			
		||||
  [`FindElement`](https://godoc.org/github.com/beevik/etree#Element.FindElement)
 | 
			
		||||
  method was called.  To remain compatible with this release, all paths
 | 
			
		||||
  prefixed with `//` should be prefixed with `.//` when called from any
 | 
			
		||||
  element other than the document's root.
 | 
			
		||||
* [**edit 2/1/2019**]: Minor releases should not contain breaking changes.
 | 
			
		||||
  Even though this breaking change was very minor, it was a mistake to include
 | 
			
		||||
  it in this minor release. In the future, all breaking changes will be
 | 
			
		||||
  limited to major releases (e.g., version 2.0.0).
 | 
			
		||||
 | 
			
		||||
Release v1.0.0
 | 
			
		||||
==============
 | 
			
		||||
 | 
			
		||||
Initial release.
 | 
			
		||||
							
								
								
									
										1453
									
								
								vendor/github.com/beevik/etree/etree.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1453
									
								
								vendor/github.com/beevik/etree/etree.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										276
									
								
								vendor/github.com/beevik/etree/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										276
									
								
								vendor/github.com/beevik/etree/helpers.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,276 +0,0 @@
 | 
			
		||||
// Copyright 2015-2019 Brett Vickers.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package etree
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"io"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// A simple stack
 | 
			
		||||
type stack struct {
 | 
			
		||||
	data []interface{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stack) empty() bool {
 | 
			
		||||
	return len(s.data) == 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stack) push(value interface{}) {
 | 
			
		||||
	s.data = append(s.data, value)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stack) pop() interface{} {
 | 
			
		||||
	value := s.data[len(s.data)-1]
 | 
			
		||||
	s.data[len(s.data)-1] = nil
 | 
			
		||||
	s.data = s.data[:len(s.data)-1]
 | 
			
		||||
	return value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stack) peek() interface{} {
 | 
			
		||||
	return s.data[len(s.data)-1]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A fifo is a simple first-in-first-out queue.
 | 
			
		||||
type fifo struct {
 | 
			
		||||
	data       []interface{}
 | 
			
		||||
	head, tail int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *fifo) add(value interface{}) {
 | 
			
		||||
	if f.len()+1 >= len(f.data) {
 | 
			
		||||
		f.grow()
 | 
			
		||||
	}
 | 
			
		||||
	f.data[f.tail] = value
 | 
			
		||||
	if f.tail++; f.tail == len(f.data) {
 | 
			
		||||
		f.tail = 0
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *fifo) remove() interface{} {
 | 
			
		||||
	value := f.data[f.head]
 | 
			
		||||
	f.data[f.head] = nil
 | 
			
		||||
	if f.head++; f.head == len(f.data) {
 | 
			
		||||
		f.head = 0
 | 
			
		||||
	}
 | 
			
		||||
	return value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *fifo) len() int {
 | 
			
		||||
	if f.tail >= f.head {
 | 
			
		||||
		return f.tail - f.head
 | 
			
		||||
	}
 | 
			
		||||
	return len(f.data) - f.head + f.tail
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *fifo) grow() {
 | 
			
		||||
	c := len(f.data) * 2
 | 
			
		||||
	if c == 0 {
 | 
			
		||||
		c = 4
 | 
			
		||||
	}
 | 
			
		||||
	buf, count := make([]interface{}, c), f.len()
 | 
			
		||||
	if f.tail >= f.head {
 | 
			
		||||
		copy(buf[0:count], f.data[f.head:f.tail])
 | 
			
		||||
	} else {
 | 
			
		||||
		hindex := len(f.data) - f.head
 | 
			
		||||
		copy(buf[0:hindex], f.data[f.head:])
 | 
			
		||||
		copy(buf[hindex:count], f.data[:f.tail])
 | 
			
		||||
	}
 | 
			
		||||
	f.data, f.head, f.tail = buf, 0, count
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// countReader implements a proxy reader that counts the number of
 | 
			
		||||
// bytes read from its encapsulated reader.
 | 
			
		||||
type countReader struct {
 | 
			
		||||
	r     io.Reader
 | 
			
		||||
	bytes int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newCountReader(r io.Reader) *countReader {
 | 
			
		||||
	return &countReader{r: r}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cr *countReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
	b, err := cr.r.Read(p)
 | 
			
		||||
	cr.bytes += int64(b)
 | 
			
		||||
	return b, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// countWriter implements a proxy writer that counts the number of
 | 
			
		||||
// bytes written by its encapsulated writer.
 | 
			
		||||
type countWriter struct {
 | 
			
		||||
	w     io.Writer
 | 
			
		||||
	bytes int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newCountWriter(w io.Writer) *countWriter {
 | 
			
		||||
	return &countWriter{w: w}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cw *countWriter) Write(p []byte) (n int, err error) {
 | 
			
		||||
	b, err := cw.w.Write(p)
 | 
			
		||||
	cw.bytes += int64(b)
 | 
			
		||||
	return b, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isWhitespace returns true if the byte slice contains only
 | 
			
		||||
// whitespace characters.
 | 
			
		||||
func isWhitespace(s string) bool {
 | 
			
		||||
	for i := 0; i < len(s); i++ {
 | 
			
		||||
		if c := s[i]; c != ' ' && c != '\t' && c != '\n' && c != '\r' {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// spaceMatch returns true if namespace a is the empty string
 | 
			
		||||
// or if namespace a equals namespace b.
 | 
			
		||||
func spaceMatch(a, b string) bool {
 | 
			
		||||
	switch {
 | 
			
		||||
	case a == "":
 | 
			
		||||
		return true
 | 
			
		||||
	default:
 | 
			
		||||
		return a == b
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// spaceDecompose breaks a namespace:tag identifier at the ':'
 | 
			
		||||
// and returns the two parts.
 | 
			
		||||
func spaceDecompose(str string) (space, key string) {
 | 
			
		||||
	colon := strings.IndexByte(str, ':')
 | 
			
		||||
	if colon == -1 {
 | 
			
		||||
		return "", str
 | 
			
		||||
	}
 | 
			
		||||
	return str[:colon], str[colon+1:]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Strings used by indentCRLF and indentLF
 | 
			
		||||
const (
 | 
			
		||||
	indentSpaces = "\r\n                                                                "
 | 
			
		||||
	indentTabs   = "\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// indentCRLF returns a CRLF newline followed by n copies of the first
 | 
			
		||||
// non-CRLF character in the source string.
 | 
			
		||||
func indentCRLF(n int, source string) string {
 | 
			
		||||
	switch {
 | 
			
		||||
	case n < 0:
 | 
			
		||||
		return source[:2]
 | 
			
		||||
	case n < len(source)-1:
 | 
			
		||||
		return source[:n+2]
 | 
			
		||||
	default:
 | 
			
		||||
		return source + strings.Repeat(source[2:3], n-len(source)+2)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// indentLF returns a LF newline followed by n copies of the first non-LF
 | 
			
		||||
// character in the source string.
 | 
			
		||||
func indentLF(n int, source string) string {
 | 
			
		||||
	switch {
 | 
			
		||||
	case n < 0:
 | 
			
		||||
		return source[1:2]
 | 
			
		||||
	case n < len(source)-1:
 | 
			
		||||
		return source[1 : n+2]
 | 
			
		||||
	default:
 | 
			
		||||
		return source[1:] + strings.Repeat(source[2:3], n-len(source)+2)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// nextIndex returns the index of the next occurrence of sep in s,
 | 
			
		||||
// starting from offset.  It returns -1 if the sep string is not found.
 | 
			
		||||
func nextIndex(s, sep string, offset int) int {
 | 
			
		||||
	switch i := strings.Index(s[offset:], sep); i {
 | 
			
		||||
	case -1:
 | 
			
		||||
		return -1
 | 
			
		||||
	default:
 | 
			
		||||
		return offset + i
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// isInteger returns true if the string s contains an integer.
 | 
			
		||||
func isInteger(s string) bool {
 | 
			
		||||
	for i := 0; i < len(s); i++ {
 | 
			
		||||
		if (s[i] < '0' || s[i] > '9') && !(i == 0 && s[i] == '-') {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type escapeMode byte
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	escapeNormal escapeMode = iota
 | 
			
		||||
	escapeCanonicalText
 | 
			
		||||
	escapeCanonicalAttr
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// escapeString writes an escaped version of a string to the writer.
 | 
			
		||||
func escapeString(w *bufio.Writer, s string, m escapeMode) {
 | 
			
		||||
	var esc []byte
 | 
			
		||||
	last := 0
 | 
			
		||||
	for i := 0; i < len(s); {
 | 
			
		||||
		r, width := utf8.DecodeRuneInString(s[i:])
 | 
			
		||||
		i += width
 | 
			
		||||
		switch r {
 | 
			
		||||
		case '&':
 | 
			
		||||
			esc = []byte("&")
 | 
			
		||||
		case '<':
 | 
			
		||||
			esc = []byte("<")
 | 
			
		||||
		case '>':
 | 
			
		||||
			if m == escapeCanonicalAttr {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			esc = []byte(">")
 | 
			
		||||
		case '\'':
 | 
			
		||||
			if m != escapeNormal {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			esc = []byte("'")
 | 
			
		||||
		case '"':
 | 
			
		||||
			if m == escapeCanonicalText {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			esc = []byte(""")
 | 
			
		||||
		case '\t':
 | 
			
		||||
			if m != escapeCanonicalAttr {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			esc = []byte("	")
 | 
			
		||||
		case '\n':
 | 
			
		||||
			if m != escapeCanonicalAttr {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			esc = []byte("
")
 | 
			
		||||
		case '\r':
 | 
			
		||||
			if m == escapeNormal {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			esc = []byte("
")
 | 
			
		||||
		default:
 | 
			
		||||
			if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) {
 | 
			
		||||
				esc = []byte("\uFFFD")
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		w.WriteString(s[last : i-width])
 | 
			
		||||
		w.Write(esc)
 | 
			
		||||
		last = i
 | 
			
		||||
	}
 | 
			
		||||
	w.WriteString(s[last:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isInCharacterRange(r rune) bool {
 | 
			
		||||
	return r == 0x09 ||
 | 
			
		||||
		r == 0x0A ||
 | 
			
		||||
		r == 0x0D ||
 | 
			
		||||
		r >= 0x20 && r <= 0xD7FF ||
 | 
			
		||||
		r >= 0xE000 && r <= 0xFFFD ||
 | 
			
		||||
		r >= 0x10000 && r <= 0x10FFFF
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										582
									
								
								vendor/github.com/beevik/etree/path.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										582
									
								
								vendor/github.com/beevik/etree/path.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,582 +0,0 @@
 | 
			
		||||
// Copyright 2015-2019 Brett Vickers.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package etree
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
A Path is a string that represents a search path through an etree starting
 | 
			
		||||
from the document root or an arbitrary element. Paths are used with the
 | 
			
		||||
Element object's Find* methods to locate and return desired elements.
 | 
			
		||||
 | 
			
		||||
A Path consists of a series of slash-separated "selectors", each of which may
 | 
			
		||||
be modified by one or more bracket-enclosed "filters". Selectors are used to
 | 
			
		||||
traverse the etree from element to element, while filters are used to narrow
 | 
			
		||||
the list of candidate elements at each node.
 | 
			
		||||
 | 
			
		||||
Although etree Path strings are similar to XPath strings
 | 
			
		||||
(https://www.w3.org/TR/1999/REC-xpath-19991116/), they have a more limited set
 | 
			
		||||
of selectors and filtering options.
 | 
			
		||||
 | 
			
		||||
The following selectors are supported by etree Path strings:
 | 
			
		||||
 | 
			
		||||
    .               Select the current element.
 | 
			
		||||
    ..              Select the parent of the current element.
 | 
			
		||||
    *               Select all child elements of the current element.
 | 
			
		||||
    /               Select the root element when used at the start of a path.
 | 
			
		||||
    //              Select all descendants of the current element.
 | 
			
		||||
    tag             Select all child elements with a name matching the tag.
 | 
			
		||||
 | 
			
		||||
The following basic filters are supported by etree Path strings:
 | 
			
		||||
 | 
			
		||||
    [@attrib]       Keep elements with an attribute named attrib.
 | 
			
		||||
    [@attrib='val'] Keep elements with an attribute named attrib and value matching val.
 | 
			
		||||
    [tag]           Keep elements with a child element named tag.
 | 
			
		||||
    [tag='val']     Keep elements with a child element named tag and text matching val.
 | 
			
		||||
    [n]             Keep the n-th element, where n is a numeric index starting from 1.
 | 
			
		||||
 | 
			
		||||
The following function filters are also supported:
 | 
			
		||||
 | 
			
		||||
    [text()]                    Keep elements with non-empty text.
 | 
			
		||||
    [text()='val']              Keep elements whose text matches val.
 | 
			
		||||
    [local-name()='val']        Keep elements whose un-prefixed tag matches val.
 | 
			
		||||
    [name()='val']              Keep elements whose full tag exactly matches val.
 | 
			
		||||
    [namespace-prefix()='val']  Keep elements whose namespace prefix matches val.
 | 
			
		||||
    [namespace-uri()='val']     Keep elements whose namespace URI matches val.
 | 
			
		||||
 | 
			
		||||
Here are some examples of Path strings:
 | 
			
		||||
 | 
			
		||||
- Select the bookstore child element of the root element:
 | 
			
		||||
    /bookstore
 | 
			
		||||
 | 
			
		||||
- Beginning from the root element, select the title elements of all
 | 
			
		||||
descendant book elements having a 'category' attribute of 'WEB':
 | 
			
		||||
    //book[@category='WEB']/title
 | 
			
		||||
 | 
			
		||||
- Beginning from the current element, select the first descendant
 | 
			
		||||
book element with a title child element containing the text 'Great
 | 
			
		||||
Expectations':
 | 
			
		||||
    .//book[title='Great Expectations'][1]
 | 
			
		||||
 | 
			
		||||
- Beginning from the current element, select all child elements of
 | 
			
		||||
book elements with an attribute 'language' set to 'english':
 | 
			
		||||
    ./book/*[@language='english']
 | 
			
		||||
 | 
			
		||||
- Beginning from the current element, select all child elements of
 | 
			
		||||
book elements containing the text 'special':
 | 
			
		||||
    ./book/*[text()='special']
 | 
			
		||||
 | 
			
		||||
- Beginning from the current element, select all descendant book
 | 
			
		||||
elements whose title child element has a 'language' attribute of 'french':
 | 
			
		||||
    .//book/title[@language='french']/..
 | 
			
		||||
 | 
			
		||||
- Beginning from the current element, select all book elements
 | 
			
		||||
belonging to the http://www.w3.org/TR/html4/ namespace:
 | 
			
		||||
	.//book[namespace-uri()='http://www.w3.org/TR/html4/']
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
type Path struct {
 | 
			
		||||
	segments []segment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ErrPath is returned by path functions when an invalid etree path is provided.
 | 
			
		||||
type ErrPath string
 | 
			
		||||
 | 
			
		||||
// Error returns the string describing a path error.
 | 
			
		||||
func (err ErrPath) Error() string {
 | 
			
		||||
	return "etree: " + string(err)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CompilePath creates an optimized version of an XPath-like string that
 | 
			
		||||
// can be used to query elements in an element tree.
 | 
			
		||||
func CompilePath(path string) (Path, error) {
 | 
			
		||||
	var comp compiler
 | 
			
		||||
	segments := comp.parsePath(path)
 | 
			
		||||
	if comp.err != ErrPath("") {
 | 
			
		||||
		return Path{nil}, comp.err
 | 
			
		||||
	}
 | 
			
		||||
	return Path{segments}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MustCompilePath creates an optimized version of an XPath-like string that
 | 
			
		||||
// can be used to query elements in an element tree.  Panics if an error
 | 
			
		||||
// occurs.  Use this function to create Paths when you know the path is
 | 
			
		||||
// valid (i.e., if it's hard-coded).
 | 
			
		||||
func MustCompilePath(path string) Path {
 | 
			
		||||
	p, err := CompilePath(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	return p
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A segment is a portion of a path between "/" characters.
 | 
			
		||||
// It contains one selector and zero or more [filters].
 | 
			
		||||
type segment struct {
 | 
			
		||||
	sel     selector
 | 
			
		||||
	filters []filter
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (seg *segment) apply(e *Element, p *pather) {
 | 
			
		||||
	seg.sel.apply(e, p)
 | 
			
		||||
	for _, f := range seg.filters {
 | 
			
		||||
		f.apply(p)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A selector selects XML elements for consideration by the
 | 
			
		||||
// path traversal.
 | 
			
		||||
type selector interface {
 | 
			
		||||
	apply(e *Element, p *pather)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A filter pares down a list of candidate XML elements based
 | 
			
		||||
// on a path filter in [brackets].
 | 
			
		||||
type filter interface {
 | 
			
		||||
	apply(p *pather)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A pather is helper object that traverses an element tree using
 | 
			
		||||
// a Path object.  It collects and deduplicates all elements matching
 | 
			
		||||
// the path query.
 | 
			
		||||
type pather struct {
 | 
			
		||||
	queue      fifo
 | 
			
		||||
	results    []*Element
 | 
			
		||||
	inResults  map[*Element]bool
 | 
			
		||||
	candidates []*Element
 | 
			
		||||
	scratch    []*Element // used by filters
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A node represents an element and the remaining path segments that
 | 
			
		||||
// should be applied against it by the pather.
 | 
			
		||||
type node struct {
 | 
			
		||||
	e        *Element
 | 
			
		||||
	segments []segment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newPather() *pather {
 | 
			
		||||
	return &pather{
 | 
			
		||||
		results:    make([]*Element, 0),
 | 
			
		||||
		inResults:  make(map[*Element]bool),
 | 
			
		||||
		candidates: make([]*Element, 0),
 | 
			
		||||
		scratch:    make([]*Element, 0),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// traverse follows the path from the element e, collecting
 | 
			
		||||
// and then returning all elements that match the path's selectors
 | 
			
		||||
// and filters.
 | 
			
		||||
func (p *pather) traverse(e *Element, path Path) []*Element {
 | 
			
		||||
	for p.queue.add(node{e, path.segments}); p.queue.len() > 0; {
 | 
			
		||||
		p.eval(p.queue.remove().(node))
 | 
			
		||||
	}
 | 
			
		||||
	return p.results
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// eval evalutes the current path node by applying the remaining
 | 
			
		||||
// path's selector rules against the node's element.
 | 
			
		||||
func (p *pather) eval(n node) {
 | 
			
		||||
	p.candidates = p.candidates[0:0]
 | 
			
		||||
	seg, remain := n.segments[0], n.segments[1:]
 | 
			
		||||
	seg.apply(n.e, p)
 | 
			
		||||
 | 
			
		||||
	if len(remain) == 0 {
 | 
			
		||||
		for _, c := range p.candidates {
 | 
			
		||||
			if in := p.inResults[c]; !in {
 | 
			
		||||
				p.inResults[c] = true
 | 
			
		||||
				p.results = append(p.results, c)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		for _, c := range p.candidates {
 | 
			
		||||
			p.queue.add(node{c, remain})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// A compiler generates a compiled path from a path string.
 | 
			
		||||
type compiler struct {
 | 
			
		||||
	err ErrPath
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parsePath parses an XPath-like string describing a path
 | 
			
		||||
// through an element tree and returns a slice of segment
 | 
			
		||||
// descriptors.
 | 
			
		||||
func (c *compiler) parsePath(path string) []segment {
 | 
			
		||||
	// If path ends with //, fix it
 | 
			
		||||
	if strings.HasSuffix(path, "//") {
 | 
			
		||||
		path = path + "*"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var segments []segment
 | 
			
		||||
 | 
			
		||||
	// Check for an absolute path
 | 
			
		||||
	if strings.HasPrefix(path, "/") {
 | 
			
		||||
		segments = append(segments, segment{new(selectRoot), []filter{}})
 | 
			
		||||
		path = path[1:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Split path into segments
 | 
			
		||||
	for _, s := range splitPath(path) {
 | 
			
		||||
		segments = append(segments, c.parseSegment(s))
 | 
			
		||||
		if c.err != ErrPath("") {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return segments
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func splitPath(path string) []string {
 | 
			
		||||
	pieces := make([]string, 0)
 | 
			
		||||
	start := 0
 | 
			
		||||
	inquote := false
 | 
			
		||||
	for i := 0; i+1 <= len(path); i++ {
 | 
			
		||||
		if path[i] == '\'' {
 | 
			
		||||
			inquote = !inquote
 | 
			
		||||
		} else if path[i] == '/' && !inquote {
 | 
			
		||||
			pieces = append(pieces, path[start:i])
 | 
			
		||||
			start = i + 1
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return append(pieces, path[start:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseSegment parses a path segment between / characters.
 | 
			
		||||
func (c *compiler) parseSegment(path string) segment {
 | 
			
		||||
	pieces := strings.Split(path, "[")
 | 
			
		||||
	seg := segment{
 | 
			
		||||
		sel:     c.parseSelector(pieces[0]),
 | 
			
		||||
		filters: []filter{},
 | 
			
		||||
	}
 | 
			
		||||
	for i := 1; i < len(pieces); i++ {
 | 
			
		||||
		fpath := pieces[i]
 | 
			
		||||
		if fpath[len(fpath)-1] != ']' {
 | 
			
		||||
			c.err = ErrPath("path has invalid filter [brackets].")
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		seg.filters = append(seg.filters, c.parseFilter(fpath[:len(fpath)-1]))
 | 
			
		||||
	}
 | 
			
		||||
	return seg
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseSelector parses a selector at the start of a path segment.
 | 
			
		||||
func (c *compiler) parseSelector(path string) selector {
 | 
			
		||||
	switch path {
 | 
			
		||||
	case ".":
 | 
			
		||||
		return new(selectSelf)
 | 
			
		||||
	case "..":
 | 
			
		||||
		return new(selectParent)
 | 
			
		||||
	case "*":
 | 
			
		||||
		return new(selectChildren)
 | 
			
		||||
	case "":
 | 
			
		||||
		return new(selectDescendants)
 | 
			
		||||
	default:
 | 
			
		||||
		return newSelectChildrenByTag(path)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var fnTable = map[string]struct {
 | 
			
		||||
	hasFn    func(e *Element) bool
 | 
			
		||||
	getValFn func(e *Element) string
 | 
			
		||||
}{
 | 
			
		||||
	"local-name":       {nil, (*Element).name},
 | 
			
		||||
	"name":             {nil, (*Element).FullTag},
 | 
			
		||||
	"namespace-prefix": {nil, (*Element).namespacePrefix},
 | 
			
		||||
	"namespace-uri":    {nil, (*Element).NamespaceURI},
 | 
			
		||||
	"text":             {(*Element).hasText, (*Element).Text},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseFilter parses a path filter contained within [brackets].
 | 
			
		||||
func (c *compiler) parseFilter(path string) filter {
 | 
			
		||||
	if len(path) == 0 {
 | 
			
		||||
		c.err = ErrPath("path contains an empty filter expression.")
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Filter contains [@attr='val'], [fn()='val'], or [tag='val']?
 | 
			
		||||
	eqindex := strings.Index(path, "='")
 | 
			
		||||
	if eqindex >= 0 {
 | 
			
		||||
		rindex := nextIndex(path, "'", eqindex+2)
 | 
			
		||||
		if rindex != len(path)-1 {
 | 
			
		||||
			c.err = ErrPath("path has mismatched filter quotes.")
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		key := path[:eqindex]
 | 
			
		||||
		value := path[eqindex+2 : rindex]
 | 
			
		||||
 | 
			
		||||
		switch {
 | 
			
		||||
		case key[0] == '@':
 | 
			
		||||
			return newFilterAttrVal(key[1:], value)
 | 
			
		||||
		case strings.HasSuffix(key, "()"):
 | 
			
		||||
			fn := key[:len(key)-2]
 | 
			
		||||
			if t, ok := fnTable[fn]; ok && t.getValFn != nil {
 | 
			
		||||
				return newFilterFuncVal(t.getValFn, value)
 | 
			
		||||
			}
 | 
			
		||||
			c.err = ErrPath("path has unknown function " + fn)
 | 
			
		||||
			return nil
 | 
			
		||||
		default:
 | 
			
		||||
			return newFilterChildText(key, value)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Filter contains [@attr], [N], [tag] or [fn()]
 | 
			
		||||
	switch {
 | 
			
		||||
	case path[0] == '@':
 | 
			
		||||
		return newFilterAttr(path[1:])
 | 
			
		||||
	case strings.HasSuffix(path, "()"):
 | 
			
		||||
		fn := path[:len(path)-2]
 | 
			
		||||
		if t, ok := fnTable[fn]; ok && t.hasFn != nil {
 | 
			
		||||
			return newFilterFunc(t.hasFn)
 | 
			
		||||
		}
 | 
			
		||||
		c.err = ErrPath("path has unknown function " + fn)
 | 
			
		||||
		return nil
 | 
			
		||||
	case isInteger(path):
 | 
			
		||||
		pos, _ := strconv.Atoi(path)
 | 
			
		||||
		switch {
 | 
			
		||||
		case pos > 0:
 | 
			
		||||
			return newFilterPos(pos - 1)
 | 
			
		||||
		default:
 | 
			
		||||
			return newFilterPos(pos)
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		return newFilterChild(path)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// selectSelf selects the current element into the candidate list.
 | 
			
		||||
type selectSelf struct{}
 | 
			
		||||
 | 
			
		||||
func (s *selectSelf) apply(e *Element, p *pather) {
 | 
			
		||||
	p.candidates = append(p.candidates, e)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// selectRoot selects the element's root node.
 | 
			
		||||
type selectRoot struct{}
 | 
			
		||||
 | 
			
		||||
func (s *selectRoot) apply(e *Element, p *pather) {
 | 
			
		||||
	root := e
 | 
			
		||||
	for root.parent != nil {
 | 
			
		||||
		root = root.parent
 | 
			
		||||
	}
 | 
			
		||||
	p.candidates = append(p.candidates, root)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// selectParent selects the element's parent into the candidate list.
 | 
			
		||||
type selectParent struct{}
 | 
			
		||||
 | 
			
		||||
func (s *selectParent) apply(e *Element, p *pather) {
 | 
			
		||||
	if e.parent != nil {
 | 
			
		||||
		p.candidates = append(p.candidates, e.parent)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// selectChildren selects the element's child elements into the
 | 
			
		||||
// candidate list.
 | 
			
		||||
type selectChildren struct{}
 | 
			
		||||
 | 
			
		||||
func (s *selectChildren) apply(e *Element, p *pather) {
 | 
			
		||||
	for _, c := range e.Child {
 | 
			
		||||
		if c, ok := c.(*Element); ok {
 | 
			
		||||
			p.candidates = append(p.candidates, c)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// selectDescendants selects all descendant child elements
 | 
			
		||||
// of the element into the candidate list.
 | 
			
		||||
type selectDescendants struct{}
 | 
			
		||||
 | 
			
		||||
func (s *selectDescendants) apply(e *Element, p *pather) {
 | 
			
		||||
	var queue fifo
 | 
			
		||||
	for queue.add(e); queue.len() > 0; {
 | 
			
		||||
		e := queue.remove().(*Element)
 | 
			
		||||
		p.candidates = append(p.candidates, e)
 | 
			
		||||
		for _, c := range e.Child {
 | 
			
		||||
			if c, ok := c.(*Element); ok {
 | 
			
		||||
				queue.add(c)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// selectChildrenByTag selects into the candidate list all child
 | 
			
		||||
// elements of the element having the specified tag.
 | 
			
		||||
type selectChildrenByTag struct {
 | 
			
		||||
	space, tag string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newSelectChildrenByTag(path string) *selectChildrenByTag {
 | 
			
		||||
	s, l := spaceDecompose(path)
 | 
			
		||||
	return &selectChildrenByTag{s, l}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *selectChildrenByTag) apply(e *Element, p *pather) {
 | 
			
		||||
	for _, c := range e.Child {
 | 
			
		||||
		if c, ok := c.(*Element); ok && spaceMatch(s.space, c.Space) && s.tag == c.Tag {
 | 
			
		||||
			p.candidates = append(p.candidates, c)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// filterPos filters the candidate list, keeping only the
 | 
			
		||||
// candidate at the specified index.
 | 
			
		||||
type filterPos struct {
 | 
			
		||||
	index int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newFilterPos(pos int) *filterPos {
 | 
			
		||||
	return &filterPos{pos}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *filterPos) apply(p *pather) {
 | 
			
		||||
	if f.index >= 0 {
 | 
			
		||||
		if f.index < len(p.candidates) {
 | 
			
		||||
			p.scratch = append(p.scratch, p.candidates[f.index])
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if -f.index <= len(p.candidates) {
 | 
			
		||||
			p.scratch = append(p.scratch, p.candidates[len(p.candidates)+f.index])
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p.candidates, p.scratch = p.scratch, p.candidates[0:0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// filterAttr filters the candidate list for elements having
 | 
			
		||||
// the specified attribute.
 | 
			
		||||
type filterAttr struct {
 | 
			
		||||
	space, key string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newFilterAttr(str string) *filterAttr {
 | 
			
		||||
	s, l := spaceDecompose(str)
 | 
			
		||||
	return &filterAttr{s, l}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *filterAttr) apply(p *pather) {
 | 
			
		||||
	for _, c := range p.candidates {
 | 
			
		||||
		for _, a := range c.Attr {
 | 
			
		||||
			if spaceMatch(f.space, a.Space) && f.key == a.Key {
 | 
			
		||||
				p.scratch = append(p.scratch, c)
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p.candidates, p.scratch = p.scratch, p.candidates[0:0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// filterAttrVal filters the candidate list for elements having
 | 
			
		||||
// the specified attribute with the specified value.
 | 
			
		||||
type filterAttrVal struct {
 | 
			
		||||
	space, key, val string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newFilterAttrVal(str, value string) *filterAttrVal {
 | 
			
		||||
	s, l := spaceDecompose(str)
 | 
			
		||||
	return &filterAttrVal{s, l, value}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *filterAttrVal) apply(p *pather) {
 | 
			
		||||
	for _, c := range p.candidates {
 | 
			
		||||
		for _, a := range c.Attr {
 | 
			
		||||
			if spaceMatch(f.space, a.Space) && f.key == a.Key && f.val == a.Value {
 | 
			
		||||
				p.scratch = append(p.scratch, c)
 | 
			
		||||
				break
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p.candidates, p.scratch = p.scratch, p.candidates[0:0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// filterFunc filters the candidate list for elements satisfying a custom
 | 
			
		||||
// boolean function.
 | 
			
		||||
type filterFunc struct {
 | 
			
		||||
	fn func(e *Element) bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newFilterFunc(fn func(e *Element) bool) *filterFunc {
 | 
			
		||||
	return &filterFunc{fn}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *filterFunc) apply(p *pather) {
 | 
			
		||||
	for _, c := range p.candidates {
 | 
			
		||||
		if f.fn(c) {
 | 
			
		||||
			p.scratch = append(p.scratch, c)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p.candidates, p.scratch = p.scratch, p.candidates[0:0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// filterFuncVal filters the candidate list for elements containing a value
 | 
			
		||||
// matching the result of a custom function.
 | 
			
		||||
type filterFuncVal struct {
 | 
			
		||||
	fn  func(e *Element) string
 | 
			
		||||
	val string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newFilterFuncVal(fn func(e *Element) string, value string) *filterFuncVal {
 | 
			
		||||
	return &filterFuncVal{fn, value}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *filterFuncVal) apply(p *pather) {
 | 
			
		||||
	for _, c := range p.candidates {
 | 
			
		||||
		if f.fn(c) == f.val {
 | 
			
		||||
			p.scratch = append(p.scratch, c)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p.candidates, p.scratch = p.scratch, p.candidates[0:0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// filterChild filters the candidate list for elements having
 | 
			
		||||
// a child element with the specified tag.
 | 
			
		||||
type filterChild struct {
 | 
			
		||||
	space, tag string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newFilterChild(str string) *filterChild {
 | 
			
		||||
	s, l := spaceDecompose(str)
 | 
			
		||||
	return &filterChild{s, l}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *filterChild) apply(p *pather) {
 | 
			
		||||
	for _, c := range p.candidates {
 | 
			
		||||
		for _, cc := range c.Child {
 | 
			
		||||
			if cc, ok := cc.(*Element); ok &&
 | 
			
		||||
				spaceMatch(f.space, cc.Space) &&
 | 
			
		||||
				f.tag == cc.Tag {
 | 
			
		||||
				p.scratch = append(p.scratch, c)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p.candidates, p.scratch = p.scratch, p.candidates[0:0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// filterChildText filters the candidate list for elements having
 | 
			
		||||
// a child element with the specified tag and text.
 | 
			
		||||
type filterChildText struct {
 | 
			
		||||
	space, tag, text string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newFilterChildText(str, text string) *filterChildText {
 | 
			
		||||
	s, l := spaceDecompose(str)
 | 
			
		||||
	return &filterChildText{s, l, text}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f *filterChildText) apply(p *pather) {
 | 
			
		||||
	for _, c := range p.candidates {
 | 
			
		||||
		for _, cc := range c.Child {
 | 
			
		||||
			if cc, ok := cc.(*Element); ok &&
 | 
			
		||||
				spaceMatch(f.space, cc.Space) &&
 | 
			
		||||
				f.tag == cc.Tag &&
 | 
			
		||||
				f.text == cc.Text() {
 | 
			
		||||
				p.scratch = append(p.scratch, c)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	p.candidates, p.scratch = p.scratch, p.candidates[0:0]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/beorn7/perks/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/beorn7/perks/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,20 +0,0 @@
 | 
			
		||||
Copyright (C) 2013 Blake Mizerany
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining
 | 
			
		||||
a copy of this software and associated documentation files (the
 | 
			
		||||
"Software"), to deal in the Software without restriction, including
 | 
			
		||||
without limitation the rights to use, copy, modify, merge, publish,
 | 
			
		||||
distribute, sublicense, and/or sell copies of the Software, and to
 | 
			
		||||
permit persons to whom the Software is furnished to do so, subject to
 | 
			
		||||
the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be
 | 
			
		||||
included in all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
			
		||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 | 
			
		||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | 
			
		||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | 
			
		||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
							
								
								
									
										2388
									
								
								vendor/github.com/beorn7/perks/quantile/exampledata.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2388
									
								
								vendor/github.com/beorn7/perks/quantile/exampledata.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										316
									
								
								vendor/github.com/beorn7/perks/quantile/stream.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										316
									
								
								vendor/github.com/beorn7/perks/quantile/stream.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,316 +0,0 @@
 | 
			
		||||
// Package quantile computes approximate quantiles over an unbounded data
 | 
			
		||||
// stream within low memory and CPU bounds.
 | 
			
		||||
//
 | 
			
		||||
// A small amount of accuracy is traded to achieve the above properties.
 | 
			
		||||
//
 | 
			
		||||
// Multiple streams can be merged before calling Query to generate a single set
 | 
			
		||||
// of results. This is meaningful when the streams represent the same type of
 | 
			
		||||
// data. See Merge and Samples.
 | 
			
		||||
//
 | 
			
		||||
// For more detailed information about the algorithm used, see:
 | 
			
		||||
//
 | 
			
		||||
// Effective Computation of Biased Quantiles over Data Streams
 | 
			
		||||
//
 | 
			
		||||
// http://www.cs.rutgers.edu/~muthu/bquant.pdf
 | 
			
		||||
package quantile
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"math"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Sample holds an observed value and meta information for compression. JSON
 | 
			
		||||
// tags have been added for convenience.
 | 
			
		||||
type Sample struct {
 | 
			
		||||
	Value float64 `json:",string"`
 | 
			
		||||
	Width float64 `json:",string"`
 | 
			
		||||
	Delta float64 `json:",string"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Samples represents a slice of samples. It implements sort.Interface.
 | 
			
		||||
type Samples []Sample
 | 
			
		||||
 | 
			
		||||
func (a Samples) Len() int           { return len(a) }
 | 
			
		||||
func (a Samples) Less(i, j int) bool { return a[i].Value < a[j].Value }
 | 
			
		||||
func (a Samples) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
 | 
			
		||||
 | 
			
		||||
type invariant func(s *stream, r float64) float64
 | 
			
		||||
 | 
			
		||||
// NewLowBiased returns an initialized Stream for low-biased quantiles
 | 
			
		||||
// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
 | 
			
		||||
// error guarantees can still be given even for the lower ranks of the data
 | 
			
		||||
// distribution.
 | 
			
		||||
//
 | 
			
		||||
// The provided epsilon is a relative error, i.e. the true quantile of a value
 | 
			
		||||
// returned by a query is guaranteed to be within (1±Epsilon)*Quantile.
 | 
			
		||||
//
 | 
			
		||||
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
 | 
			
		||||
// properties.
 | 
			
		||||
func NewLowBiased(epsilon float64) *Stream {
 | 
			
		||||
	ƒ := func(s *stream, r float64) float64 {
 | 
			
		||||
		return 2 * epsilon * r
 | 
			
		||||
	}
 | 
			
		||||
	return newStream(ƒ)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewHighBiased returns an initialized Stream for high-biased quantiles
 | 
			
		||||
// (e.g. 0.01, 0.1, 0.5) where the needed quantiles are not known a priori, but
 | 
			
		||||
// error guarantees can still be given even for the higher ranks of the data
 | 
			
		||||
// distribution.
 | 
			
		||||
//
 | 
			
		||||
// The provided epsilon is a relative error, i.e. the true quantile of a value
 | 
			
		||||
// returned by a query is guaranteed to be within 1-(1±Epsilon)*(1-Quantile).
 | 
			
		||||
//
 | 
			
		||||
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error
 | 
			
		||||
// properties.
 | 
			
		||||
func NewHighBiased(epsilon float64) *Stream {
 | 
			
		||||
	ƒ := func(s *stream, r float64) float64 {
 | 
			
		||||
		return 2 * epsilon * (s.n - r)
 | 
			
		||||
	}
 | 
			
		||||
	return newStream(ƒ)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewTargeted returns an initialized Stream concerned with a particular set of
 | 
			
		||||
// quantile values that are supplied a priori. Knowing these a priori reduces
 | 
			
		||||
// space and computation time. The targets map maps the desired quantiles to
 | 
			
		||||
// their absolute errors, i.e. the true quantile of a value returned by a query
 | 
			
		||||
// is guaranteed to be within (Quantile±Epsilon).
 | 
			
		||||
//
 | 
			
		||||
// See http://www.cs.rutgers.edu/~muthu/bquant.pdf for time, space, and error properties.
 | 
			
		||||
func NewTargeted(targetMap map[float64]float64) *Stream {
 | 
			
		||||
	// Convert map to slice to avoid slow iterations on a map.
 | 
			
		||||
	// ƒ is called on the hot path, so converting the map to a slice
 | 
			
		||||
	// beforehand results in significant CPU savings.
 | 
			
		||||
	targets := targetMapToSlice(targetMap)
 | 
			
		||||
 | 
			
		||||
	ƒ := func(s *stream, r float64) float64 {
 | 
			
		||||
		var m = math.MaxFloat64
 | 
			
		||||
		var f float64
 | 
			
		||||
		for _, t := range targets {
 | 
			
		||||
			if t.quantile*s.n <= r {
 | 
			
		||||
				f = (2 * t.epsilon * r) / t.quantile
 | 
			
		||||
			} else {
 | 
			
		||||
				f = (2 * t.epsilon * (s.n - r)) / (1 - t.quantile)
 | 
			
		||||
			}
 | 
			
		||||
			if f < m {
 | 
			
		||||
				m = f
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return m
 | 
			
		||||
	}
 | 
			
		||||
	return newStream(ƒ)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type target struct {
 | 
			
		||||
	quantile float64
 | 
			
		||||
	epsilon  float64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func targetMapToSlice(targetMap map[float64]float64) []target {
 | 
			
		||||
	targets := make([]target, 0, len(targetMap))
 | 
			
		||||
 | 
			
		||||
	for quantile, epsilon := range targetMap {
 | 
			
		||||
		t := target{
 | 
			
		||||
			quantile: quantile,
 | 
			
		||||
			epsilon:  epsilon,
 | 
			
		||||
		}
 | 
			
		||||
		targets = append(targets, t)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return targets
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Stream computes quantiles for a stream of float64s. It is not thread-safe by
 | 
			
		||||
// design. Take care when using across multiple goroutines.
 | 
			
		||||
type Stream struct {
 | 
			
		||||
	*stream
 | 
			
		||||
	b      Samples
 | 
			
		||||
	sorted bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newStream(ƒ invariant) *Stream {
 | 
			
		||||
	x := &stream{ƒ: ƒ}
 | 
			
		||||
	return &Stream{x, make(Samples, 0, 500), true}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Insert inserts v into the stream.
 | 
			
		||||
func (s *Stream) Insert(v float64) {
 | 
			
		||||
	s.insert(Sample{Value: v, Width: 1})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Stream) insert(sample Sample) {
 | 
			
		||||
	s.b = append(s.b, sample)
 | 
			
		||||
	s.sorted = false
 | 
			
		||||
	if len(s.b) == cap(s.b) {
 | 
			
		||||
		s.flush()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Query returns the computed qth percentiles value. If s was created with
 | 
			
		||||
// NewTargeted, and q is not in the set of quantiles provided a priori, Query
 | 
			
		||||
// will return an unspecified result.
 | 
			
		||||
func (s *Stream) Query(q float64) float64 {
 | 
			
		||||
	if !s.flushed() {
 | 
			
		||||
		// Fast path when there hasn't been enough data for a flush;
 | 
			
		||||
		// this also yields better accuracy for small sets of data.
 | 
			
		||||
		l := len(s.b)
 | 
			
		||||
		if l == 0 {
 | 
			
		||||
			return 0
 | 
			
		||||
		}
 | 
			
		||||
		i := int(math.Ceil(float64(l) * q))
 | 
			
		||||
		if i > 0 {
 | 
			
		||||
			i -= 1
 | 
			
		||||
		}
 | 
			
		||||
		s.maybeSort()
 | 
			
		||||
		return s.b[i].Value
 | 
			
		||||
	}
 | 
			
		||||
	s.flush()
 | 
			
		||||
	return s.stream.query(q)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Merge merges samples into the underlying streams samples. This is handy when
 | 
			
		||||
// merging multiple streams from separate threads, database shards, etc.
 | 
			
		||||
//
 | 
			
		||||
// ATTENTION: This method is broken and does not yield correct results. The
 | 
			
		||||
// underlying algorithm is not capable of merging streams correctly.
 | 
			
		||||
func (s *Stream) Merge(samples Samples) {
 | 
			
		||||
	sort.Sort(samples)
 | 
			
		||||
	s.stream.merge(samples)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reset reinitializes and clears the list reusing the samples buffer memory.
 | 
			
		||||
func (s *Stream) Reset() {
 | 
			
		||||
	s.stream.reset()
 | 
			
		||||
	s.b = s.b[:0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Samples returns stream samples held by s.
 | 
			
		||||
func (s *Stream) Samples() Samples {
 | 
			
		||||
	if !s.flushed() {
 | 
			
		||||
		return s.b
 | 
			
		||||
	}
 | 
			
		||||
	s.flush()
 | 
			
		||||
	return s.stream.samples()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Count returns the total number of samples observed in the stream
 | 
			
		||||
// since initialization.
 | 
			
		||||
func (s *Stream) Count() int {
 | 
			
		||||
	return len(s.b) + s.stream.count()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Stream) flush() {
 | 
			
		||||
	s.maybeSort()
 | 
			
		||||
	s.stream.merge(s.b)
 | 
			
		||||
	s.b = s.b[:0]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Stream) maybeSort() {
 | 
			
		||||
	if !s.sorted {
 | 
			
		||||
		s.sorted = true
 | 
			
		||||
		sort.Sort(s.b)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Stream) flushed() bool {
 | 
			
		||||
	return len(s.stream.l) > 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type stream struct {
 | 
			
		||||
	n float64
 | 
			
		||||
	l []Sample
 | 
			
		||||
	ƒ invariant
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stream) reset() {
 | 
			
		||||
	s.l = s.l[:0]
 | 
			
		||||
	s.n = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stream) insert(v float64) {
 | 
			
		||||
	s.merge(Samples{{v, 1, 0}})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stream) merge(samples Samples) {
 | 
			
		||||
	// TODO(beorn7): This tries to merge not only individual samples, but
 | 
			
		||||
	// whole summaries. The paper doesn't mention merging summaries at
 | 
			
		||||
	// all. Unittests show that the merging is inaccurate. Find out how to
 | 
			
		||||
	// do merges properly.
 | 
			
		||||
	var r float64
 | 
			
		||||
	i := 0
 | 
			
		||||
	for _, sample := range samples {
 | 
			
		||||
		for ; i < len(s.l); i++ {
 | 
			
		||||
			c := s.l[i]
 | 
			
		||||
			if c.Value > sample.Value {
 | 
			
		||||
				// Insert at position i.
 | 
			
		||||
				s.l = append(s.l, Sample{})
 | 
			
		||||
				copy(s.l[i+1:], s.l[i:])
 | 
			
		||||
				s.l[i] = Sample{
 | 
			
		||||
					sample.Value,
 | 
			
		||||
					sample.Width,
 | 
			
		||||
					math.Max(sample.Delta, math.Floor(s.ƒ(s, r))-1),
 | 
			
		||||
					// TODO(beorn7): How to calculate delta correctly?
 | 
			
		||||
				}
 | 
			
		||||
				i++
 | 
			
		||||
				goto inserted
 | 
			
		||||
			}
 | 
			
		||||
			r += c.Width
 | 
			
		||||
		}
 | 
			
		||||
		s.l = append(s.l, Sample{sample.Value, sample.Width, 0})
 | 
			
		||||
		i++
 | 
			
		||||
	inserted:
 | 
			
		||||
		s.n += sample.Width
 | 
			
		||||
		r += sample.Width
 | 
			
		||||
	}
 | 
			
		||||
	s.compress()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stream) count() int {
 | 
			
		||||
	return int(s.n)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stream) query(q float64) float64 {
 | 
			
		||||
	t := math.Ceil(q * s.n)
 | 
			
		||||
	t += math.Ceil(s.ƒ(s, t) / 2)
 | 
			
		||||
	p := s.l[0]
 | 
			
		||||
	var r float64
 | 
			
		||||
	for _, c := range s.l[1:] {
 | 
			
		||||
		r += p.Width
 | 
			
		||||
		if r+c.Width+c.Delta > t {
 | 
			
		||||
			return p.Value
 | 
			
		||||
		}
 | 
			
		||||
		p = c
 | 
			
		||||
	}
 | 
			
		||||
	return p.Value
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stream) compress() {
 | 
			
		||||
	if len(s.l) < 2 {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	x := s.l[len(s.l)-1]
 | 
			
		||||
	xi := len(s.l) - 1
 | 
			
		||||
	r := s.n - 1 - x.Width
 | 
			
		||||
 | 
			
		||||
	for i := len(s.l) - 2; i >= 0; i-- {
 | 
			
		||||
		c := s.l[i]
 | 
			
		||||
		if c.Width+x.Width+x.Delta <= s.ƒ(s, r) {
 | 
			
		||||
			x.Width += c.Width
 | 
			
		||||
			s.l[xi] = x
 | 
			
		||||
			// Remove element at i.
 | 
			
		||||
			copy(s.l[i:], s.l[i+1:])
 | 
			
		||||
			s.l = s.l[:len(s.l)-1]
 | 
			
		||||
			xi -= 1
 | 
			
		||||
		} else {
 | 
			
		||||
			x = c
 | 
			
		||||
			xi = i
 | 
			
		||||
		}
 | 
			
		||||
		r -= c.Width
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *stream) samples() Samples {
 | 
			
		||||
	samples := make(Samples, len(s.l))
 | 
			
		||||
	copy(samples, s.l)
 | 
			
		||||
	return samples
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/cenkalti/backoff/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/cenkalti/backoff/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,22 +0,0 @@
 | 
			
		||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
 | 
			
		||||
*.o
 | 
			
		||||
*.a
 | 
			
		||||
*.so
 | 
			
		||||
 | 
			
		||||
# Folders
 | 
			
		||||
_obj
 | 
			
		||||
_test
 | 
			
		||||
 | 
			
		||||
# Architecture specific extensions/prefixes
 | 
			
		||||
*.[568vq]
 | 
			
		||||
[568vq].out
 | 
			
		||||
 | 
			
		||||
*.cgo1.go
 | 
			
		||||
*.cgo2.c
 | 
			
		||||
_cgo_defun.c
 | 
			
		||||
_cgo_gotypes.go
 | 
			
		||||
_cgo_export.*
 | 
			
		||||
 | 
			
		||||
_testmain.go
 | 
			
		||||
 | 
			
		||||
*.exe
 | 
			
		||||
							
								
								
									
										10
									
								
								vendor/github.com/cenkalti/backoff/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/cenkalti/backoff/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,10 +0,0 @@
 | 
			
		||||
language: go
 | 
			
		||||
go:
 | 
			
		||||
  - 1.7
 | 
			
		||||
  - 1.x
 | 
			
		||||
  - tip
 | 
			
		||||
before_install:
 | 
			
		||||
  - go get github.com/mattn/goveralls
 | 
			
		||||
  - go get golang.org/x/tools/cmd/cover
 | 
			
		||||
script:
 | 
			
		||||
  - $HOME/gopath/bin/goveralls -service=travis-ci
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/github.com/cenkalti/backoff/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/cenkalti/backoff/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,20 +0,0 @@
 | 
			
		||||
The MIT License (MIT)
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2014 Cenk Altı
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
			
		||||
this software and associated documentation files (the "Software"), to deal in
 | 
			
		||||
the Software without restriction, including without limitation the rights to
 | 
			
		||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 | 
			
		||||
the Software, and to permit persons to whom the Software is furnished to do so,
 | 
			
		||||
subject to the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 | 
			
		||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 | 
			
		||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
			
		||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
							
								
								
									
										30
									
								
								vendor/github.com/cenkalti/backoff/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										30
									
								
								vendor/github.com/cenkalti/backoff/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,30 +0,0 @@
 | 
			
		||||
# Exponential Backoff [![GoDoc][godoc image]][godoc] [![Build Status][travis image]][travis] [![Coverage Status][coveralls image]][coveralls]
 | 
			
		||||
 | 
			
		||||
This is a Go port of the exponential backoff algorithm from [Google's HTTP Client Library for Java][google-http-java-client].
 | 
			
		||||
 | 
			
		||||
[Exponential backoff][exponential backoff wiki]
 | 
			
		||||
is an algorithm that uses feedback to multiplicatively decrease the rate of some process,
 | 
			
		||||
in order to gradually find an acceptable rate.
 | 
			
		||||
The retries exponentially increase and stop increasing when a certain threshold is met.
 | 
			
		||||
 | 
			
		||||
## Usage
 | 
			
		||||
 | 
			
		||||
See https://godoc.org/github.com/cenkalti/backoff#pkg-examples
 | 
			
		||||
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
* I would like to keep this library as small as possible.
 | 
			
		||||
* Please don't send a PR without opening an issue and discussing it first.
 | 
			
		||||
* If proposed change is not a common use case, I will probably not accept it.
 | 
			
		||||
 | 
			
		||||
[godoc]: https://godoc.org/github.com/cenkalti/backoff
 | 
			
		||||
[godoc image]: https://godoc.org/github.com/cenkalti/backoff?status.png
 | 
			
		||||
[travis]: https://travis-ci.org/cenkalti/backoff
 | 
			
		||||
[travis image]: https://travis-ci.org/cenkalti/backoff.png?branch=master
 | 
			
		||||
[coveralls]: https://coveralls.io/github/cenkalti/backoff?branch=master
 | 
			
		||||
[coveralls image]: https://coveralls.io/repos/github/cenkalti/backoff/badge.svg?branch=master
 | 
			
		||||
 | 
			
		||||
[google-http-java-client]: https://github.com/google/google-http-java-client/blob/da1aa993e90285ec18579f1553339b00e19b3ab5/google-http-client/src/main/java/com/google/api/client/util/ExponentialBackOff.java
 | 
			
		||||
[exponential backoff wiki]: http://en.wikipedia.org/wiki/Exponential_backoff
 | 
			
		||||
 | 
			
		||||
[advanced example]: https://godoc.org/github.com/cenkalti/backoff#example_
 | 
			
		||||
							
								
								
									
										66
									
								
								vendor/github.com/cenkalti/backoff/backoff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										66
									
								
								vendor/github.com/cenkalti/backoff/backoff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,66 +0,0 @@
 | 
			
		||||
// Package backoff implements backoff algorithms for retrying operations.
 | 
			
		||||
//
 | 
			
		||||
// Use Retry function for retrying operations that may fail.
 | 
			
		||||
// If Retry does not meet your needs,
 | 
			
		||||
// copy/paste the function into your project and modify as you wish.
 | 
			
		||||
//
 | 
			
		||||
// There is also Ticker type similar to time.Ticker.
 | 
			
		||||
// You can use it if you need to work with channels.
 | 
			
		||||
//
 | 
			
		||||
// See Examples section below for usage examples.
 | 
			
		||||
package backoff
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
// BackOff is a backoff policy for retrying an operation.
 | 
			
		||||
type BackOff interface {
 | 
			
		||||
	// NextBackOff returns the duration to wait before retrying the operation,
 | 
			
		||||
	// or backoff. Stop to indicate that no more retries should be made.
 | 
			
		||||
	//
 | 
			
		||||
	// Example usage:
 | 
			
		||||
	//
 | 
			
		||||
	// 	duration := backoff.NextBackOff();
 | 
			
		||||
	// 	if (duration == backoff.Stop) {
 | 
			
		||||
	// 		// Do not retry operation.
 | 
			
		||||
	// 	} else {
 | 
			
		||||
	// 		// Sleep for duration and retry operation.
 | 
			
		||||
	// 	}
 | 
			
		||||
	//
 | 
			
		||||
	NextBackOff() time.Duration
 | 
			
		||||
 | 
			
		||||
	// Reset to initial state.
 | 
			
		||||
	Reset()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Stop indicates that no more retries should be made for use in NextBackOff().
 | 
			
		||||
const Stop time.Duration = -1
 | 
			
		||||
 | 
			
		||||
// ZeroBackOff is a fixed backoff policy whose backoff time is always zero,
 | 
			
		||||
// meaning that the operation is retried immediately without waiting, indefinitely.
 | 
			
		||||
type ZeroBackOff struct{}
 | 
			
		||||
 | 
			
		||||
func (b *ZeroBackOff) Reset() {}
 | 
			
		||||
 | 
			
		||||
func (b *ZeroBackOff) NextBackOff() time.Duration { return 0 }
 | 
			
		||||
 | 
			
		||||
// StopBackOff is a fixed backoff policy that always returns backoff.Stop for
 | 
			
		||||
// NextBackOff(), meaning that the operation should never be retried.
 | 
			
		||||
type StopBackOff struct{}
 | 
			
		||||
 | 
			
		||||
func (b *StopBackOff) Reset() {}
 | 
			
		||||
 | 
			
		||||
func (b *StopBackOff) NextBackOff() time.Duration { return Stop }
 | 
			
		||||
 | 
			
		||||
// ConstantBackOff is a backoff policy that always returns the same backoff delay.
 | 
			
		||||
// This is in contrast to an exponential backoff policy,
 | 
			
		||||
// which returns a delay that grows longer as you call NextBackOff() over and over again.
 | 
			
		||||
type ConstantBackOff struct {
 | 
			
		||||
	Interval time.Duration
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *ConstantBackOff) Reset()                     {}
 | 
			
		||||
func (b *ConstantBackOff) NextBackOff() time.Duration { return b.Interval }
 | 
			
		||||
 | 
			
		||||
func NewConstantBackOff(d time.Duration) *ConstantBackOff {
 | 
			
		||||
	return &ConstantBackOff{Interval: d}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										63
									
								
								vendor/github.com/cenkalti/backoff/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										63
									
								
								vendor/github.com/cenkalti/backoff/context.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,63 +0,0 @@
 | 
			
		||||
package backoff
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// BackOffContext is a backoff policy that stops retrying after the context
 | 
			
		||||
// is canceled.
 | 
			
		||||
type BackOffContext interface {
 | 
			
		||||
	BackOff
 | 
			
		||||
	Context() context.Context
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type backOffContext struct {
 | 
			
		||||
	BackOff
 | 
			
		||||
	ctx context.Context
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithContext returns a BackOffContext with context ctx
 | 
			
		||||
//
 | 
			
		||||
// ctx must not be nil
 | 
			
		||||
func WithContext(b BackOff, ctx context.Context) BackOffContext {
 | 
			
		||||
	if ctx == nil {
 | 
			
		||||
		panic("nil context")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if b, ok := b.(*backOffContext); ok {
 | 
			
		||||
		return &backOffContext{
 | 
			
		||||
			BackOff: b.BackOff,
 | 
			
		||||
			ctx:     ctx,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &backOffContext{
 | 
			
		||||
		BackOff: b,
 | 
			
		||||
		ctx:     ctx,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ensureContext(b BackOff) BackOffContext {
 | 
			
		||||
	if cb, ok := b.(BackOffContext); ok {
 | 
			
		||||
		return cb
 | 
			
		||||
	}
 | 
			
		||||
	return WithContext(b, context.Background())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *backOffContext) Context() context.Context {
 | 
			
		||||
	return b.ctx
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *backOffContext) NextBackOff() time.Duration {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-b.ctx.Done():
 | 
			
		||||
		return Stop
 | 
			
		||||
	default:
 | 
			
		||||
	}
 | 
			
		||||
	next := b.BackOff.NextBackOff()
 | 
			
		||||
	if deadline, ok := b.ctx.Deadline(); ok && deadline.Sub(time.Now()) < next {
 | 
			
		||||
		return Stop
 | 
			
		||||
	}
 | 
			
		||||
	return next
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										153
									
								
								vendor/github.com/cenkalti/backoff/exponential.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										153
									
								
								vendor/github.com/cenkalti/backoff/exponential.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,153 +0,0 @@
 | 
			
		||||
package backoff
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
ExponentialBackOff is a backoff implementation that increases the backoff
 | 
			
		||||
period for each retry attempt using a randomization function that grows exponentially.
 | 
			
		||||
 | 
			
		||||
NextBackOff() is calculated using the following formula:
 | 
			
		||||
 | 
			
		||||
 randomized interval =
 | 
			
		||||
     RetryInterval * (random value in range [1 - RandomizationFactor, 1 + RandomizationFactor])
 | 
			
		||||
 | 
			
		||||
In other words NextBackOff() will range between the randomization factor
 | 
			
		||||
percentage below and above the retry interval.
 | 
			
		||||
 | 
			
		||||
For example, given the following parameters:
 | 
			
		||||
 | 
			
		||||
 RetryInterval = 2
 | 
			
		||||
 RandomizationFactor = 0.5
 | 
			
		||||
 Multiplier = 2
 | 
			
		||||
 | 
			
		||||
the actual backoff period used in the next retry attempt will range between 1 and 3 seconds,
 | 
			
		||||
multiplied by the exponential, that is, between 2 and 6 seconds.
 | 
			
		||||
 | 
			
		||||
Note: MaxInterval caps the RetryInterval and not the randomized interval.
 | 
			
		||||
 | 
			
		||||
If the time elapsed since an ExponentialBackOff instance is created goes past the
 | 
			
		||||
MaxElapsedTime, then the method NextBackOff() starts returning backoff.Stop.
 | 
			
		||||
 | 
			
		||||
The elapsed time can be reset by calling Reset().
 | 
			
		||||
 | 
			
		||||
Example: Given the following default arguments, for 10 tries the sequence will be,
 | 
			
		||||
and assuming we go over the MaxElapsedTime on the 10th try:
 | 
			
		||||
 | 
			
		||||
 Request #  RetryInterval (seconds)  Randomized Interval (seconds)
 | 
			
		||||
 | 
			
		||||
  1          0.5                     [0.25,   0.75]
 | 
			
		||||
  2          0.75                    [0.375,  1.125]
 | 
			
		||||
  3          1.125                   [0.562,  1.687]
 | 
			
		||||
  4          1.687                   [0.8435, 2.53]
 | 
			
		||||
  5          2.53                    [1.265,  3.795]
 | 
			
		||||
  6          3.795                   [1.897,  5.692]
 | 
			
		||||
  7          5.692                   [2.846,  8.538]
 | 
			
		||||
  8          8.538                   [4.269, 12.807]
 | 
			
		||||
  9         12.807                   [6.403, 19.210]
 | 
			
		||||
 10         19.210                   backoff.Stop
 | 
			
		||||
 | 
			
		||||
Note: Implementation is not thread-safe.
 | 
			
		||||
*/
 | 
			
		||||
type ExponentialBackOff struct {
 | 
			
		||||
	InitialInterval     time.Duration
 | 
			
		||||
	RandomizationFactor float64
 | 
			
		||||
	Multiplier          float64
 | 
			
		||||
	MaxInterval         time.Duration
 | 
			
		||||
	// After MaxElapsedTime the ExponentialBackOff stops.
 | 
			
		||||
	// It never stops if MaxElapsedTime == 0.
 | 
			
		||||
	MaxElapsedTime time.Duration
 | 
			
		||||
	Clock          Clock
 | 
			
		||||
 | 
			
		||||
	currentInterval time.Duration
 | 
			
		||||
	startTime       time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Clock is an interface that returns current time for BackOff.
 | 
			
		||||
type Clock interface {
 | 
			
		||||
	Now() time.Time
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Default values for ExponentialBackOff.
 | 
			
		||||
const (
 | 
			
		||||
	DefaultInitialInterval     = 500 * time.Millisecond
 | 
			
		||||
	DefaultRandomizationFactor = 0.5
 | 
			
		||||
	DefaultMultiplier          = 1.5
 | 
			
		||||
	DefaultMaxInterval         = 60 * time.Second
 | 
			
		||||
	DefaultMaxElapsedTime      = 15 * time.Minute
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewExponentialBackOff creates an instance of ExponentialBackOff using default values.
 | 
			
		||||
func NewExponentialBackOff() *ExponentialBackOff {
 | 
			
		||||
	b := &ExponentialBackOff{
 | 
			
		||||
		InitialInterval:     DefaultInitialInterval,
 | 
			
		||||
		RandomizationFactor: DefaultRandomizationFactor,
 | 
			
		||||
		Multiplier:          DefaultMultiplier,
 | 
			
		||||
		MaxInterval:         DefaultMaxInterval,
 | 
			
		||||
		MaxElapsedTime:      DefaultMaxElapsedTime,
 | 
			
		||||
		Clock:               SystemClock,
 | 
			
		||||
	}
 | 
			
		||||
	b.Reset()
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type systemClock struct{}
 | 
			
		||||
 | 
			
		||||
func (t systemClock) Now() time.Time {
 | 
			
		||||
	return time.Now()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SystemClock implements Clock interface that uses time.Now().
 | 
			
		||||
var SystemClock = systemClock{}
 | 
			
		||||
 | 
			
		||||
// Reset the interval back to the initial retry interval and restarts the timer.
 | 
			
		||||
func (b *ExponentialBackOff) Reset() {
 | 
			
		||||
	b.currentInterval = b.InitialInterval
 | 
			
		||||
	b.startTime = b.Clock.Now()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NextBackOff calculates the next backoff interval using the formula:
 | 
			
		||||
// 	Randomized interval = RetryInterval +/- (RandomizationFactor * RetryInterval)
 | 
			
		||||
func (b *ExponentialBackOff) NextBackOff() time.Duration {
 | 
			
		||||
	// Make sure we have not gone over the maximum elapsed time.
 | 
			
		||||
	if b.MaxElapsedTime != 0 && b.GetElapsedTime() > b.MaxElapsedTime {
 | 
			
		||||
		return Stop
 | 
			
		||||
	}
 | 
			
		||||
	defer b.incrementCurrentInterval()
 | 
			
		||||
	return getRandomValueFromInterval(b.RandomizationFactor, rand.Float64(), b.currentInterval)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetElapsedTime returns the elapsed time since an ExponentialBackOff instance
 | 
			
		||||
// is created and is reset when Reset() is called.
 | 
			
		||||
//
 | 
			
		||||
// The elapsed time is computed using time.Now().UnixNano(). It is
 | 
			
		||||
// safe to call even while the backoff policy is used by a running
 | 
			
		||||
// ticker.
 | 
			
		||||
func (b *ExponentialBackOff) GetElapsedTime() time.Duration {
 | 
			
		||||
	return b.Clock.Now().Sub(b.startTime)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Increments the current interval by multiplying it with the multiplier.
 | 
			
		||||
func (b *ExponentialBackOff) incrementCurrentInterval() {
 | 
			
		||||
	// Check for overflow, if overflow is detected set the current interval to the max interval.
 | 
			
		||||
	if float64(b.currentInterval) >= float64(b.MaxInterval)/b.Multiplier {
 | 
			
		||||
		b.currentInterval = b.MaxInterval
 | 
			
		||||
	} else {
 | 
			
		||||
		b.currentInterval = time.Duration(float64(b.currentInterval) * b.Multiplier)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns a random value from the following interval:
 | 
			
		||||
// 	[randomizationFactor * currentInterval, randomizationFactor * currentInterval].
 | 
			
		||||
func getRandomValueFromInterval(randomizationFactor, random float64, currentInterval time.Duration) time.Duration {
 | 
			
		||||
	var delta = randomizationFactor * float64(currentInterval)
 | 
			
		||||
	var minInterval = float64(currentInterval) - delta
 | 
			
		||||
	var maxInterval = float64(currentInterval) + delta
 | 
			
		||||
 | 
			
		||||
	// Get a random value from the range [minInterval, maxInterval].
 | 
			
		||||
	// The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then
 | 
			
		||||
	// we want a 33% chance for selecting either 1, 2 or 3.
 | 
			
		||||
	return time.Duration(minInterval + (random * (maxInterval - minInterval + 1)))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								vendor/github.com/cenkalti/backoff/retry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/cenkalti/backoff/retry.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,82 +0,0 @@
 | 
			
		||||
package backoff
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
// An Operation is executing by Retry() or RetryNotify().
 | 
			
		||||
// The operation will be retried using a backoff policy if it returns an error.
 | 
			
		||||
type Operation func() error
 | 
			
		||||
 | 
			
		||||
// Notify is a notify-on-error function. It receives an operation error and
 | 
			
		||||
// backoff delay if the operation failed (with an error).
 | 
			
		||||
//
 | 
			
		||||
// NOTE that if the backoff policy stated to stop retrying,
 | 
			
		||||
// the notify function isn't called.
 | 
			
		||||
type Notify func(error, time.Duration)
 | 
			
		||||
 | 
			
		||||
// Retry the operation o until it does not return error or BackOff stops.
 | 
			
		||||
// o is guaranteed to be run at least once.
 | 
			
		||||
//
 | 
			
		||||
// If o returns a *PermanentError, the operation is not retried, and the
 | 
			
		||||
// wrapped error is returned.
 | 
			
		||||
//
 | 
			
		||||
// Retry sleeps the goroutine for the duration returned by BackOff after a
 | 
			
		||||
// failed operation returns.
 | 
			
		||||
func Retry(o Operation, b BackOff) error { return RetryNotify(o, b, nil) }
 | 
			
		||||
 | 
			
		||||
// RetryNotify calls notify function with the error and wait duration
 | 
			
		||||
// for each failed attempt before sleep.
 | 
			
		||||
func RetryNotify(operation Operation, b BackOff, notify Notify) error {
 | 
			
		||||
	var err error
 | 
			
		||||
	var next time.Duration
 | 
			
		||||
	var t *time.Timer
 | 
			
		||||
 | 
			
		||||
	cb := ensureContext(b)
 | 
			
		||||
 | 
			
		||||
	b.Reset()
 | 
			
		||||
	for {
 | 
			
		||||
		if err = operation(); err == nil {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if permanent, ok := err.(*PermanentError); ok {
 | 
			
		||||
			return permanent.Err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if next = cb.NextBackOff(); next == Stop {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if notify != nil {
 | 
			
		||||
			notify(err, next)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if t == nil {
 | 
			
		||||
			t = time.NewTimer(next)
 | 
			
		||||
			defer t.Stop()
 | 
			
		||||
		} else {
 | 
			
		||||
			t.Reset(next)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		select {
 | 
			
		||||
		case <-cb.Context().Done():
 | 
			
		||||
			return err
 | 
			
		||||
		case <-t.C:
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PermanentError signals that the operation should not be retried.
 | 
			
		||||
type PermanentError struct {
 | 
			
		||||
	Err error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e *PermanentError) Error() string {
 | 
			
		||||
	return e.Err.Error()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Permanent wraps the given err in a *PermanentError.
 | 
			
		||||
func Permanent(err error) *PermanentError {
 | 
			
		||||
	return &PermanentError{
 | 
			
		||||
		Err: err,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								vendor/github.com/cenkalti/backoff/ticker.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/cenkalti/backoff/ticker.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,82 +0,0 @@
 | 
			
		||||
package backoff
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Ticker holds a channel that delivers `ticks' of a clock at times reported by a BackOff.
 | 
			
		||||
//
 | 
			
		||||
// Ticks will continue to arrive when the previous operation is still running,
 | 
			
		||||
// so operations that take a while to fail could run in quick succession.
 | 
			
		||||
type Ticker struct {
 | 
			
		||||
	C        <-chan time.Time
 | 
			
		||||
	c        chan time.Time
 | 
			
		||||
	b        BackOffContext
 | 
			
		||||
	stop     chan struct{}
 | 
			
		||||
	stopOnce sync.Once
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewTicker returns a new Ticker containing a channel that will send
 | 
			
		||||
// the time at times specified by the BackOff argument. Ticker is
 | 
			
		||||
// guaranteed to tick at least once.  The channel is closed when Stop
 | 
			
		||||
// method is called or BackOff stops. It is not safe to manipulate the
 | 
			
		||||
// provided backoff policy (notably calling NextBackOff or Reset)
 | 
			
		||||
// while the ticker is running.
 | 
			
		||||
func NewTicker(b BackOff) *Ticker {
 | 
			
		||||
	c := make(chan time.Time)
 | 
			
		||||
	t := &Ticker{
 | 
			
		||||
		C:    c,
 | 
			
		||||
		c:    c,
 | 
			
		||||
		b:    ensureContext(b),
 | 
			
		||||
		stop: make(chan struct{}),
 | 
			
		||||
	}
 | 
			
		||||
	t.b.Reset()
 | 
			
		||||
	go t.run()
 | 
			
		||||
	return t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Stop turns off a ticker. After Stop, no more ticks will be sent.
 | 
			
		||||
func (t *Ticker) Stop() {
 | 
			
		||||
	t.stopOnce.Do(func() { close(t.stop) })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Ticker) run() {
 | 
			
		||||
	c := t.c
 | 
			
		||||
	defer close(c)
 | 
			
		||||
 | 
			
		||||
	// Ticker is guaranteed to tick at least once.
 | 
			
		||||
	afterC := t.send(time.Now())
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		if afterC == nil {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		select {
 | 
			
		||||
		case tick := <-afterC:
 | 
			
		||||
			afterC = t.send(tick)
 | 
			
		||||
		case <-t.stop:
 | 
			
		||||
			t.c = nil // Prevent future ticks from being sent to the channel.
 | 
			
		||||
			return
 | 
			
		||||
		case <-t.b.Context().Done():
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Ticker) send(tick time.Time) <-chan time.Time {
 | 
			
		||||
	select {
 | 
			
		||||
	case t.c <- tick:
 | 
			
		||||
	case <-t.stop:
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	next := t.b.NextBackOff()
 | 
			
		||||
	if next == Stop {
 | 
			
		||||
		t.Stop()
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return time.After(next)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								vendor/github.com/cenkalti/backoff/tries.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								vendor/github.com/cenkalti/backoff/tries.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,35 +0,0 @@
 | 
			
		||||
package backoff
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
WithMaxRetries creates a wrapper around another BackOff, which will
 | 
			
		||||
return Stop if NextBackOff() has been called too many times since
 | 
			
		||||
the last time Reset() was called
 | 
			
		||||
 | 
			
		||||
Note: Implementation is not thread-safe.
 | 
			
		||||
*/
 | 
			
		||||
func WithMaxRetries(b BackOff, max uint64) BackOff {
 | 
			
		||||
	return &backOffTries{delegate: b, maxTries: max}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type backOffTries struct {
 | 
			
		||||
	delegate BackOff
 | 
			
		||||
	maxTries uint64
 | 
			
		||||
	numTries uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *backOffTries) NextBackOff() time.Duration {
 | 
			
		||||
	if b.maxTries > 0 {
 | 
			
		||||
		if b.maxTries <= b.numTries {
 | 
			
		||||
			return Stop
 | 
			
		||||
		}
 | 
			
		||||
		b.numTries++
 | 
			
		||||
	}
 | 
			
		||||
	return b.delegate.NextBackOff()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *backOffTries) Reset() {
 | 
			
		||||
	b.numTries = 0
 | 
			
		||||
	b.delegate.Reset()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/github.com/cespare/xxhash/v2/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/cespare/xxhash/v2/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,8 +0,0 @@
 | 
			
		||||
language: go
 | 
			
		||||
go:
 | 
			
		||||
  - "1.x"
 | 
			
		||||
  - master
 | 
			
		||||
env:
 | 
			
		||||
  - TAGS=""
 | 
			
		||||
  - TAGS="-tags purego"
 | 
			
		||||
script: go test $TAGS -v ./...
 | 
			
		||||
							
								
								
									
										22
									
								
								vendor/github.com/cespare/xxhash/v2/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								vendor/github.com/cespare/xxhash/v2/LICENSE.txt
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,22 +0,0 @@
 | 
			
		||||
Copyright (c) 2016 Caleb Spare
 | 
			
		||||
 | 
			
		||||
MIT License
 | 
			
		||||
 | 
			
		||||
Permission is hereby granted, free of charge, to any person obtaining
 | 
			
		||||
a copy of this software and associated documentation files (the
 | 
			
		||||
"Software"), to deal in the Software without restriction, including
 | 
			
		||||
without limitation the rights to use, copy, modify, merge, publish,
 | 
			
		||||
distribute, sublicense, and/or sell copies of the Software, and to
 | 
			
		||||
permit persons to whom the Software is furnished to do so, subject to
 | 
			
		||||
the following conditions:
 | 
			
		||||
 | 
			
		||||
The above copyright notice and this permission notice shall be
 | 
			
		||||
included in all copies or substantial portions of the Software.
 | 
			
		||||
 | 
			
		||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
			
		||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 | 
			
		||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 | 
			
		||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | 
			
		||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
							
								
								
									
										67
									
								
								vendor/github.com/cespare/xxhash/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										67
									
								
								vendor/github.com/cespare/xxhash/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,67 +0,0 @@
 | 
			
		||||
# xxhash
 | 
			
		||||
 | 
			
		||||
[](https://godoc.org/github.com/cespare/xxhash)
 | 
			
		||||
[](https://travis-ci.org/cespare/xxhash)
 | 
			
		||||
 | 
			
		||||
xxhash is a Go implementation of the 64-bit
 | 
			
		||||
[xxHash](http://cyan4973.github.io/xxHash/) algorithm, XXH64. This is a
 | 
			
		||||
high-quality hashing algorithm that is much faster than anything in the Go
 | 
			
		||||
standard library.
 | 
			
		||||
 | 
			
		||||
This package provides a straightforward API:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
func Sum64(b []byte) uint64
 | 
			
		||||
func Sum64String(s string) uint64
 | 
			
		||||
type Digest struct{ ... }
 | 
			
		||||
    func New() *Digest
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `Digest` type implements hash.Hash64. Its key methods are:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
func (*Digest) Write([]byte) (int, error)
 | 
			
		||||
func (*Digest) WriteString(string) (int, error)
 | 
			
		||||
func (*Digest) Sum64() uint64
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This implementation provides a fast pure-Go implementation and an even faster
 | 
			
		||||
assembly implementation for amd64.
 | 
			
		||||
 | 
			
		||||
## Compatibility
 | 
			
		||||
 | 
			
		||||
This package is in a module and the latest code is in version 2 of the module.
 | 
			
		||||
You need a version of Go with at least "minimal module compatibility" to use
 | 
			
		||||
github.com/cespare/xxhash/v2:
 | 
			
		||||
 | 
			
		||||
* 1.9.7+ for Go 1.9
 | 
			
		||||
* 1.10.3+ for Go 1.10
 | 
			
		||||
* Go 1.11 or later
 | 
			
		||||
 | 
			
		||||
I recommend using the latest release of Go.
 | 
			
		||||
 | 
			
		||||
## Benchmarks
 | 
			
		||||
 | 
			
		||||
Here are some quick benchmarks comparing the pure-Go and assembly
 | 
			
		||||
implementations of Sum64.
 | 
			
		||||
 | 
			
		||||
| input size | purego | asm |
 | 
			
		||||
| --- | --- | --- |
 | 
			
		||||
| 5 B   |  979.66 MB/s |  1291.17 MB/s  |
 | 
			
		||||
| 100 B | 7475.26 MB/s | 7973.40 MB/s  |
 | 
			
		||||
| 4 KB  | 17573.46 MB/s | 17602.65 MB/s |
 | 
			
		||||
| 10 MB | 17131.46 MB/s | 17142.16 MB/s |
 | 
			
		||||
 | 
			
		||||
These numbers were generated on Ubuntu 18.04 with an Intel i7-8700K CPU using
 | 
			
		||||
the following commands under Go 1.11.2:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
$ go test -tags purego -benchtime 10s -bench '/xxhash,direct,bytes'
 | 
			
		||||
$ go test -benchtime 10s -bench '/xxhash,direct,bytes'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Projects using this package
 | 
			
		||||
 | 
			
		||||
- [InfluxDB](https://github.com/influxdata/influxdb)
 | 
			
		||||
- [Prometheus](https://github.com/prometheus/prometheus)
 | 
			
		||||
- [FreeCache](https://github.com/coocood/freecache)
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/cespare/xxhash/v2/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/cespare/xxhash/v2/go.mod
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +0,0 @@
 | 
			
		||||
module github.com/cespare/xxhash/v2
 | 
			
		||||
 | 
			
		||||
go 1.11
 | 
			
		||||
							
								
								
									
										0
									
								
								vendor/github.com/cespare/xxhash/v2/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								vendor/github.com/cespare/xxhash/v2/go.sum
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
									
										236
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										236
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,236 +0,0 @@
 | 
			
		||||
// Package xxhash implements the 64-bit variant of xxHash (XXH64) as described
 | 
			
		||||
// at http://cyan4973.github.io/xxHash/.
 | 
			
		||||
package xxhash
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"math/bits"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	prime1 uint64 = 11400714785074694791
 | 
			
		||||
	prime2 uint64 = 14029467366897019727
 | 
			
		||||
	prime3 uint64 = 1609587929392839161
 | 
			
		||||
	prime4 uint64 = 9650029242287828579
 | 
			
		||||
	prime5 uint64 = 2870177450012600261
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NOTE(caleb): I'm using both consts and vars of the primes. Using consts where
 | 
			
		||||
// possible in the Go code is worth a small (but measurable) performance boost
 | 
			
		||||
// by avoiding some MOVQs. Vars are needed for the asm and also are useful for
 | 
			
		||||
// convenience in the Go code in a few places where we need to intentionally
 | 
			
		||||
// avoid constant arithmetic (e.g., v1 := prime1 + prime2 fails because the
 | 
			
		||||
// result overflows a uint64).
 | 
			
		||||
var (
 | 
			
		||||
	prime1v = prime1
 | 
			
		||||
	prime2v = prime2
 | 
			
		||||
	prime3v = prime3
 | 
			
		||||
	prime4v = prime4
 | 
			
		||||
	prime5v = prime5
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Digest implements hash.Hash64.
 | 
			
		||||
type Digest struct {
 | 
			
		||||
	v1    uint64
 | 
			
		||||
	v2    uint64
 | 
			
		||||
	v3    uint64
 | 
			
		||||
	v4    uint64
 | 
			
		||||
	total uint64
 | 
			
		||||
	mem   [32]byte
 | 
			
		||||
	n     int // how much of mem is used
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new Digest that computes the 64-bit xxHash algorithm.
 | 
			
		||||
func New() *Digest {
 | 
			
		||||
	var d Digest
 | 
			
		||||
	d.Reset()
 | 
			
		||||
	return &d
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Reset clears the Digest's state so that it can be reused.
 | 
			
		||||
func (d *Digest) Reset() {
 | 
			
		||||
	d.v1 = prime1v + prime2
 | 
			
		||||
	d.v2 = prime2
 | 
			
		||||
	d.v3 = 0
 | 
			
		||||
	d.v4 = -prime1v
 | 
			
		||||
	d.total = 0
 | 
			
		||||
	d.n = 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Size always returns 8 bytes.
 | 
			
		||||
func (d *Digest) Size() int { return 8 }
 | 
			
		||||
 | 
			
		||||
// BlockSize always returns 32 bytes.
 | 
			
		||||
func (d *Digest) BlockSize() int { return 32 }
 | 
			
		||||
 | 
			
		||||
// Write adds more data to d. It always returns len(b), nil.
 | 
			
		||||
func (d *Digest) Write(b []byte) (n int, err error) {
 | 
			
		||||
	n = len(b)
 | 
			
		||||
	d.total += uint64(n)
 | 
			
		||||
 | 
			
		||||
	if d.n+n < 32 {
 | 
			
		||||
		// This new data doesn't even fill the current block.
 | 
			
		||||
		copy(d.mem[d.n:], b)
 | 
			
		||||
		d.n += n
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if d.n > 0 {
 | 
			
		||||
		// Finish off the partial block.
 | 
			
		||||
		copy(d.mem[d.n:], b)
 | 
			
		||||
		d.v1 = round(d.v1, u64(d.mem[0:8]))
 | 
			
		||||
		d.v2 = round(d.v2, u64(d.mem[8:16]))
 | 
			
		||||
		d.v3 = round(d.v3, u64(d.mem[16:24]))
 | 
			
		||||
		d.v4 = round(d.v4, u64(d.mem[24:32]))
 | 
			
		||||
		b = b[32-d.n:]
 | 
			
		||||
		d.n = 0
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(b) >= 32 {
 | 
			
		||||
		// One or more full blocks left.
 | 
			
		||||
		nw := writeBlocks(d, b)
 | 
			
		||||
		b = b[nw:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Store any remaining partial block.
 | 
			
		||||
	copy(d.mem[:], b)
 | 
			
		||||
	d.n = len(b)
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sum appends the current hash to b and returns the resulting slice.
 | 
			
		||||
func (d *Digest) Sum(b []byte) []byte {
 | 
			
		||||
	s := d.Sum64()
 | 
			
		||||
	return append(
 | 
			
		||||
		b,
 | 
			
		||||
		byte(s>>56),
 | 
			
		||||
		byte(s>>48),
 | 
			
		||||
		byte(s>>40),
 | 
			
		||||
		byte(s>>32),
 | 
			
		||||
		byte(s>>24),
 | 
			
		||||
		byte(s>>16),
 | 
			
		||||
		byte(s>>8),
 | 
			
		||||
		byte(s),
 | 
			
		||||
	)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Sum64 returns the current hash.
 | 
			
		||||
func (d *Digest) Sum64() uint64 {
 | 
			
		||||
	var h uint64
 | 
			
		||||
 | 
			
		||||
	if d.total >= 32 {
 | 
			
		||||
		v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
 | 
			
		||||
		h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
 | 
			
		||||
		h = mergeRound(h, v1)
 | 
			
		||||
		h = mergeRound(h, v2)
 | 
			
		||||
		h = mergeRound(h, v3)
 | 
			
		||||
		h = mergeRound(h, v4)
 | 
			
		||||
	} else {
 | 
			
		||||
		h = d.v3 + prime5
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h += d.total
 | 
			
		||||
 | 
			
		||||
	i, end := 0, d.n
 | 
			
		||||
	for ; i+8 <= end; i += 8 {
 | 
			
		||||
		k1 := round(0, u64(d.mem[i:i+8]))
 | 
			
		||||
		h ^= k1
 | 
			
		||||
		h = rol27(h)*prime1 + prime4
 | 
			
		||||
	}
 | 
			
		||||
	if i+4 <= end {
 | 
			
		||||
		h ^= uint64(u32(d.mem[i:i+4])) * prime1
 | 
			
		||||
		h = rol23(h)*prime2 + prime3
 | 
			
		||||
		i += 4
 | 
			
		||||
	}
 | 
			
		||||
	for i < end {
 | 
			
		||||
		h ^= uint64(d.mem[i]) * prime5
 | 
			
		||||
		h = rol11(h) * prime1
 | 
			
		||||
		i++
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h ^= h >> 33
 | 
			
		||||
	h *= prime2
 | 
			
		||||
	h ^= h >> 29
 | 
			
		||||
	h *= prime3
 | 
			
		||||
	h ^= h >> 32
 | 
			
		||||
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	magic         = "xxh\x06"
 | 
			
		||||
	marshaledSize = len(magic) + 8*5 + 32
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MarshalBinary implements the encoding.BinaryMarshaler interface.
 | 
			
		||||
func (d *Digest) MarshalBinary() ([]byte, error) {
 | 
			
		||||
	b := make([]byte, 0, marshaledSize)
 | 
			
		||||
	b = append(b, magic...)
 | 
			
		||||
	b = appendUint64(b, d.v1)
 | 
			
		||||
	b = appendUint64(b, d.v2)
 | 
			
		||||
	b = appendUint64(b, d.v3)
 | 
			
		||||
	b = appendUint64(b, d.v4)
 | 
			
		||||
	b = appendUint64(b, d.total)
 | 
			
		||||
	b = append(b, d.mem[:d.n]...)
 | 
			
		||||
	b = b[:len(b)+len(d.mem)-d.n]
 | 
			
		||||
	return b, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalBinary implements the encoding.BinaryUnmarshaler interface.
 | 
			
		||||
func (d *Digest) UnmarshalBinary(b []byte) error {
 | 
			
		||||
	if len(b) < len(magic) || string(b[:len(magic)]) != magic {
 | 
			
		||||
		return errors.New("xxhash: invalid hash state identifier")
 | 
			
		||||
	}
 | 
			
		||||
	if len(b) != marshaledSize {
 | 
			
		||||
		return errors.New("xxhash: invalid hash state size")
 | 
			
		||||
	}
 | 
			
		||||
	b = b[len(magic):]
 | 
			
		||||
	b, d.v1 = consumeUint64(b)
 | 
			
		||||
	b, d.v2 = consumeUint64(b)
 | 
			
		||||
	b, d.v3 = consumeUint64(b)
 | 
			
		||||
	b, d.v4 = consumeUint64(b)
 | 
			
		||||
	b, d.total = consumeUint64(b)
 | 
			
		||||
	copy(d.mem[:], b)
 | 
			
		||||
	b = b[len(d.mem):]
 | 
			
		||||
	d.n = int(d.total % uint64(len(d.mem)))
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func appendUint64(b []byte, x uint64) []byte {
 | 
			
		||||
	var a [8]byte
 | 
			
		||||
	binary.LittleEndian.PutUint64(a[:], x)
 | 
			
		||||
	return append(b, a[:]...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func consumeUint64(b []byte) ([]byte, uint64) {
 | 
			
		||||
	x := u64(b)
 | 
			
		||||
	return b[8:], x
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func u64(b []byte) uint64 { return binary.LittleEndian.Uint64(b) }
 | 
			
		||||
func u32(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
 | 
			
		||||
 | 
			
		||||
func round(acc, input uint64) uint64 {
 | 
			
		||||
	acc += input * prime2
 | 
			
		||||
	acc = rol31(acc)
 | 
			
		||||
	acc *= prime1
 | 
			
		||||
	return acc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func mergeRound(acc, val uint64) uint64 {
 | 
			
		||||
	val = round(0, val)
 | 
			
		||||
	acc ^= val
 | 
			
		||||
	acc = acc*prime1 + prime4
 | 
			
		||||
	return acc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func rol1(x uint64) uint64  { return bits.RotateLeft64(x, 1) }
 | 
			
		||||
func rol7(x uint64) uint64  { return bits.RotateLeft64(x, 7) }
 | 
			
		||||
func rol11(x uint64) uint64 { return bits.RotateLeft64(x, 11) }
 | 
			
		||||
func rol12(x uint64) uint64 { return bits.RotateLeft64(x, 12) }
 | 
			
		||||
func rol18(x uint64) uint64 { return bits.RotateLeft64(x, 18) }
 | 
			
		||||
func rol23(x uint64) uint64 { return bits.RotateLeft64(x, 23) }
 | 
			
		||||
func rol27(x uint64) uint64 { return bits.RotateLeft64(x, 27) }
 | 
			
		||||
func rol31(x uint64) uint64 { return bits.RotateLeft64(x, 31) }
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_amd64.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,13 +0,0 @@
 | 
			
		||||
// +build !appengine
 | 
			
		||||
// +build gc
 | 
			
		||||
// +build !purego
 | 
			
		||||
 | 
			
		||||
package xxhash
 | 
			
		||||
 | 
			
		||||
// Sum64 computes the 64-bit xxHash digest of b.
 | 
			
		||||
//
 | 
			
		||||
//go:noescape
 | 
			
		||||
func Sum64(b []byte) uint64
 | 
			
		||||
 | 
			
		||||
//go:noescape
 | 
			
		||||
func writeBlocks(d *Digest, b []byte) int
 | 
			
		||||
							
								
								
									
										215
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										215
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_amd64.s
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,215 +0,0 @@
 | 
			
		||||
// +build !appengine
 | 
			
		||||
// +build gc
 | 
			
		||||
// +build !purego
 | 
			
		||||
 | 
			
		||||
#include "textflag.h"
 | 
			
		||||
 | 
			
		||||
// Register allocation:
 | 
			
		||||
// AX	h
 | 
			
		||||
// CX	pointer to advance through b
 | 
			
		||||
// DX	n
 | 
			
		||||
// BX	loop end
 | 
			
		||||
// R8	v1, k1
 | 
			
		||||
// R9	v2
 | 
			
		||||
// R10	v3
 | 
			
		||||
// R11	v4
 | 
			
		||||
// R12	tmp
 | 
			
		||||
// R13	prime1v
 | 
			
		||||
// R14	prime2v
 | 
			
		||||
// R15	prime4v
 | 
			
		||||
 | 
			
		||||
// round reads from and advances the buffer pointer in CX.
 | 
			
		||||
// It assumes that R13 has prime1v and R14 has prime2v.
 | 
			
		||||
#define round(r) \
 | 
			
		||||
	MOVQ  (CX), R12 \
 | 
			
		||||
	ADDQ  $8, CX    \
 | 
			
		||||
	IMULQ R14, R12  \
 | 
			
		||||
	ADDQ  R12, r    \
 | 
			
		||||
	ROLQ  $31, r    \
 | 
			
		||||
	IMULQ R13, r
 | 
			
		||||
 | 
			
		||||
// mergeRound applies a merge round on the two registers acc and val.
 | 
			
		||||
// It assumes that R13 has prime1v, R14 has prime2v, and R15 has prime4v.
 | 
			
		||||
#define mergeRound(acc, val) \
 | 
			
		||||
	IMULQ R14, val \
 | 
			
		||||
	ROLQ  $31, val \
 | 
			
		||||
	IMULQ R13, val \
 | 
			
		||||
	XORQ  val, acc \
 | 
			
		||||
	IMULQ R13, acc \
 | 
			
		||||
	ADDQ  R15, acc
 | 
			
		||||
 | 
			
		||||
// func Sum64(b []byte) uint64
 | 
			
		||||
TEXT ·Sum64(SB), NOSPLIT, $0-32
 | 
			
		||||
	// Load fixed primes.
 | 
			
		||||
	MOVQ ·prime1v(SB), R13
 | 
			
		||||
	MOVQ ·prime2v(SB), R14
 | 
			
		||||
	MOVQ ·prime4v(SB), R15
 | 
			
		||||
 | 
			
		||||
	// Load slice.
 | 
			
		||||
	MOVQ b_base+0(FP), CX
 | 
			
		||||
	MOVQ b_len+8(FP), DX
 | 
			
		||||
	LEAQ (CX)(DX*1), BX
 | 
			
		||||
 | 
			
		||||
	// The first loop limit will be len(b)-32.
 | 
			
		||||
	SUBQ $32, BX
 | 
			
		||||
 | 
			
		||||
	// Check whether we have at least one block.
 | 
			
		||||
	CMPQ DX, $32
 | 
			
		||||
	JLT  noBlocks
 | 
			
		||||
 | 
			
		||||
	// Set up initial state (v1, v2, v3, v4).
 | 
			
		||||
	MOVQ R13, R8
 | 
			
		||||
	ADDQ R14, R8
 | 
			
		||||
	MOVQ R14, R9
 | 
			
		||||
	XORQ R10, R10
 | 
			
		||||
	XORQ R11, R11
 | 
			
		||||
	SUBQ R13, R11
 | 
			
		||||
 | 
			
		||||
	// Loop until CX > BX.
 | 
			
		||||
blockLoop:
 | 
			
		||||
	round(R8)
 | 
			
		||||
	round(R9)
 | 
			
		||||
	round(R10)
 | 
			
		||||
	round(R11)
 | 
			
		||||
 | 
			
		||||
	CMPQ CX, BX
 | 
			
		||||
	JLE  blockLoop
 | 
			
		||||
 | 
			
		||||
	MOVQ R8, AX
 | 
			
		||||
	ROLQ $1, AX
 | 
			
		||||
	MOVQ R9, R12
 | 
			
		||||
	ROLQ $7, R12
 | 
			
		||||
	ADDQ R12, AX
 | 
			
		||||
	MOVQ R10, R12
 | 
			
		||||
	ROLQ $12, R12
 | 
			
		||||
	ADDQ R12, AX
 | 
			
		||||
	MOVQ R11, R12
 | 
			
		||||
	ROLQ $18, R12
 | 
			
		||||
	ADDQ R12, AX
 | 
			
		||||
 | 
			
		||||
	mergeRound(AX, R8)
 | 
			
		||||
	mergeRound(AX, R9)
 | 
			
		||||
	mergeRound(AX, R10)
 | 
			
		||||
	mergeRound(AX, R11)
 | 
			
		||||
 | 
			
		||||
	JMP afterBlocks
 | 
			
		||||
 | 
			
		||||
noBlocks:
 | 
			
		||||
	MOVQ ·prime5v(SB), AX
 | 
			
		||||
 | 
			
		||||
afterBlocks:
 | 
			
		||||
	ADDQ DX, AX
 | 
			
		||||
 | 
			
		||||
	// Right now BX has len(b)-32, and we want to loop until CX > len(b)-8.
 | 
			
		||||
	ADDQ $24, BX
 | 
			
		||||
 | 
			
		||||
	CMPQ CX, BX
 | 
			
		||||
	JG   fourByte
 | 
			
		||||
 | 
			
		||||
wordLoop:
 | 
			
		||||
	// Calculate k1.
 | 
			
		||||
	MOVQ  (CX), R8
 | 
			
		||||
	ADDQ  $8, CX
 | 
			
		||||
	IMULQ R14, R8
 | 
			
		||||
	ROLQ  $31, R8
 | 
			
		||||
	IMULQ R13, R8
 | 
			
		||||
 | 
			
		||||
	XORQ  R8, AX
 | 
			
		||||
	ROLQ  $27, AX
 | 
			
		||||
	IMULQ R13, AX
 | 
			
		||||
	ADDQ  R15, AX
 | 
			
		||||
 | 
			
		||||
	CMPQ CX, BX
 | 
			
		||||
	JLE  wordLoop
 | 
			
		||||
 | 
			
		||||
fourByte:
 | 
			
		||||
	ADDQ $4, BX
 | 
			
		||||
	CMPQ CX, BX
 | 
			
		||||
	JG   singles
 | 
			
		||||
 | 
			
		||||
	MOVL  (CX), R8
 | 
			
		||||
	ADDQ  $4, CX
 | 
			
		||||
	IMULQ R13, R8
 | 
			
		||||
	XORQ  R8, AX
 | 
			
		||||
 | 
			
		||||
	ROLQ  $23, AX
 | 
			
		||||
	IMULQ R14, AX
 | 
			
		||||
	ADDQ  ·prime3v(SB), AX
 | 
			
		||||
 | 
			
		||||
singles:
 | 
			
		||||
	ADDQ $4, BX
 | 
			
		||||
	CMPQ CX, BX
 | 
			
		||||
	JGE  finalize
 | 
			
		||||
 | 
			
		||||
singlesLoop:
 | 
			
		||||
	MOVBQZX (CX), R12
 | 
			
		||||
	ADDQ    $1, CX
 | 
			
		||||
	IMULQ   ·prime5v(SB), R12
 | 
			
		||||
	XORQ    R12, AX
 | 
			
		||||
 | 
			
		||||
	ROLQ  $11, AX
 | 
			
		||||
	IMULQ R13, AX
 | 
			
		||||
 | 
			
		||||
	CMPQ CX, BX
 | 
			
		||||
	JL   singlesLoop
 | 
			
		||||
 | 
			
		||||
finalize:
 | 
			
		||||
	MOVQ  AX, R12
 | 
			
		||||
	SHRQ  $33, R12
 | 
			
		||||
	XORQ  R12, AX
 | 
			
		||||
	IMULQ R14, AX
 | 
			
		||||
	MOVQ  AX, R12
 | 
			
		||||
	SHRQ  $29, R12
 | 
			
		||||
	XORQ  R12, AX
 | 
			
		||||
	IMULQ ·prime3v(SB), AX
 | 
			
		||||
	MOVQ  AX, R12
 | 
			
		||||
	SHRQ  $32, R12
 | 
			
		||||
	XORQ  R12, AX
 | 
			
		||||
 | 
			
		||||
	MOVQ AX, ret+24(FP)
 | 
			
		||||
	RET
 | 
			
		||||
 | 
			
		||||
// writeBlocks uses the same registers as above except that it uses AX to store
 | 
			
		||||
// the d pointer.
 | 
			
		||||
 | 
			
		||||
// func writeBlocks(d *Digest, b []byte) int
 | 
			
		||||
TEXT ·writeBlocks(SB), NOSPLIT, $0-40
 | 
			
		||||
	// Load fixed primes needed for round.
 | 
			
		||||
	MOVQ ·prime1v(SB), R13
 | 
			
		||||
	MOVQ ·prime2v(SB), R14
 | 
			
		||||
 | 
			
		||||
	// Load slice.
 | 
			
		||||
	MOVQ b_base+8(FP), CX
 | 
			
		||||
	MOVQ b_len+16(FP), DX
 | 
			
		||||
	LEAQ (CX)(DX*1), BX
 | 
			
		||||
	SUBQ $32, BX
 | 
			
		||||
 | 
			
		||||
	// Load vN from d.
 | 
			
		||||
	MOVQ d+0(FP), AX
 | 
			
		||||
	MOVQ 0(AX), R8   // v1
 | 
			
		||||
	MOVQ 8(AX), R9   // v2
 | 
			
		||||
	MOVQ 16(AX), R10 // v3
 | 
			
		||||
	MOVQ 24(AX), R11 // v4
 | 
			
		||||
 | 
			
		||||
	// We don't need to check the loop condition here; this function is
 | 
			
		||||
	// always called with at least one block of data to process.
 | 
			
		||||
blockLoop:
 | 
			
		||||
	round(R8)
 | 
			
		||||
	round(R9)
 | 
			
		||||
	round(R10)
 | 
			
		||||
	round(R11)
 | 
			
		||||
 | 
			
		||||
	CMPQ CX, BX
 | 
			
		||||
	JLE  blockLoop
 | 
			
		||||
 | 
			
		||||
	// Copy vN back to d.
 | 
			
		||||
	MOVQ R8, 0(AX)
 | 
			
		||||
	MOVQ R9, 8(AX)
 | 
			
		||||
	MOVQ R10, 16(AX)
 | 
			
		||||
	MOVQ R11, 24(AX)
 | 
			
		||||
 | 
			
		||||
	// The number of bytes written is CX minus the old base pointer.
 | 
			
		||||
	SUBQ b_base+8(FP), CX
 | 
			
		||||
	MOVQ CX, ret+32(FP)
 | 
			
		||||
 | 
			
		||||
	RET
 | 
			
		||||
							
								
								
									
										76
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_other.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										76
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_other.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,76 +0,0 @@
 | 
			
		||||
// +build !amd64 appengine !gc purego
 | 
			
		||||
 | 
			
		||||
package xxhash
 | 
			
		||||
 | 
			
		||||
// Sum64 computes the 64-bit xxHash digest of b.
 | 
			
		||||
func Sum64(b []byte) uint64 {
 | 
			
		||||
	// A simpler version would be
 | 
			
		||||
	//   d := New()
 | 
			
		||||
	//   d.Write(b)
 | 
			
		||||
	//   return d.Sum64()
 | 
			
		||||
	// but this is faster, particularly for small inputs.
 | 
			
		||||
 | 
			
		||||
	n := len(b)
 | 
			
		||||
	var h uint64
 | 
			
		||||
 | 
			
		||||
	if n >= 32 {
 | 
			
		||||
		v1 := prime1v + prime2
 | 
			
		||||
		v2 := prime2
 | 
			
		||||
		v3 := uint64(0)
 | 
			
		||||
		v4 := -prime1v
 | 
			
		||||
		for len(b) >= 32 {
 | 
			
		||||
			v1 = round(v1, u64(b[0:8:len(b)]))
 | 
			
		||||
			v2 = round(v2, u64(b[8:16:len(b)]))
 | 
			
		||||
			v3 = round(v3, u64(b[16:24:len(b)]))
 | 
			
		||||
			v4 = round(v4, u64(b[24:32:len(b)]))
 | 
			
		||||
			b = b[32:len(b):len(b)]
 | 
			
		||||
		}
 | 
			
		||||
		h = rol1(v1) + rol7(v2) + rol12(v3) + rol18(v4)
 | 
			
		||||
		h = mergeRound(h, v1)
 | 
			
		||||
		h = mergeRound(h, v2)
 | 
			
		||||
		h = mergeRound(h, v3)
 | 
			
		||||
		h = mergeRound(h, v4)
 | 
			
		||||
	} else {
 | 
			
		||||
		h = prime5
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h += uint64(n)
 | 
			
		||||
 | 
			
		||||
	i, end := 0, len(b)
 | 
			
		||||
	for ; i+8 <= end; i += 8 {
 | 
			
		||||
		k1 := round(0, u64(b[i:i+8:len(b)]))
 | 
			
		||||
		h ^= k1
 | 
			
		||||
		h = rol27(h)*prime1 + prime4
 | 
			
		||||
	}
 | 
			
		||||
	if i+4 <= end {
 | 
			
		||||
		h ^= uint64(u32(b[i:i+4:len(b)])) * prime1
 | 
			
		||||
		h = rol23(h)*prime2 + prime3
 | 
			
		||||
		i += 4
 | 
			
		||||
	}
 | 
			
		||||
	for ; i < end; i++ {
 | 
			
		||||
		h ^= uint64(b[i]) * prime5
 | 
			
		||||
		h = rol11(h) * prime1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	h ^= h >> 33
 | 
			
		||||
	h *= prime2
 | 
			
		||||
	h ^= h >> 29
 | 
			
		||||
	h *= prime3
 | 
			
		||||
	h ^= h >> 32
 | 
			
		||||
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeBlocks(d *Digest, b []byte) int {
 | 
			
		||||
	v1, v2, v3, v4 := d.v1, d.v2, d.v3, d.v4
 | 
			
		||||
	n := len(b)
 | 
			
		||||
	for len(b) >= 32 {
 | 
			
		||||
		v1 = round(v1, u64(b[0:8:len(b)]))
 | 
			
		||||
		v2 = round(v2, u64(b[8:16:len(b)]))
 | 
			
		||||
		v3 = round(v3, u64(b[16:24:len(b)]))
 | 
			
		||||
		v4 = round(v4, u64(b[24:32:len(b)]))
 | 
			
		||||
		b = b[32:len(b):len(b)]
 | 
			
		||||
	}
 | 
			
		||||
	d.v1, d.v2, d.v3, d.v4 = v1, v2, v3, v4
 | 
			
		||||
	return n - len(b)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,15 +0,0 @@
 | 
			
		||||
// +build appengine
 | 
			
		||||
 | 
			
		||||
// This file contains the safe implementations of otherwise unsafe-using code.
 | 
			
		||||
 | 
			
		||||
package xxhash
 | 
			
		||||
 | 
			
		||||
// Sum64String computes the 64-bit xxHash digest of s.
 | 
			
		||||
func Sum64String(s string) uint64 {
 | 
			
		||||
	return Sum64([]byte(s))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteString adds more data to d. It always returns len(s), nil.
 | 
			
		||||
func (d *Digest) WriteString(s string) (n int, err error) {
 | 
			
		||||
	return d.Write([]byte(s))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										46
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,46 +0,0 @@
 | 
			
		||||
// +build !appengine
 | 
			
		||||
 | 
			
		||||
// This file encapsulates usage of unsafe.
 | 
			
		||||
// xxhash_safe.go contains the safe implementations.
 | 
			
		||||
 | 
			
		||||
package xxhash
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Notes:
 | 
			
		||||
//
 | 
			
		||||
// See https://groups.google.com/d/msg/golang-nuts/dcjzJy-bSpw/tcZYBzQqAQAJ
 | 
			
		||||
// for some discussion about these unsafe conversions.
 | 
			
		||||
//
 | 
			
		||||
// In the future it's possible that compiler optimizations will make these
 | 
			
		||||
// unsafe operations unnecessary: https://golang.org/issue/2205.
 | 
			
		||||
//
 | 
			
		||||
// Both of these wrapper functions still incur function call overhead since they
 | 
			
		||||
// will not be inlined. We could write Go/asm copies of Sum64 and Digest.Write
 | 
			
		||||
// for strings to squeeze out a bit more speed. Mid-stack inlining should
 | 
			
		||||
// eventually fix this.
 | 
			
		||||
 | 
			
		||||
// Sum64String computes the 64-bit xxHash digest of s.
 | 
			
		||||
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
 | 
			
		||||
func Sum64String(s string) uint64 {
 | 
			
		||||
	var b []byte
 | 
			
		||||
	bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
 | 
			
		||||
	bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
 | 
			
		||||
	bh.Len = len(s)
 | 
			
		||||
	bh.Cap = len(s)
 | 
			
		||||
	return Sum64(b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WriteString adds more data to d. It always returns len(s), nil.
 | 
			
		||||
// It may be faster than Write([]byte(s)) by avoiding a copy.
 | 
			
		||||
func (d *Digest) WriteString(s string) (n int, err error) {
 | 
			
		||||
	var b []byte
 | 
			
		||||
	bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
 | 
			
		||||
	bh.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
 | 
			
		||||
	bh.Len = len(s)
 | 
			
		||||
	bh.Cap = len(s)
 | 
			
		||||
	return d.Write(b)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/containerd/continuity/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/containerd/continuity/AUTHORS
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,16 +0,0 @@
 | 
			
		||||
Aaron Lehmann <aaron.lehmann@docker.com>
 | 
			
		||||
Akash Gupta <akagup@microsoft.com>
 | 
			
		||||
Akihiro Suda <suda.akihiro@lab.ntt.co.jp>
 | 
			
		||||
Andrew Pennebaker <apennebaker@datapipe.com>
 | 
			
		||||
Brandon Philips <brandon.philips@coreos.com>
 | 
			
		||||
Christopher Jones <tophj@linux.vnet.ibm.com>
 | 
			
		||||
Daniel, Dao Quang Minh <dqminh89@gmail.com>
 | 
			
		||||
Derek McGowan <derek@mcgstyle.net>
 | 
			
		||||
Edward Pilatowicz <edward.pilatowicz@oracle.com>
 | 
			
		||||
Ian Campbell <ijc@docker.com>
 | 
			
		||||
Justin Cormack <justin.cormack@docker.com>
 | 
			
		||||
Justin Cummins <sul3n3t@gmail.com>
 | 
			
		||||
Phil Estes <estesp@gmail.com>
 | 
			
		||||
Stephen J Day <stephen.day@docker.com>
 | 
			
		||||
Tobias Klauser <tklauser@distanz.ch>
 | 
			
		||||
Tonis Tiigi <tonistiigi@gmail.com>
 | 
			
		||||
							
								
								
									
										191
									
								
								vendor/github.com/containerd/continuity/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										191
									
								
								vendor/github.com/containerd/continuity/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,191 +0,0 @@
 | 
			
		||||
 | 
			
		||||
                                 Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        https://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
   1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
   END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
   Copyright The containerd Authors
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
 | 
			
		||||
       https://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.
 | 
			
		||||
							
								
								
									
										172
									
								
								vendor/github.com/containerd/continuity/fs/copy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										172
									
								
								vendor/github.com/containerd/continuity/fs/copy.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,172 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var bufferPool = &sync.Pool{
 | 
			
		||||
	New: func() interface{} {
 | 
			
		||||
		buffer := make([]byte, 32*1024)
 | 
			
		||||
		return &buffer
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// XAttrErrorHandlers transform a non-nil xattr error.
 | 
			
		||||
// Return nil to ignore an error.
 | 
			
		||||
// xattrKey can be empty for listxattr operation.
 | 
			
		||||
type XAttrErrorHandler func(dst, src, xattrKey string, err error) error
 | 
			
		||||
 | 
			
		||||
type copyDirOpts struct {
 | 
			
		||||
	xeh XAttrErrorHandler
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type CopyDirOpt func(*copyDirOpts) error
 | 
			
		||||
 | 
			
		||||
// WithXAttrErrorHandler allows specifying XAttrErrorHandler
 | 
			
		||||
// If nil XAttrErrorHandler is specified (default), CopyDir stops
 | 
			
		||||
// on a non-nil xattr error.
 | 
			
		||||
func WithXAttrErrorHandler(xeh XAttrErrorHandler) CopyDirOpt {
 | 
			
		||||
	return func(o *copyDirOpts) error {
 | 
			
		||||
		o.xeh = xeh
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// WithAllowXAttrErrors allows ignoring xattr errors.
 | 
			
		||||
func WithAllowXAttrErrors() CopyDirOpt {
 | 
			
		||||
	xeh := func(dst, src, xattrKey string, err error) error {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return WithXAttrErrorHandler(xeh)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CopyDir copies the directory from src to dst.
 | 
			
		||||
// Most efficient copy of files is attempted.
 | 
			
		||||
func CopyDir(dst, src string, opts ...CopyDirOpt) error {
 | 
			
		||||
	var o copyDirOpts
 | 
			
		||||
	for _, opt := range opts {
 | 
			
		||||
		if err := opt(&o); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	inodes := map[uint64]string{}
 | 
			
		||||
	return copyDirectory(dst, src, inodes, &o)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDirectory(dst, src string, inodes map[uint64]string, o *copyDirOpts) error {
 | 
			
		||||
	stat, err := os.Stat(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to stat %s", src)
 | 
			
		||||
	}
 | 
			
		||||
	if !stat.IsDir() {
 | 
			
		||||
		return errors.Errorf("source is not directory")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if st, err := os.Stat(dst); err != nil {
 | 
			
		||||
		if err := os.Mkdir(dst, stat.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to mkdir %s", dst)
 | 
			
		||||
		}
 | 
			
		||||
	} else if !st.IsDir() {
 | 
			
		||||
		return errors.Errorf("cannot copy to non-directory: %s", dst)
 | 
			
		||||
	} else {
 | 
			
		||||
		if err := os.Chmod(dst, stat.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chmod on %s", dst)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fis, err := ioutil.ReadDir(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to read %s", src)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := copyFileInfo(stat, dst); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to copy file info for %s", dst)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, fi := range fis {
 | 
			
		||||
		source := filepath.Join(src, fi.Name())
 | 
			
		||||
		target := filepath.Join(dst, fi.Name())
 | 
			
		||||
 | 
			
		||||
		switch {
 | 
			
		||||
		case fi.IsDir():
 | 
			
		||||
			if err := copyDirectory(target, source, inodes, o); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			continue
 | 
			
		||||
		case (fi.Mode() & os.ModeType) == 0:
 | 
			
		||||
			link, err := getLinkSource(target, fi, inodes)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrap(err, "failed to get hardlink")
 | 
			
		||||
			}
 | 
			
		||||
			if link != "" {
 | 
			
		||||
				if err := os.Link(link, target); err != nil {
 | 
			
		||||
					return errors.Wrap(err, "failed to create hard link")
 | 
			
		||||
				}
 | 
			
		||||
			} else if err := CopyFile(target, source); err != nil {
 | 
			
		||||
				return errors.Wrap(err, "failed to copy files")
 | 
			
		||||
			}
 | 
			
		||||
		case (fi.Mode() & os.ModeSymlink) == os.ModeSymlink:
 | 
			
		||||
			link, err := os.Readlink(source)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "failed to read link: %s", source)
 | 
			
		||||
			}
 | 
			
		||||
			if err := os.Symlink(link, target); err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "failed to create symlink: %s", target)
 | 
			
		||||
			}
 | 
			
		||||
		case (fi.Mode() & os.ModeDevice) == os.ModeDevice:
 | 
			
		||||
			if err := copyDevice(target, fi); err != nil {
 | 
			
		||||
				return errors.Wrapf(err, "failed to create device")
 | 
			
		||||
			}
 | 
			
		||||
		default:
 | 
			
		||||
			// TODO: Support pipes and sockets
 | 
			
		||||
			return errors.Wrapf(err, "unsupported mode %s", fi.Mode())
 | 
			
		||||
		}
 | 
			
		||||
		if err := copyFileInfo(fi, target); err != nil {
 | 
			
		||||
			return errors.Wrap(err, "failed to copy file info")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if err := copyXAttrs(target, source, o.xeh); err != nil {
 | 
			
		||||
			return errors.Wrap(err, "failed to copy xattrs")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CopyFile copies the source file to the target.
 | 
			
		||||
// The most efficient means of copying is used for the platform.
 | 
			
		||||
func CopyFile(target, source string) error {
 | 
			
		||||
	src, err := os.Open(source)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to open source %s", source)
 | 
			
		||||
	}
 | 
			
		||||
	defer src.Close()
 | 
			
		||||
	tgt, err := os.Create(target)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to open target %s", target)
 | 
			
		||||
	}
 | 
			
		||||
	defer tgt.Close()
 | 
			
		||||
 | 
			
		||||
	return copyFileContent(tgt, src)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										144
									
								
								vendor/github.com/containerd/continuity/fs/copy_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										144
									
								
								vendor/github.com/containerd/continuity/fs/copy_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,144 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func copyFileInfo(fi os.FileInfo, name string) error {
 | 
			
		||||
	st := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
 | 
			
		||||
		if os.IsPermission(err) {
 | 
			
		||||
			// Normally if uid/gid are the same this would be a no-op, but some
 | 
			
		||||
			// filesystems may still return EPERM... for instance NFS does this.
 | 
			
		||||
			// In such a case, this is not an error.
 | 
			
		||||
			if dstStat, err2 := os.Lstat(name); err2 == nil {
 | 
			
		||||
				st2 := dstStat.Sys().(*syscall.Stat_t)
 | 
			
		||||
				if st.Uid == st2.Uid && st.Gid == st2.Gid {
 | 
			
		||||
					err = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chown %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
 | 
			
		||||
		if err := os.Chmod(name, fi.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chmod %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timespec := []unix.Timespec{unix.Timespec(StatAtime(st)), unix.Timespec(StatMtime(st))}
 | 
			
		||||
	if err := unix.UtimesNanoAt(unix.AT_FDCWD, name, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to utime %s", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const maxSSizeT = int64(^uint(0) >> 1)
 | 
			
		||||
 | 
			
		||||
func copyFileContent(dst, src *os.File) error {
 | 
			
		||||
	st, err := src.Stat()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return errors.Wrap(err, "unable to stat source")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	size := st.Size()
 | 
			
		||||
	first := true
 | 
			
		||||
	srcFd := int(src.Fd())
 | 
			
		||||
	dstFd := int(dst.Fd())
 | 
			
		||||
 | 
			
		||||
	for size > 0 {
 | 
			
		||||
		// Ensure that we are never trying to copy more than SSIZE_MAX at a
 | 
			
		||||
		// time and at the same time avoids overflows when the file is larger
 | 
			
		||||
		// than 4GB on 32-bit systems.
 | 
			
		||||
		var copySize int
 | 
			
		||||
		if size > maxSSizeT {
 | 
			
		||||
			copySize = int(maxSSizeT)
 | 
			
		||||
		} else {
 | 
			
		||||
			copySize = int(size)
 | 
			
		||||
		}
 | 
			
		||||
		n, err := unix.CopyFileRange(srcFd, nil, dstFd, nil, copySize, 0)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if (err != unix.ENOSYS && err != unix.EXDEV) || !first {
 | 
			
		||||
				return errors.Wrap(err, "copy file range failed")
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			buf := bufferPool.Get().(*[]byte)
 | 
			
		||||
			_, err = io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
			bufferPool.Put(buf)
 | 
			
		||||
			return errors.Wrap(err, "userspace copy failed")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		first = false
 | 
			
		||||
		size -= int64(n)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 | 
			
		||||
	xattrKeys, err := sysx.LListxattr(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		e := errors.Wrapf(err, "failed to list xattrs on %s", src)
 | 
			
		||||
		if xeh != nil {
 | 
			
		||||
			e = xeh(dst, src, "", e)
 | 
			
		||||
		}
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	for _, xattr := range xattrKeys {
 | 
			
		||||
		data, err := sysx.LGetxattr(src, xattr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src)
 | 
			
		||||
			if xeh != nil {
 | 
			
		||||
				if e = xeh(dst, src, xattr, e); e == nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return e
 | 
			
		||||
		}
 | 
			
		||||
		if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
 | 
			
		||||
			e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst)
 | 
			
		||||
			if xeh != nil {
 | 
			
		||||
				if e = xeh(dst, src, xattr, e); e == nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return e
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDevice(dst string, fi os.FileInfo) error {
 | 
			
		||||
	st, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("unsupported stat type")
 | 
			
		||||
	}
 | 
			
		||||
	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										112
									
								
								vendor/github.com/containerd/continuity/fs/copy_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/containerd/continuity/fs/copy_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,112 +0,0 @@
 | 
			
		||||
// +build solaris darwin freebsd
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func copyFileInfo(fi os.FileInfo, name string) error {
 | 
			
		||||
	st := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if err := os.Lchown(name, int(st.Uid), int(st.Gid)); err != nil {
 | 
			
		||||
		if os.IsPermission(err) {
 | 
			
		||||
			// Normally if uid/gid are the same this would be a no-op, but some
 | 
			
		||||
			// filesystems may still return EPERM... for instance NFS does this.
 | 
			
		||||
			// In such a case, this is not an error.
 | 
			
		||||
			if dstStat, err2 := os.Lstat(name); err2 == nil {
 | 
			
		||||
				st2 := dstStat.Sys().(*syscall.Stat_t)
 | 
			
		||||
				if st.Uid == st2.Uid && st.Gid == st2.Gid {
 | 
			
		||||
					err = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chown %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (fi.Mode() & os.ModeSymlink) != os.ModeSymlink {
 | 
			
		||||
		if err := os.Chmod(name, fi.Mode()); err != nil {
 | 
			
		||||
			return errors.Wrapf(err, "failed to chmod %s", name)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	timespec := []syscall.Timespec{StatAtime(st), StatMtime(st)}
 | 
			
		||||
	if err := syscall.UtimesNano(name, timespec); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to utime %s", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyFileContent(dst, src *os.File) error {
 | 
			
		||||
	buf := bufferPool.Get().(*[]byte)
 | 
			
		||||
	_, err := io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
	bufferPool.Put(buf)
 | 
			
		||||
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 | 
			
		||||
	xattrKeys, err := sysx.LListxattr(src)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		e := errors.Wrapf(err, "failed to list xattrs on %s", src)
 | 
			
		||||
		if xeh != nil {
 | 
			
		||||
			e = xeh(dst, src, "", e)
 | 
			
		||||
		}
 | 
			
		||||
		return e
 | 
			
		||||
	}
 | 
			
		||||
	for _, xattr := range xattrKeys {
 | 
			
		||||
		data, err := sysx.LGetxattr(src, xattr)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			e := errors.Wrapf(err, "failed to get xattr %q on %s", xattr, src)
 | 
			
		||||
			if xeh != nil {
 | 
			
		||||
				if e = xeh(dst, src, xattr, e); e == nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return e
 | 
			
		||||
		}
 | 
			
		||||
		if err := sysx.LSetxattr(dst, xattr, data, 0); err != nil {
 | 
			
		||||
			e := errors.Wrapf(err, "failed to set xattr %q on %s", xattr, dst)
 | 
			
		||||
			if xeh != nil {
 | 
			
		||||
				if e = xeh(dst, src, xattr, e); e == nil {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			return e
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDevice(dst string, fi os.FileInfo) error {
 | 
			
		||||
	st, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return errors.New("unsupported stat type")
 | 
			
		||||
	}
 | 
			
		||||
	return unix.Mknod(dst, uint32(fi.Mode()), int(st.Rdev))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								vendor/github.com/containerd/continuity/fs/copy_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								vendor/github.com/containerd/continuity/fs/copy_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,49 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func copyFileInfo(fi os.FileInfo, name string) error {
 | 
			
		||||
	if err := os.Chmod(name, fi.Mode()); err != nil {
 | 
			
		||||
		return errors.Wrapf(err, "failed to chmod %s", name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// TODO: copy windows specific metadata
 | 
			
		||||
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyFileContent(dst, src *os.File) error {
 | 
			
		||||
	buf := bufferPool.Get().(*[]byte)
 | 
			
		||||
	_, err := io.CopyBuffer(dst, src, *buf)
 | 
			
		||||
	bufferPool.Put(buf)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyXAttrs(dst, src string, xeh XAttrErrorHandler) error {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyDevice(dst string, fi os.FileInfo) error {
 | 
			
		||||
	return errors.New("device copy not supported")
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										326
									
								
								vendor/github.com/containerd/continuity/fs/diff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										326
									
								
								vendor/github.com/containerd/continuity/fs/diff.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,326 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sync/errgroup"
 | 
			
		||||
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ChangeKind is the type of modification that
 | 
			
		||||
// a change is making.
 | 
			
		||||
type ChangeKind int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// ChangeKindUnmodified represents an unmodified
 | 
			
		||||
	// file
 | 
			
		||||
	ChangeKindUnmodified = iota
 | 
			
		||||
 | 
			
		||||
	// ChangeKindAdd represents an addition of
 | 
			
		||||
	// a file
 | 
			
		||||
	ChangeKindAdd
 | 
			
		||||
 | 
			
		||||
	// ChangeKindModify represents a change to
 | 
			
		||||
	// an existing file
 | 
			
		||||
	ChangeKindModify
 | 
			
		||||
 | 
			
		||||
	// ChangeKindDelete represents a delete of
 | 
			
		||||
	// a file
 | 
			
		||||
	ChangeKindDelete
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (k ChangeKind) String() string {
 | 
			
		||||
	switch k {
 | 
			
		||||
	case ChangeKindUnmodified:
 | 
			
		||||
		return "unmodified"
 | 
			
		||||
	case ChangeKindAdd:
 | 
			
		||||
		return "add"
 | 
			
		||||
	case ChangeKindModify:
 | 
			
		||||
		return "modify"
 | 
			
		||||
	case ChangeKindDelete:
 | 
			
		||||
		return "delete"
 | 
			
		||||
	default:
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Change represents single change between a diff and its parent.
 | 
			
		||||
type Change struct {
 | 
			
		||||
	Kind ChangeKind
 | 
			
		||||
	Path string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ChangeFunc is the type of function called for each change
 | 
			
		||||
// computed during a directory changes calculation.
 | 
			
		||||
type ChangeFunc func(ChangeKind, string, os.FileInfo, error) error
 | 
			
		||||
 | 
			
		||||
// Changes computes changes between two directories calling the
 | 
			
		||||
// given change function for each computed change. The first
 | 
			
		||||
// directory is intended to the base directory and second
 | 
			
		||||
// directory the changed directory.
 | 
			
		||||
//
 | 
			
		||||
// The change callback is called by the order of path names and
 | 
			
		||||
// should be appliable in that order.
 | 
			
		||||
//  Due to this apply ordering, the following is true
 | 
			
		||||
//  - Removed directory trees only create a single change for the root
 | 
			
		||||
//    directory removed. Remaining changes are implied.
 | 
			
		||||
//  - A directory which is modified to become a file will not have
 | 
			
		||||
//    delete entries for sub-path items, their removal is implied
 | 
			
		||||
//    by the removal of the parent directory.
 | 
			
		||||
//
 | 
			
		||||
// Opaque directories will not be treated specially and each file
 | 
			
		||||
// removed from the base directory will show up as a removal.
 | 
			
		||||
//
 | 
			
		||||
// File content comparisons will be done on files which have timestamps
 | 
			
		||||
// which may have been truncated. If either of the files being compared
 | 
			
		||||
// has a zero value nanosecond value, each byte will be compared for
 | 
			
		||||
// differences. If 2 files have the same seconds value but different
 | 
			
		||||
// nanosecond values where one of those values is zero, the files will
 | 
			
		||||
// be considered unchanged if the content is the same. This behavior
 | 
			
		||||
// is to account for timestamp truncation during archiving.
 | 
			
		||||
func Changes(ctx context.Context, a, b string, changeFn ChangeFunc) error {
 | 
			
		||||
	if a == "" {
 | 
			
		||||
		logrus.Debugf("Using single walk diff for %s", b)
 | 
			
		||||
		return addDirChanges(ctx, changeFn, b)
 | 
			
		||||
	} else if diffOptions := detectDirDiff(b, a); diffOptions != nil {
 | 
			
		||||
		logrus.Debugf("Using single walk diff for %s from %s", diffOptions.diffDir, a)
 | 
			
		||||
		return diffDirChanges(ctx, changeFn, a, diffOptions)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logrus.Debugf("Using double walk diff for %s from %s", b, a)
 | 
			
		||||
	return doubleWalkDiff(ctx, changeFn, a, b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func addDirChanges(ctx context.Context, changeFn ChangeFunc, root string) error {
 | 
			
		||||
	return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Rebase path
 | 
			
		||||
		path, err = filepath.Rel(root, path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = filepath.Join(string(os.PathSeparator), path)
 | 
			
		||||
 | 
			
		||||
		// Skip root
 | 
			
		||||
		if path == string(os.PathSeparator) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return changeFn(ChangeKindAdd, path, f, nil)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// diffDirOptions is used when the diff can be directly calculated from
 | 
			
		||||
// a diff directory to its base, without walking both trees.
 | 
			
		||||
type diffDirOptions struct {
 | 
			
		||||
	diffDir      string
 | 
			
		||||
	skipChange   func(string) (bool, error)
 | 
			
		||||
	deleteChange func(string, string, os.FileInfo) (string, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// diffDirChanges walks the diff directory and compares changes against the base.
 | 
			
		||||
func diffDirChanges(ctx context.Context, changeFn ChangeFunc, base string, o *diffDirOptions) error {
 | 
			
		||||
	changedDirs := make(map[string]struct{})
 | 
			
		||||
	return filepath.Walk(o.diffDir, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Rebase path
 | 
			
		||||
		path, err = filepath.Rel(o.diffDir, path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = filepath.Join(string(os.PathSeparator), path)
 | 
			
		||||
 | 
			
		||||
		// Skip root
 | 
			
		||||
		if path == string(os.PathSeparator) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// TODO: handle opaqueness, start new double walker at this
 | 
			
		||||
		// location to get deletes, and skip tree in single walker
 | 
			
		||||
 | 
			
		||||
		if o.skipChange != nil {
 | 
			
		||||
			if skip, err := o.skipChange(path); skip {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		var kind ChangeKind
 | 
			
		||||
 | 
			
		||||
		deletedFile, err := o.deleteChange(o.diffDir, path, f)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Find out what kind of modification happened
 | 
			
		||||
		if deletedFile != "" {
 | 
			
		||||
			path = deletedFile
 | 
			
		||||
			kind = ChangeKindDelete
 | 
			
		||||
			f = nil
 | 
			
		||||
		} else {
 | 
			
		||||
			// Otherwise, the file was added
 | 
			
		||||
			kind = ChangeKindAdd
 | 
			
		||||
 | 
			
		||||
			// ...Unless it already existed in a base, in which case, it's a modification
 | 
			
		||||
			stat, err := os.Stat(filepath.Join(base, path))
 | 
			
		||||
			if err != nil && !os.IsNotExist(err) {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				// The file existed in the base, so that's a modification
 | 
			
		||||
 | 
			
		||||
				// However, if it's a directory, maybe it wasn't actually modified.
 | 
			
		||||
				// If you modify /foo/bar/baz, then /foo will be part of the changed files only because it's the parent of bar
 | 
			
		||||
				if stat.IsDir() && f.IsDir() {
 | 
			
		||||
					if f.Size() == stat.Size() && f.Mode() == stat.Mode() && sameFsTime(f.ModTime(), stat.ModTime()) {
 | 
			
		||||
						// Both directories are the same, don't record the change
 | 
			
		||||
						return nil
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				kind = ChangeKindModify
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If /foo/bar/file.txt is modified, then /foo/bar must be part of the changed files.
 | 
			
		||||
		// This block is here to ensure the change is recorded even if the
 | 
			
		||||
		// modify time, mode and size of the parent directory in the rw and ro layers are all equal.
 | 
			
		||||
		// Check https://github.com/docker/docker/pull/13590 for details.
 | 
			
		||||
		if f.IsDir() {
 | 
			
		||||
			changedDirs[path] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
		if kind == ChangeKindAdd || kind == ChangeKindDelete {
 | 
			
		||||
			parent := filepath.Dir(path)
 | 
			
		||||
			if _, ok := changedDirs[parent]; !ok && parent != "/" {
 | 
			
		||||
				pi, err := os.Stat(filepath.Join(o.diffDir, parent))
 | 
			
		||||
				if err := changeFn(ChangeKindModify, parent, pi, err); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				changedDirs[parent] = struct{}{}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return changeFn(kind, path, f, nil)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// doubleWalkDiff walks both directories to create a diff
 | 
			
		||||
func doubleWalkDiff(ctx context.Context, changeFn ChangeFunc, a, b string) (err error) {
 | 
			
		||||
	g, ctx := errgroup.WithContext(ctx)
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		c1 = make(chan *currentPath)
 | 
			
		||||
		c2 = make(chan *currentPath)
 | 
			
		||||
 | 
			
		||||
		f1, f2 *currentPath
 | 
			
		||||
		rmdir  string
 | 
			
		||||
	)
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		defer close(c1)
 | 
			
		||||
		return pathWalk(ctx, a, c1)
 | 
			
		||||
	})
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		defer close(c2)
 | 
			
		||||
		return pathWalk(ctx, b, c2)
 | 
			
		||||
	})
 | 
			
		||||
	g.Go(func() error {
 | 
			
		||||
		for c1 != nil || c2 != nil {
 | 
			
		||||
			if f1 == nil && c1 != nil {
 | 
			
		||||
				f1, err = nextPath(ctx, c1)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if f1 == nil {
 | 
			
		||||
					c1 = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if f2 == nil && c2 != nil {
 | 
			
		||||
				f2, err = nextPath(ctx, c2)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if f2 == nil {
 | 
			
		||||
					c2 = nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if f1 == nil && f2 == nil {
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			var f os.FileInfo
 | 
			
		||||
			k, p := pathChange(f1, f2)
 | 
			
		||||
			switch k {
 | 
			
		||||
			case ChangeKindAdd:
 | 
			
		||||
				if rmdir != "" {
 | 
			
		||||
					rmdir = ""
 | 
			
		||||
				}
 | 
			
		||||
				f = f2.f
 | 
			
		||||
				f2 = nil
 | 
			
		||||
			case ChangeKindDelete:
 | 
			
		||||
				// Check if this file is already removed by being
 | 
			
		||||
				// under of a removed directory
 | 
			
		||||
				if rmdir != "" && strings.HasPrefix(f1.path, rmdir) {
 | 
			
		||||
					f1 = nil
 | 
			
		||||
					continue
 | 
			
		||||
				} else if f1.f.IsDir() {
 | 
			
		||||
					rmdir = f1.path + string(os.PathSeparator)
 | 
			
		||||
				} else if rmdir != "" {
 | 
			
		||||
					rmdir = ""
 | 
			
		||||
				}
 | 
			
		||||
				f1 = nil
 | 
			
		||||
			case ChangeKindModify:
 | 
			
		||||
				same, err := sameFile(f1, f2)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if f1.f.IsDir() && !f2.f.IsDir() {
 | 
			
		||||
					rmdir = f1.path + string(os.PathSeparator)
 | 
			
		||||
				} else if rmdir != "" {
 | 
			
		||||
					rmdir = ""
 | 
			
		||||
				}
 | 
			
		||||
				f = f2.f
 | 
			
		||||
				f1 = nil
 | 
			
		||||
				f2 = nil
 | 
			
		||||
				if same {
 | 
			
		||||
					if !isLinked(f) {
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
					k = ChangeKindUnmodified
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			if err := changeFn(k, p, f, nil); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	return g.Wait()
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								vendor/github.com/containerd/continuity/fs/diff_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/containerd/continuity/fs/diff_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,74 +0,0 @@
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/sysx"
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// detectDirDiff returns diff dir options if a directory could
 | 
			
		||||
// be found in the mount info for upper which is the direct
 | 
			
		||||
// diff with the provided lower directory
 | 
			
		||||
func detectDirDiff(upper, lower string) *diffDirOptions {
 | 
			
		||||
	// TODO: get mount options for upper
 | 
			
		||||
	// TODO: detect AUFS
 | 
			
		||||
	// TODO: detect overlay
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// compareSysStat returns whether the stats are equivalent,
 | 
			
		||||
// whether the files are considered the same file, and
 | 
			
		||||
// an error
 | 
			
		||||
func compareSysStat(s1, s2 interface{}) (bool, error) {
 | 
			
		||||
	ls1, ok := s1.(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	ls2, ok := s2.(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ls1.Mode == ls2.Mode && ls1.Uid == ls2.Uid && ls1.Gid == ls2.Gid && ls1.Rdev == ls2.Rdev, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareCapabilities(p1, p2 string) (bool, error) {
 | 
			
		||||
	c1, err := sysx.LGetxattr(p1, "security.capability")
 | 
			
		||||
	if err != nil && err != sysx.ENODATA {
 | 
			
		||||
		return false, errors.Wrapf(err, "failed to get xattr for %s", p1)
 | 
			
		||||
	}
 | 
			
		||||
	c2, err := sysx.LGetxattr(p2, "security.capability")
 | 
			
		||||
	if err != nil && err != sysx.ENODATA {
 | 
			
		||||
		return false, errors.Wrapf(err, "failed to get xattr for %s", p2)
 | 
			
		||||
	}
 | 
			
		||||
	return bytes.Equal(c1, c2), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isLinked(f os.FileInfo) bool {
 | 
			
		||||
	s, ok := f.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return !f.IsDir() && s.Nlink > 1
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								vendor/github.com/containerd/continuity/fs/diff_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										48
									
								
								vendor/github.com/containerd/continuity/fs/diff_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,48 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/windows"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func detectDirDiff(upper, lower string) *diffDirOptions {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareSysStat(s1, s2 interface{}) (bool, error) {
 | 
			
		||||
	f1, ok := s1.(windows.Win32FileAttributeData)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	f2, ok := s2.(windows.Win32FileAttributeData)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
	return f1.FileAttributes == f2.FileAttributes, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareCapabilities(p1, p2 string) (bool, error) {
 | 
			
		||||
	// TODO: Use windows equivalent
 | 
			
		||||
	return true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isLinked(os.FileInfo) bool {
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										103
									
								
								vendor/github.com/containerd/continuity/fs/dtype_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/containerd/continuity/fs/dtype_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,103 +0,0 @@
 | 
			
		||||
// +build linux
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func locateDummyIfEmpty(path string) (string, error) {
 | 
			
		||||
	children, err := ioutil.ReadDir(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	if len(children) != 0 {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
	dummyFile, err := ioutil.TempFile(path, "fsutils-dummy")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	name := dummyFile.Name()
 | 
			
		||||
	err = dummyFile.Close()
 | 
			
		||||
	return name, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SupportsDType returns whether the filesystem mounted on path supports d_type
 | 
			
		||||
func SupportsDType(path string) (bool, error) {
 | 
			
		||||
	// locate dummy so that we have at least one dirent
 | 
			
		||||
	dummy, err := locateDummyIfEmpty(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	if dummy != "" {
 | 
			
		||||
		defer os.Remove(dummy)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	visited := 0
 | 
			
		||||
	supportsDType := true
 | 
			
		||||
	fn := func(ent *syscall.Dirent) bool {
 | 
			
		||||
		visited++
 | 
			
		||||
		if ent.Type == syscall.DT_UNKNOWN {
 | 
			
		||||
			supportsDType = false
 | 
			
		||||
			// stop iteration
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
		// continue iteration
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	if err = iterateReadDir(path, fn); err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	if visited == 0 {
 | 
			
		||||
		return false, fmt.Errorf("did not hit any dirent during iteration %s", path)
 | 
			
		||||
	}
 | 
			
		||||
	return supportsDType, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func iterateReadDir(path string, fn func(*syscall.Dirent) bool) error {
 | 
			
		||||
	d, err := os.Open(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	defer d.Close()
 | 
			
		||||
	fd := int(d.Fd())
 | 
			
		||||
	buf := make([]byte, 4096)
 | 
			
		||||
	for {
 | 
			
		||||
		nbytes, err := syscall.ReadDirent(fd, buf)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		if nbytes == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		for off := 0; off < nbytes; {
 | 
			
		||||
			ent := (*syscall.Dirent)(unsafe.Pointer(&buf[off]))
 | 
			
		||||
			if stop := fn(ent); stop {
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
			off += int(ent.Reclen)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								vendor/github.com/containerd/continuity/fs/du.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/containerd/continuity/fs/du.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,38 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import "context"
 | 
			
		||||
 | 
			
		||||
// Usage of disk information
 | 
			
		||||
type Usage struct {
 | 
			
		||||
	Inodes int64
 | 
			
		||||
	Size   int64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DiskUsage counts the number of inodes and disk usage for the resources under
 | 
			
		||||
// path.
 | 
			
		||||
func DiskUsage(ctx context.Context, roots ...string) (Usage, error) {
 | 
			
		||||
	return diskUsage(ctx, roots...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DiffUsage counts the numbers of inodes and disk usage in the
 | 
			
		||||
// diff between the 2 directories. The first path is intended
 | 
			
		||||
// as the base directory and the second as the changed directory.
 | 
			
		||||
func DiffUsage(ctx context.Context, a, b string) (Usage, error) {
 | 
			
		||||
	return diffUsage(ctx, a, b)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										110
									
								
								vendor/github.com/containerd/continuity/fs/du_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										110
									
								
								vendor/github.com/containerd/continuity/fs/du_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,110 +0,0 @@
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type inode struct {
 | 
			
		||||
	// TODO(stevvooe): Can probably reduce memory usage by not tracking
 | 
			
		||||
	// device, but we can leave this right for now.
 | 
			
		||||
	dev, ino uint64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newInode(stat *syscall.Stat_t) inode {
 | 
			
		||||
	return inode{
 | 
			
		||||
		// Dev is uint32 on darwin/bsd, uint64 on linux/solaris
 | 
			
		||||
		dev: uint64(stat.Dev), // nolint: unconvert
 | 
			
		||||
		// Ino is uint32 on bsd, uint64 on darwin/linux/solaris
 | 
			
		||||
		ino: uint64(stat.Ino), // nolint: unconvert
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		size   int64
 | 
			
		||||
		inodes = map[inode]struct{}{} // expensive!
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	for _, root := range roots {
 | 
			
		||||
		if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ctx.Done():
 | 
			
		||||
				return ctx.Err()
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			inoKey := newInode(fi.Sys().(*syscall.Stat_t))
 | 
			
		||||
			if _, ok := inodes[inoKey]; !ok {
 | 
			
		||||
				inodes[inoKey] = struct{}{}
 | 
			
		||||
				size += fi.Size()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
			return Usage{}, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Inodes: int64(len(inodes)),
 | 
			
		||||
		Size:   size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diffUsage(ctx context.Context, a, b string) (Usage, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		size   int64
 | 
			
		||||
		inodes = map[inode]struct{}{} // expensive!
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if kind == ChangeKindAdd || kind == ChangeKindModify {
 | 
			
		||||
			inoKey := newInode(fi.Sys().(*syscall.Stat_t))
 | 
			
		||||
			if _, ok := inodes[inoKey]; !ok {
 | 
			
		||||
				inodes[inoKey] = struct{}{}
 | 
			
		||||
				size += fi.Size()
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return Usage{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Inodes: int64(len(inodes)),
 | 
			
		||||
		Size:   size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								vendor/github.com/containerd/continuity/fs/du_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/containerd/continuity/fs/du_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,82 +0,0 @@
 | 
			
		||||
// +build windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func diskUsage(ctx context.Context, roots ...string) (Usage, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		size int64
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// TODO(stevvooe): Support inodes (or equivalent) for windows.
 | 
			
		||||
 | 
			
		||||
	for _, root := range roots {
 | 
			
		||||
		if err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			select {
 | 
			
		||||
			case <-ctx.Done():
 | 
			
		||||
				return ctx.Err()
 | 
			
		||||
			default:
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			size += fi.Size()
 | 
			
		||||
			return nil
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
			return Usage{}, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Size: size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func diffUsage(ctx context.Context, a, b string) (Usage, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		size int64
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if err := Changes(ctx, a, b, func(kind ChangeKind, _ string, fi os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if kind == ChangeKindAdd || kind == ChangeKindModify {
 | 
			
		||||
			size += fi.Size()
 | 
			
		||||
 | 
			
		||||
			return nil
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		return nil
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		return Usage{}, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Usage{
 | 
			
		||||
		Size: size,
 | 
			
		||||
	}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/hardlink.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/hardlink.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,43 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
// GetLinkInfo returns an identifier representing the node a hardlink is pointing
 | 
			
		||||
// to. If the file is not hard linked then 0 will be returned.
 | 
			
		||||
func GetLinkInfo(fi os.FileInfo) (uint64, bool) {
 | 
			
		||||
	return getLinkInfo(fi)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getLinkSource returns a path for the given name and
 | 
			
		||||
// file info to its link source in the provided inode
 | 
			
		||||
// map. If the given file name is not in the map and
 | 
			
		||||
// has other links, it is added to the inode map
 | 
			
		||||
// to be a source for other link locations.
 | 
			
		||||
func getLinkSource(name string, fi os.FileInfo, inodes map[uint64]string) (string, error) {
 | 
			
		||||
	inode, isHardlink := getLinkInfo(fi)
 | 
			
		||||
	if !isHardlink {
 | 
			
		||||
		return "", nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path, ok := inodes[inode]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		inodes[inode] = name
 | 
			
		||||
	}
 | 
			
		||||
	return path, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,34 +0,0 @@
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
 | 
			
		||||
	s, ok := fi.Sys().(*syscall.Stat_t)
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return 0, false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Ino is uint32 on bsd, uint64 on darwin/linux/solaris
 | 
			
		||||
	return uint64(s.Ino), !fi.IsDir() && s.Nlink > 1 // nolint: unconvert
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/containerd/continuity/fs/hardlink_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,23 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import "os"
 | 
			
		||||
 | 
			
		||||
func getLinkInfo(fi os.FileInfo) (uint64, bool) {
 | 
			
		||||
	return 0, false
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										313
									
								
								vendor/github.com/containerd/continuity/fs/path.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										313
									
								
								vendor/github.com/containerd/continuity/fs/path.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,313 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"context"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/pkg/errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	errTooManyLinks = errors.New("too many links")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type currentPath struct {
 | 
			
		||||
	path     string
 | 
			
		||||
	f        os.FileInfo
 | 
			
		||||
	fullPath string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pathChange(lower, upper *currentPath) (ChangeKind, string) {
 | 
			
		||||
	if lower == nil {
 | 
			
		||||
		if upper == nil {
 | 
			
		||||
			panic("cannot compare nil paths")
 | 
			
		||||
		}
 | 
			
		||||
		return ChangeKindAdd, upper.path
 | 
			
		||||
	}
 | 
			
		||||
	if upper == nil {
 | 
			
		||||
		return ChangeKindDelete, lower.path
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch i := directoryCompare(lower.path, upper.path); {
 | 
			
		||||
	case i < 0:
 | 
			
		||||
		// File in lower that is not in upper
 | 
			
		||||
		return ChangeKindDelete, lower.path
 | 
			
		||||
	case i > 0:
 | 
			
		||||
		// File in upper that is not in lower
 | 
			
		||||
		return ChangeKindAdd, upper.path
 | 
			
		||||
	default:
 | 
			
		||||
		return ChangeKindModify, upper.path
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func directoryCompare(a, b string) int {
 | 
			
		||||
	l := len(a)
 | 
			
		||||
	if len(b) < l {
 | 
			
		||||
		l = len(b)
 | 
			
		||||
	}
 | 
			
		||||
	for i := 0; i < l; i++ {
 | 
			
		||||
		c1, c2 := a[i], b[i]
 | 
			
		||||
		if c1 == filepath.Separator {
 | 
			
		||||
			c1 = byte(0)
 | 
			
		||||
		}
 | 
			
		||||
		if c2 == filepath.Separator {
 | 
			
		||||
			c2 = byte(0)
 | 
			
		||||
		}
 | 
			
		||||
		if c1 < c2 {
 | 
			
		||||
			return -1
 | 
			
		||||
		}
 | 
			
		||||
		if c1 > c2 {
 | 
			
		||||
			return +1
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if len(a) < len(b) {
 | 
			
		||||
		return -1
 | 
			
		||||
	}
 | 
			
		||||
	if len(a) > len(b) {
 | 
			
		||||
		return +1
 | 
			
		||||
	}
 | 
			
		||||
	return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func sameFile(f1, f2 *currentPath) (bool, error) {
 | 
			
		||||
	if os.SameFile(f1.f, f2.f) {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	equalStat, err := compareSysStat(f1.f.Sys(), f2.f.Sys())
 | 
			
		||||
	if err != nil || !equalStat {
 | 
			
		||||
		return equalStat, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if eq, err := compareCapabilities(f1.fullPath, f2.fullPath); err != nil || !eq {
 | 
			
		||||
		return eq, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// If not a directory also check size, modtime, and content
 | 
			
		||||
	if !f1.f.IsDir() {
 | 
			
		||||
		if f1.f.Size() != f2.f.Size() {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		t1 := f1.f.ModTime()
 | 
			
		||||
		t2 := f2.f.ModTime()
 | 
			
		||||
 | 
			
		||||
		if t1.Unix() != t2.Unix() {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// If the timestamp may have been truncated in both of the
 | 
			
		||||
		// files, check content of file to determine difference
 | 
			
		||||
		if t1.Nanosecond() == 0 && t2.Nanosecond() == 0 {
 | 
			
		||||
			var eq bool
 | 
			
		||||
			if (f1.f.Mode() & os.ModeSymlink) == os.ModeSymlink {
 | 
			
		||||
				eq, err = compareSymlinkTarget(f1.fullPath, f2.fullPath)
 | 
			
		||||
			} else if f1.f.Size() > 0 {
 | 
			
		||||
				eq, err = compareFileContent(f1.fullPath, f2.fullPath)
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil || !eq {
 | 
			
		||||
				return eq, err
 | 
			
		||||
			}
 | 
			
		||||
		} else if t1.Nanosecond() != t2.Nanosecond() {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func compareSymlinkTarget(p1, p2 string) (bool, error) {
 | 
			
		||||
	t1, err := os.Readlink(p1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	t2, err := os.Readlink(p2)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	return t1 == t2, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const compareChuckSize = 32 * 1024
 | 
			
		||||
 | 
			
		||||
// compareFileContent compares the content of 2 same sized files
 | 
			
		||||
// by comparing each byte.
 | 
			
		||||
func compareFileContent(p1, p2 string) (bool, error) {
 | 
			
		||||
	f1, err := os.Open(p1)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f1.Close()
 | 
			
		||||
	f2, err := os.Open(p2)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	}
 | 
			
		||||
	defer f2.Close()
 | 
			
		||||
 | 
			
		||||
	b1 := make([]byte, compareChuckSize)
 | 
			
		||||
	b2 := make([]byte, compareChuckSize)
 | 
			
		||||
	for {
 | 
			
		||||
		n1, err1 := f1.Read(b1)
 | 
			
		||||
		if err1 != nil && err1 != io.EOF {
 | 
			
		||||
			return false, err1
 | 
			
		||||
		}
 | 
			
		||||
		n2, err2 := f2.Read(b2)
 | 
			
		||||
		if err2 != nil && err2 != io.EOF {
 | 
			
		||||
			return false, err2
 | 
			
		||||
		}
 | 
			
		||||
		if n1 != n2 || !bytes.Equal(b1[:n1], b2[:n2]) {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		if err1 == io.EOF && err2 == io.EOF {
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pathWalk(ctx context.Context, root string, pathC chan<- *currentPath) error {
 | 
			
		||||
	return filepath.Walk(root, func(path string, f os.FileInfo, err error) error {
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Rebase path
 | 
			
		||||
		path, err = filepath.Rel(root, path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		path = filepath.Join(string(os.PathSeparator), path)
 | 
			
		||||
 | 
			
		||||
		// Skip root
 | 
			
		||||
		if path == string(os.PathSeparator) {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		p := ¤tPath{
 | 
			
		||||
			path:     path,
 | 
			
		||||
			f:        f,
 | 
			
		||||
			fullPath: filepath.Join(root, path),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ctx.Done():
 | 
			
		||||
			return ctx.Err()
 | 
			
		||||
		case pathC <- p:
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func nextPath(ctx context.Context, pathC <-chan *currentPath) (*currentPath, error) {
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
		return nil, ctx.Err()
 | 
			
		||||
	case p := <-pathC:
 | 
			
		||||
		return p, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RootPath joins a path with a root, evaluating and bounding any
 | 
			
		||||
// symlink to the root directory.
 | 
			
		||||
func RootPath(root, path string) (string, error) {
 | 
			
		||||
	if path == "" {
 | 
			
		||||
		return root, nil
 | 
			
		||||
	}
 | 
			
		||||
	var linksWalked int // to protect against cycles
 | 
			
		||||
	for {
 | 
			
		||||
		i := linksWalked
 | 
			
		||||
		newpath, err := walkLinks(root, path, &linksWalked)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		path = newpath
 | 
			
		||||
		if i == linksWalked {
 | 
			
		||||
			newpath = filepath.Join("/", newpath)
 | 
			
		||||
			if path == newpath {
 | 
			
		||||
				return filepath.Join(root, newpath), nil
 | 
			
		||||
			}
 | 
			
		||||
			path = newpath
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func walkLink(root, path string, linksWalked *int) (newpath string, islink bool, err error) {
 | 
			
		||||
	if *linksWalked > 255 {
 | 
			
		||||
		return "", false, errTooManyLinks
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path = filepath.Join("/", path)
 | 
			
		||||
	if path == "/" {
 | 
			
		||||
		return path, false, nil
 | 
			
		||||
	}
 | 
			
		||||
	realPath := filepath.Join(root, path)
 | 
			
		||||
 | 
			
		||||
	fi, err := os.Lstat(realPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		// If path does not yet exist, treat as non-symlink
 | 
			
		||||
		if os.IsNotExist(err) {
 | 
			
		||||
			return path, false, nil
 | 
			
		||||
		}
 | 
			
		||||
		return "", false, err
 | 
			
		||||
	}
 | 
			
		||||
	if fi.Mode()&os.ModeSymlink == 0 {
 | 
			
		||||
		return path, false, nil
 | 
			
		||||
	}
 | 
			
		||||
	newpath, err = os.Readlink(realPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", false, err
 | 
			
		||||
	}
 | 
			
		||||
	*linksWalked++
 | 
			
		||||
	return newpath, true, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func walkLinks(root, path string, linksWalked *int) (string, error) {
 | 
			
		||||
	switch dir, file := filepath.Split(path); {
 | 
			
		||||
	case dir == "":
 | 
			
		||||
		newpath, _, err := walkLink(root, file, linksWalked)
 | 
			
		||||
		return newpath, err
 | 
			
		||||
	case file == "":
 | 
			
		||||
		if os.IsPathSeparator(dir[len(dir)-1]) {
 | 
			
		||||
			if dir == "/" {
 | 
			
		||||
				return dir, nil
 | 
			
		||||
			}
 | 
			
		||||
			return walkLinks(root, dir[:len(dir)-1], linksWalked)
 | 
			
		||||
		}
 | 
			
		||||
		newpath, _, err := walkLink(root, dir, linksWalked)
 | 
			
		||||
		return newpath, err
 | 
			
		||||
	default:
 | 
			
		||||
		newdir, err := walkLinks(root, dir, linksWalked)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		newpath, islink, err := walkLink(root, filepath.Join(newdir, file), linksWalked)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return "", err
 | 
			
		||||
		}
 | 
			
		||||
		if !islink {
 | 
			
		||||
			return newpath, nil
 | 
			
		||||
		}
 | 
			
		||||
		if filepath.IsAbs(newpath) {
 | 
			
		||||
			return newpath, nil
 | 
			
		||||
		}
 | 
			
		||||
		return filepath.Join(newdir, newpath), nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								vendor/github.com/containerd/continuity/fs/stat_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/containerd/continuity/fs/stat_bsd.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,44 +0,0 @@
 | 
			
		||||
// +build darwin freebsd
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// StatAtime returns the access time from a stat struct
 | 
			
		||||
func StatAtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Atimespec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatCtime returns the created time from a stat struct
 | 
			
		||||
func StatCtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Ctimespec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatMtime returns the modified time from a stat struct
 | 
			
		||||
func StatMtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Mtimespec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatATimeAsTime returns the access time as a time.Time
 | 
			
		||||
func StatATimeAsTime(st *syscall.Stat_t) time.Time {
 | 
			
		||||
	return time.Unix(int64(st.Atimespec.Sec), int64(st.Atimespec.Nsec)) // nolint: unconvert
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/stat_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								vendor/github.com/containerd/continuity/fs/stat_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,43 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// StatAtime returns the Atim
 | 
			
		||||
func StatAtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Atim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatCtime returns the Ctim
 | 
			
		||||
func StatCtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Ctim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatMtime returns the Mtim
 | 
			
		||||
func StatMtime(st *syscall.Stat_t) syscall.Timespec {
 | 
			
		||||
	return st.Mtim
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// StatATimeAsTime returns st.Atim as a time.Time
 | 
			
		||||
func StatATimeAsTime(st *syscall.Stat_t) time.Time {
 | 
			
		||||
	// The int64 conversions ensure the line compiles for 32-bit systems as well.
 | 
			
		||||
	return time.Unix(int64(st.Atim.Sec), int64(st.Atim.Nsec)) // nolint: unconvert
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								vendor/github.com/containerd/continuity/fs/time.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/containerd/continuity/fs/time.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,29 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 fs
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
// Gnu tar and the go tar writer don't have sub-second mtime
 | 
			
		||||
// precision, which is problematic when we apply changes via tar
 | 
			
		||||
// files, we handle this by comparing for exact times, *or* same
 | 
			
		||||
// second count and either a or b having exactly 0 nanoseconds
 | 
			
		||||
func sameFsTime(a, b time.Time) bool {
 | 
			
		||||
	return a == b ||
 | 
			
		||||
		(a.Unix() == b.Unix() &&
 | 
			
		||||
			(a.Nanosecond() == 0 || b.Nanosecond() == 0))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										101
									
								
								vendor/github.com/containerd/continuity/pathdriver/path_driver.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										101
									
								
								vendor/github.com/containerd/continuity/pathdriver/path_driver.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,101 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 pathdriver
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// PathDriver provides all of the path manipulation functions in a common
 | 
			
		||||
// interface. The context should call these and never use the `filepath`
 | 
			
		||||
// package or any other package to manipulate paths.
 | 
			
		||||
type PathDriver interface {
 | 
			
		||||
	Join(paths ...string) string
 | 
			
		||||
	IsAbs(path string) bool
 | 
			
		||||
	Rel(base, target string) (string, error)
 | 
			
		||||
	Base(path string) string
 | 
			
		||||
	Dir(path string) string
 | 
			
		||||
	Clean(path string) string
 | 
			
		||||
	Split(path string) (dir, file string)
 | 
			
		||||
	Separator() byte
 | 
			
		||||
	Abs(path string) (string, error)
 | 
			
		||||
	Walk(string, filepath.WalkFunc) error
 | 
			
		||||
	FromSlash(path string) string
 | 
			
		||||
	ToSlash(path string) string
 | 
			
		||||
	Match(pattern, name string) (matched bool, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// pathDriver is a simple default implementation calls the filepath package.
 | 
			
		||||
type pathDriver struct{}
 | 
			
		||||
 | 
			
		||||
// LocalPathDriver is the exported pathDriver struct for convenience.
 | 
			
		||||
var LocalPathDriver PathDriver = &pathDriver{}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Join(paths ...string) string {
 | 
			
		||||
	return filepath.Join(paths...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) IsAbs(path string) bool {
 | 
			
		||||
	return filepath.IsAbs(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Rel(base, target string) (string, error) {
 | 
			
		||||
	return filepath.Rel(base, target)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Base(path string) string {
 | 
			
		||||
	return filepath.Base(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Dir(path string) string {
 | 
			
		||||
	return filepath.Dir(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Clean(path string) string {
 | 
			
		||||
	return filepath.Clean(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Split(path string) (dir, file string) {
 | 
			
		||||
	return filepath.Split(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Separator() byte {
 | 
			
		||||
	return filepath.Separator
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Abs(path string) (string, error) {
 | 
			
		||||
	return filepath.Abs(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Note that filepath.Walk calls os.Stat, so if the context wants to
 | 
			
		||||
// to call Driver.Stat() for Walk, they need to create a new struct that
 | 
			
		||||
// overrides this method.
 | 
			
		||||
func (*pathDriver) Walk(root string, walkFn filepath.WalkFunc) error {
 | 
			
		||||
	return filepath.Walk(root, walkFn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) FromSlash(path string) string {
 | 
			
		||||
	return filepath.FromSlash(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) ToSlash(path string) string {
 | 
			
		||||
	return filepath.ToSlash(path)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (*pathDriver) Match(pattern, name string) (bool, error) {
 | 
			
		||||
	return filepath.Match(pattern, name)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,26 +0,0 @@
 | 
			
		||||
// +build !windows
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 syscallx
 | 
			
		||||
 | 
			
		||||
import "syscall"
 | 
			
		||||
 | 
			
		||||
// Readlink returns the destination of the named symbolic link.
 | 
			
		||||
func Readlink(path string, buf []byte) (n int, err error) {
 | 
			
		||||
	return syscall.Readlink(path, buf)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										112
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/containerd/continuity/syscallx/syscall_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,112 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 syscallx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"unsafe"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type reparseDataBuffer struct {
 | 
			
		||||
	ReparseTag        uint32
 | 
			
		||||
	ReparseDataLength uint16
 | 
			
		||||
	Reserved          uint16
 | 
			
		||||
 | 
			
		||||
	// GenericReparseBuffer
 | 
			
		||||
	reparseBuffer byte
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type mountPointReparseBuffer struct {
 | 
			
		||||
	SubstituteNameOffset uint16
 | 
			
		||||
	SubstituteNameLength uint16
 | 
			
		||||
	PrintNameOffset      uint16
 | 
			
		||||
	PrintNameLength      uint16
 | 
			
		||||
	PathBuffer           [1]uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type symbolicLinkReparseBuffer struct {
 | 
			
		||||
	SubstituteNameOffset uint16
 | 
			
		||||
	SubstituteNameLength uint16
 | 
			
		||||
	PrintNameOffset      uint16
 | 
			
		||||
	PrintNameLength      uint16
 | 
			
		||||
	Flags                uint32
 | 
			
		||||
	PathBuffer           [1]uint16
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	_IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
 | 
			
		||||
	_SYMLINK_FLAG_RELATIVE      = 1
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Readlink returns the destination of the named symbolic link.
 | 
			
		||||
func Readlink(path string, buf []byte) (n int, err error) {
 | 
			
		||||
	fd, err := syscall.CreateFile(syscall.StringToUTF16Ptr(path), syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING,
 | 
			
		||||
		syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, err
 | 
			
		||||
	}
 | 
			
		||||
	defer syscall.CloseHandle(fd)
 | 
			
		||||
 | 
			
		||||
	rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
 | 
			
		||||
	var bytesReturned uint32
 | 
			
		||||
	err = syscall.DeviceIoControl(fd, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return -1, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
 | 
			
		||||
	var s string
 | 
			
		||||
	switch rdb.ReparseTag {
 | 
			
		||||
	case syscall.IO_REPARSE_TAG_SYMLINK:
 | 
			
		||||
		data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
 | 
			
		||||
		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
 | 
			
		||||
		s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
 | 
			
		||||
		if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 {
 | 
			
		||||
			if len(s) >= 4 && s[:4] == `\??\` {
 | 
			
		||||
				s = s[4:]
 | 
			
		||||
				switch {
 | 
			
		||||
				case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar
 | 
			
		||||
					// do nothing
 | 
			
		||||
				case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar
 | 
			
		||||
					s = `\\` + s[4:]
 | 
			
		||||
				default:
 | 
			
		||||
					// unexpected; do nothing
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				// unexpected; do nothing
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	case _IO_REPARSE_TAG_MOUNT_POINT:
 | 
			
		||||
		data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
 | 
			
		||||
		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
 | 
			
		||||
		s = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
 | 
			
		||||
		if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar
 | 
			
		||||
			if len(s) < 48 || s[:11] != `\??\Volume{` {
 | 
			
		||||
				s = s[4:]
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			// unexpected; do nothing
 | 
			
		||||
		}
 | 
			
		||||
	default:
 | 
			
		||||
		// the path is not a symlink or junction but another type of reparse
 | 
			
		||||
		// point
 | 
			
		||||
		return -1, syscall.ENOENT
 | 
			
		||||
	}
 | 
			
		||||
	n = copy(buf, []byte(s))
 | 
			
		||||
 | 
			
		||||
	return n, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/containerd/continuity/sysx/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/containerd/continuity/sysx/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +0,0 @@
 | 
			
		||||
This package is for internal use only. It is intended to only have
 | 
			
		||||
temporary changes before they are upstreamed to golang.org/x/sys/
 | 
			
		||||
(a.k.a. https://github.com/golang/sys).
 | 
			
		||||
							
								
								
									
										128
									
								
								vendor/github.com/containerd/continuity/sysx/file_posix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										128
									
								
								vendor/github.com/containerd/continuity/sysx/file_posix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,128 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
 | 
			
		||||
	"github.com/containerd/continuity/syscallx"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Readlink returns the destination of the named symbolic link.
 | 
			
		||||
// If there is an error, it will be of type *PathError.
 | 
			
		||||
func Readlink(name string) (string, error) {
 | 
			
		||||
	for len := 128; ; len *= 2 {
 | 
			
		||||
		b := make([]byte, len)
 | 
			
		||||
		n, e := fixCount(syscallx.Readlink(fixLongPath(name), b))
 | 
			
		||||
		if e != nil {
 | 
			
		||||
			return "", &os.PathError{Op: "readlink", Path: name, Err: e}
 | 
			
		||||
		}
 | 
			
		||||
		if n < len {
 | 
			
		||||
			return string(b[0:n]), nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Many functions in package syscall return a count of -1 instead of 0.
 | 
			
		||||
// Using fixCount(call()) instead of call() corrects the count.
 | 
			
		||||
func fixCount(n int, err error) (int, error) {
 | 
			
		||||
	if n < 0 {
 | 
			
		||||
		n = 0
 | 
			
		||||
	}
 | 
			
		||||
	return n, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// fixLongPath returns the extended-length (\\?\-prefixed) form of
 | 
			
		||||
// path when needed, in order to avoid the default 260 character file
 | 
			
		||||
// path limit imposed by Windows. If path is not easily converted to
 | 
			
		||||
// the extended-length form (for example, if path is a relative path
 | 
			
		||||
// or contains .. elements), or is short enough, fixLongPath returns
 | 
			
		||||
// path unmodified.
 | 
			
		||||
//
 | 
			
		||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
 | 
			
		||||
func fixLongPath(path string) string {
 | 
			
		||||
	// Do nothing (and don't allocate) if the path is "short".
 | 
			
		||||
	// Empirically (at least on the Windows Server 2013 builder),
 | 
			
		||||
	// the kernel is arbitrarily okay with < 248 bytes. That
 | 
			
		||||
	// matches what the docs above say:
 | 
			
		||||
	// "When using an API to create a directory, the specified
 | 
			
		||||
	// path cannot be so long that you cannot append an 8.3 file
 | 
			
		||||
	// name (that is, the directory name cannot exceed MAX_PATH
 | 
			
		||||
	// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
 | 
			
		||||
	//
 | 
			
		||||
	// The MSDN docs appear to say that a normal path that is 248 bytes long
 | 
			
		||||
	// will work; empirically the path must be less then 248 bytes long.
 | 
			
		||||
	if len(path) < 248 {
 | 
			
		||||
		// Don't fix. (This is how Go 1.7 and earlier worked,
 | 
			
		||||
		// not automatically generating the \\?\ form)
 | 
			
		||||
		return path
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// The extended form begins with \\?\, as in
 | 
			
		||||
	// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
 | 
			
		||||
	// The extended form disables evaluation of . and .. path
 | 
			
		||||
	// elements and disables the interpretation of / as equivalent
 | 
			
		||||
	// to \. The conversion here rewrites / to \ and elides
 | 
			
		||||
	// . elements as well as trailing or duplicate separators. For
 | 
			
		||||
	// simplicity it avoids the conversion entirely for relative
 | 
			
		||||
	// paths or paths containing .. elements. For now,
 | 
			
		||||
	// \\server\share paths are not converted to
 | 
			
		||||
	// \\?\UNC\server\share paths because the rules for doing so
 | 
			
		||||
	// are less well-specified.
 | 
			
		||||
	if len(path) >= 2 && path[:2] == `\\` {
 | 
			
		||||
		// Don't canonicalize UNC paths.
 | 
			
		||||
		return path
 | 
			
		||||
	}
 | 
			
		||||
	if !filepath.IsAbs(path) {
 | 
			
		||||
		// Relative path
 | 
			
		||||
		return path
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const prefix = `\\?`
 | 
			
		||||
 | 
			
		||||
	pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
 | 
			
		||||
	copy(pathbuf, prefix)
 | 
			
		||||
	n := len(path)
 | 
			
		||||
	r, w := 0, len(prefix)
 | 
			
		||||
	for r < n {
 | 
			
		||||
		switch {
 | 
			
		||||
		case os.IsPathSeparator(path[r]):
 | 
			
		||||
			// empty block
 | 
			
		||||
			r++
 | 
			
		||||
		case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
 | 
			
		||||
			// /./
 | 
			
		||||
			r++
 | 
			
		||||
		case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
 | 
			
		||||
			// /../ is currently unhandled
 | 
			
		||||
			return path
 | 
			
		||||
		default:
 | 
			
		||||
			pathbuf[w] = '\\'
 | 
			
		||||
			w++
 | 
			
		||||
			for ; r < n && !os.IsPathSeparator(path[r]); r++ {
 | 
			
		||||
				pathbuf[w] = path[r]
 | 
			
		||||
				w++
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// A drive's root directory needs a trailing \
 | 
			
		||||
	if w == len(`\\?\c:`) {
 | 
			
		||||
		pathbuf[w] = '\\'
 | 
			
		||||
		w++
 | 
			
		||||
	}
 | 
			
		||||
	return string(pathbuf[:w])
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										52
									
								
								vendor/github.com/containerd/continuity/sysx/generate.sh
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/containerd/continuity/sysx/generate.sh
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,52 +0,0 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
 | 
			
		||||
#   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
#   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.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
mksyscall="$(go env GOROOT)/src/syscall/mksyscall.pl"
 | 
			
		||||
 | 
			
		||||
fix() {
 | 
			
		||||
	sed 's,^package syscall$,package sysx,' \
 | 
			
		||||
		| sed 's,^import "unsafe"$,import (\n\t"syscall"\n\t"unsafe"\n),' \
 | 
			
		||||
		| gofmt -r='BytePtrFromString -> syscall.BytePtrFromString' \
 | 
			
		||||
		| gofmt -r='Syscall6 -> syscall.Syscall6' \
 | 
			
		||||
		| gofmt -r='Syscall -> syscall.Syscall' \
 | 
			
		||||
		| gofmt -r='SYS_GETXATTR -> syscall.SYS_GETXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LISTXATTR -> syscall.SYS_LISTXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_SETXATTR -> syscall.SYS_SETXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_REMOVEXATTR -> syscall.SYS_REMOVEXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LGETXATTR -> syscall.SYS_LGETXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LLISTXATTR -> syscall.SYS_LLISTXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LSETXATTR -> syscall.SYS_LSETXATTR' \
 | 
			
		||||
		| gofmt -r='SYS_LREMOVEXATTR -> syscall.SYS_LREMOVEXATTR'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if [ "$GOARCH" == "" ] || [ "$GOOS" == "" ]; then
 | 
			
		||||
	echo "Must specify \$GOARCH and \$GOOS"
 | 
			
		||||
	exit 1
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
mkargs=""
 | 
			
		||||
 | 
			
		||||
if [ "$GOARCH" == "386" ] || [ "$GOARCH" == "arm" ]; then
 | 
			
		||||
	mkargs="-l32"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
for f in "$@"; do
 | 
			
		||||
	$mksyscall $mkargs "${f}_${GOOS}.go" | fix > "${f}_${GOOS}_${GOARCH}.go"
 | 
			
		||||
done
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_linux.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,23 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ENODATA = syscall.ENODATA
 | 
			
		||||
							
								
								
									
										24
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,24 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// This should actually be a set that contains ENOENT and EPERM
 | 
			
		||||
const ENODATA = syscall.ENOENT
 | 
			
		||||
							
								
								
									
										25
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								vendor/github.com/containerd/continuity/sysx/nodata_unix.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,25 +0,0 @@
 | 
			
		||||
// +build darwin freebsd
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"syscall"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const ENODATA = syscall.ENOATTR
 | 
			
		||||
							
								
								
									
										125
									
								
								vendor/github.com/containerd/continuity/sysx/xattr.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										125
									
								
								vendor/github.com/containerd/continuity/sysx/xattr.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,125 +0,0 @@
 | 
			
		||||
// +build linux darwin
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"syscall"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/sys/unix"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Listxattr calls syscall listxattr and reads all content
 | 
			
		||||
// and returns a string array
 | 
			
		||||
func Listxattr(path string) ([]string, error) {
 | 
			
		||||
	return listxattrAll(path, unix.Listxattr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Removexattr calls syscall removexattr
 | 
			
		||||
func Removexattr(path string, attr string) (err error) {
 | 
			
		||||
	return unix.Removexattr(path, attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Setxattr calls syscall setxattr
 | 
			
		||||
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 | 
			
		||||
	return unix.Setxattr(path, attr, data, flags)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Getxattr calls syscall getxattr
 | 
			
		||||
func Getxattr(path, attr string) ([]byte, error) {
 | 
			
		||||
	return getxattrAll(path, attr, unix.Getxattr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LListxattr lists xattrs, not following symlinks
 | 
			
		||||
func LListxattr(path string) ([]string, error) {
 | 
			
		||||
	return listxattrAll(path, unix.Llistxattr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LRemovexattr removes an xattr, not following symlinks
 | 
			
		||||
func LRemovexattr(path string, attr string) (err error) {
 | 
			
		||||
	return unix.Lremovexattr(path, attr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LSetxattr sets an xattr, not following symlinks
 | 
			
		||||
func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
 | 
			
		||||
	return unix.Lsetxattr(path, attr, data, flags)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LGetxattr gets an xattr, not following symlinks
 | 
			
		||||
func LGetxattr(path, attr string) ([]byte, error) {
 | 
			
		||||
	return getxattrAll(path, attr, unix.Lgetxattr)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const defaultXattrBufferSize = 5
 | 
			
		||||
 | 
			
		||||
type listxattrFunc func(path string, dest []byte) (int, error)
 | 
			
		||||
 | 
			
		||||
func listxattrAll(path string, listFunc listxattrFunc) ([]string, error) {
 | 
			
		||||
	var p []byte // nil on first execution
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		n, err := listFunc(path, p) // first call gets buffer size.
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if n > len(p) {
 | 
			
		||||
			p = make([]byte, n)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		p = p[:n]
 | 
			
		||||
 | 
			
		||||
		ps := bytes.Split(bytes.TrimSuffix(p, []byte{0}), []byte{0})
 | 
			
		||||
		var entries []string
 | 
			
		||||
		for _, p := range ps {
 | 
			
		||||
			s := string(p)
 | 
			
		||||
			if s != "" {
 | 
			
		||||
				entries = append(entries, s)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return entries, nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type getxattrFunc func(string, string, []byte) (int, error)
 | 
			
		||||
 | 
			
		||||
func getxattrAll(path, attr string, getFunc getxattrFunc) ([]byte, error) {
 | 
			
		||||
	p := make([]byte, defaultXattrBufferSize)
 | 
			
		||||
	for {
 | 
			
		||||
		n, err := getFunc(path, attr, p)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if errno, ok := err.(syscall.Errno); ok && errno == syscall.ERANGE {
 | 
			
		||||
				p = make([]byte, len(p)*2) // this can't be ideal.
 | 
			
		||||
				continue                   // try again!
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// realloc to correct size and repeat
 | 
			
		||||
		if n > len(p) {
 | 
			
		||||
			p = make([]byte, n)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return p[:n], nil
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										67
									
								
								vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										67
									
								
								vendor/github.com/containerd/continuity/sysx/xattr_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,67 +0,0 @@
 | 
			
		||||
// +build !linux,!darwin
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
   Copyright The containerd Authors.
 | 
			
		||||
 | 
			
		||||
   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 sysx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"runtime"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var unsupported = errors.New("extended attributes unsupported on " + runtime.GOOS)
 | 
			
		||||
 | 
			
		||||
// Listxattr calls syscall listxattr and reads all content
 | 
			
		||||
// and returns a string array
 | 
			
		||||
func Listxattr(path string) ([]string, error) {
 | 
			
		||||
	return []string{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Removexattr calls syscall removexattr
 | 
			
		||||
func Removexattr(path string, attr string) (err error) {
 | 
			
		||||
	return unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Setxattr calls syscall setxattr
 | 
			
		||||
func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 | 
			
		||||
	return unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Getxattr calls syscall getxattr
 | 
			
		||||
func Getxattr(path, attr string) ([]byte, error) {
 | 
			
		||||
	return []byte{}, unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LListxattr lists xattrs, not following symlinks
 | 
			
		||||
func LListxattr(path string) ([]string, error) {
 | 
			
		||||
	return []string{}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LRemovexattr removes an xattr, not following symlinks
 | 
			
		||||
func LRemovexattr(path string, attr string) (err error) {
 | 
			
		||||
	return unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LSetxattr sets an xattr, not following symlinks
 | 
			
		||||
func LSetxattr(path string, attr string, data []byte, flags int) (err error) {
 | 
			
		||||
	return unsupported
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LGetxattr gets an xattr, not following symlinks
 | 
			
		||||
func LGetxattr(path, attr string) ([]byte, error) {
 | 
			
		||||
	return []byte{}, nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								vendor/github.com/coreos/go-oidc/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/coreos/go-oidc/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,2 +0,0 @@
 | 
			
		||||
/bin
 | 
			
		||||
/gopath
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/github.com/coreos/go-oidc/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/coreos/go-oidc/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,16 +0,0 @@
 | 
			
		||||
language: go
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - "1.12"
 | 
			
		||||
  - "1.13"
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
 - go get -v -t github.com/coreos/go-oidc/...
 | 
			
		||||
 - go get golang.org/x/tools/cmd/cover
 | 
			
		||||
 - go get golang.org/x/lint/golint
 | 
			
		||||
 | 
			
		||||
script:
 | 
			
		||||
 - ./test
 | 
			
		||||
 | 
			
		||||
notifications:
 | 
			
		||||
  email: false
 | 
			
		||||
							
								
								
									
										71
									
								
								vendor/github.com/coreos/go-oidc/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/coreos/go-oidc/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,71 +0,0 @@
 | 
			
		||||
# How to Contribute
 | 
			
		||||
 | 
			
		||||
CoreOS projects are [Apache 2.0 licensed](LICENSE) and accept contributions via
 | 
			
		||||
GitHub pull requests.  This document outlines some of the conventions on
 | 
			
		||||
development workflow, commit message formatting, contact points and other
 | 
			
		||||
resources to make it easier to get your contribution accepted.
 | 
			
		||||
 | 
			
		||||
# Certificate of Origin
 | 
			
		||||
 | 
			
		||||
By contributing to this project you agree to the Developer Certificate of
 | 
			
		||||
Origin (DCO). This document was created by the Linux Kernel community and is a
 | 
			
		||||
simple statement that you, as a contributor, have the legal right to make the
 | 
			
		||||
contribution. See the [DCO](DCO) file for details.
 | 
			
		||||
 | 
			
		||||
# Email and Chat
 | 
			
		||||
 | 
			
		||||
The project currently uses the general CoreOS email list and IRC channel:
 | 
			
		||||
- Email: [coreos-dev](https://groups.google.com/forum/#!forum/coreos-dev)
 | 
			
		||||
- IRC: #[coreos](irc://irc.freenode.org:6667/#coreos) IRC channel on freenode.org
 | 
			
		||||
 | 
			
		||||
Please avoid emailing maintainers found in the MAINTAINERS file directly. They
 | 
			
		||||
are very busy and read the mailing lists.
 | 
			
		||||
 | 
			
		||||
## Getting Started
 | 
			
		||||
 | 
			
		||||
- Fork the repository on GitHub
 | 
			
		||||
- Read the [README](README.md) for build and test instructions
 | 
			
		||||
- Play with the project, submit bugs, submit patches!
 | 
			
		||||
 | 
			
		||||
## Contribution Flow
 | 
			
		||||
 | 
			
		||||
This is a rough outline of what a contributor's workflow looks like:
 | 
			
		||||
 | 
			
		||||
- Create a topic branch from where you want to base your work (usually master).
 | 
			
		||||
- Make commits of logical units.
 | 
			
		||||
- Make sure your commit messages are in the proper format (see below).
 | 
			
		||||
- Push your changes to a topic branch in your fork of the repository.
 | 
			
		||||
- Make sure the tests pass, and add any new tests as appropriate.
 | 
			
		||||
- Submit a pull request to the original repository.
 | 
			
		||||
 | 
			
		||||
Thanks for your contributions!
 | 
			
		||||
 | 
			
		||||
### Format of the Commit Message
 | 
			
		||||
 | 
			
		||||
We follow a rough convention for commit messages that is designed to answer two
 | 
			
		||||
questions: what changed and why. The subject line should feature the what and
 | 
			
		||||
the body of the commit should describe the why.
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
scripts: add the test-cluster command
 | 
			
		||||
 | 
			
		||||
this uses tmux to setup a test cluster that you can easily kill and
 | 
			
		||||
start for debugging.
 | 
			
		||||
 | 
			
		||||
Fixes #38
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The format can be described more formally as follows:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
<subsystem>: <what changed>
 | 
			
		||||
<BLANK LINE>
 | 
			
		||||
<why this change was made>
 | 
			
		||||
<BLANK LINE>
 | 
			
		||||
<footer>
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The first line is the subject and should be no longer than 70 characters, the
 | 
			
		||||
second line is always blank, and other lines should be wrapped at 80 characters.
 | 
			
		||||
This allows the message to be easier to read on GitHub as well as in various
 | 
			
		||||
git tools.
 | 
			
		||||
							
								
								
									
										36
									
								
								vendor/github.com/coreos/go-oidc/DCO
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								vendor/github.com/coreos/go-oidc/DCO
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,36 +0,0 @@
 | 
			
		||||
Developer Certificate of Origin
 | 
			
		||||
Version 1.1
 | 
			
		||||
 | 
			
		||||
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
 | 
			
		||||
660 York Street, Suite 102,
 | 
			
		||||
San Francisco, CA 94110 USA
 | 
			
		||||
 | 
			
		||||
Everyone is permitted to copy and distribute verbatim copies of this
 | 
			
		||||
license document, but changing it is not allowed.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Developer's Certificate of Origin 1.1
 | 
			
		||||
 | 
			
		||||
By making a contribution to this project, I certify that:
 | 
			
		||||
 | 
			
		||||
(a) The contribution was created in whole or in part by me and I
 | 
			
		||||
    have the right to submit it under the open source license
 | 
			
		||||
    indicated in the file; or
 | 
			
		||||
 | 
			
		||||
(b) The contribution is based upon previous work that, to the best
 | 
			
		||||
    of my knowledge, is covered under an appropriate open source
 | 
			
		||||
    license and I have the right under that license to submit that
 | 
			
		||||
    work with modifications, whether created in whole or in part
 | 
			
		||||
    by me, under the same open source license (unless I am
 | 
			
		||||
    permitted to submit under a different license), as indicated
 | 
			
		||||
    in the file; or
 | 
			
		||||
 | 
			
		||||
(c) The contribution was provided directly to me by some other
 | 
			
		||||
    person who certified (a), (b) or (c) and I have not modified
 | 
			
		||||
    it.
 | 
			
		||||
 | 
			
		||||
(d) I understand and agree that this project and the contribution
 | 
			
		||||
    are public and that a record of the contribution (including all
 | 
			
		||||
    personal information I submit with it, including my sign-off) is
 | 
			
		||||
    maintained indefinitely and may be redistributed consistent with
 | 
			
		||||
    this project or the open source license(s) involved.
 | 
			
		||||
							
								
								
									
										202
									
								
								vendor/github.com/coreos/go-oidc/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										202
									
								
								vendor/github.com/coreos/go-oidc/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,202 +0,0 @@
 | 
			
		||||
Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
   1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
   END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
   APPENDIX: How to apply the Apache License to your work.
 | 
			
		||||
 | 
			
		||||
      To apply the Apache License to your work, attach the following
 | 
			
		||||
      boilerplate notice, with the fields enclosed by brackets "{}"
 | 
			
		||||
      replaced with your own identifying information. (Don't include
 | 
			
		||||
      the brackets!)  The text should be enclosed in the appropriate
 | 
			
		||||
      comment syntax for the file format. We also recommend that a
 | 
			
		||||
      file or class name and description of purpose be included on the
 | 
			
		||||
      same "printed page" as the copyright notice for easier
 | 
			
		||||
      identification within third-party archives.
 | 
			
		||||
 | 
			
		||||
   Copyright {yyyy} {name of copyright owner}
 | 
			
		||||
 | 
			
		||||
   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.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								vendor/github.com/coreos/go-oidc/MAINTAINERS
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/coreos/go-oidc/MAINTAINERS
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,3 +0,0 @@
 | 
			
		||||
Eric Chiang <ericchiang@google.com> (@ericchiang)
 | 
			
		||||
Mike Danese <mikedanese@google.com> (@mikedanese)
 | 
			
		||||
Rithu Leena John <rjohn@redhat.com> (@rithujohn191)
 | 
			
		||||
							
								
								
									
										5
									
								
								vendor/github.com/coreos/go-oidc/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/coreos/go-oidc/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,5 +0,0 @@
 | 
			
		||||
CoreOS Project
 | 
			
		||||
Copyright 2014 CoreOS, Inc
 | 
			
		||||
 | 
			
		||||
This product includes software developed at CoreOS, Inc.
 | 
			
		||||
(http://www.coreos.com/).
 | 
			
		||||
							
								
								
									
										72
									
								
								vendor/github.com/coreos/go-oidc/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										72
									
								
								vendor/github.com/coreos/go-oidc/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,72 +0,0 @@
 | 
			
		||||
# go-oidc
 | 
			
		||||
 | 
			
		||||
[](https://godoc.org/github.com/coreos/go-oidc)
 | 
			
		||||
[](https://travis-ci.org/coreos/go-oidc)
 | 
			
		||||
 | 
			
		||||
## OpenID Connect support for Go
 | 
			
		||||
 | 
			
		||||
This package enables OpenID Connect support for the [golang.org/x/oauth2](https://godoc.org/golang.org/x/oauth2) package.
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
provider, err := oidc.NewProvider(ctx, "https://accounts.google.com")
 | 
			
		||||
if err != nil {
 | 
			
		||||
    // handle error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Configure an OpenID Connect aware OAuth2 client.
 | 
			
		||||
oauth2Config := oauth2.Config{
 | 
			
		||||
    ClientID:     clientID,
 | 
			
		||||
    ClientSecret: clientSecret,
 | 
			
		||||
    RedirectURL:  redirectURL,
 | 
			
		||||
 | 
			
		||||
    // Discovery returns the OAuth2 endpoints.
 | 
			
		||||
    Endpoint: provider.Endpoint(),
 | 
			
		||||
 | 
			
		||||
    // "openid" is a required scope for OpenID Connect flows.
 | 
			
		||||
    Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
OAuth2 redirects are unchanged.
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
func handleRedirect(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
    http.Redirect(w, r, oauth2Config.AuthCodeURL(state), http.StatusFound)
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The on responses, the provider can be used to verify ID Tokens.
 | 
			
		||||
 | 
			
		||||
```go
 | 
			
		||||
var verifier = provider.Verifier(&oidc.Config{ClientID: clientID})
 | 
			
		||||
 | 
			
		||||
func handleOAuth2Callback(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
    // Verify state and errors.
 | 
			
		||||
 | 
			
		||||
    oauth2Token, err := oauth2Config.Exchange(ctx, r.URL.Query().Get("code"))
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        // handle error
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Extract the ID Token from OAuth2 token.
 | 
			
		||||
    rawIDToken, ok := oauth2Token.Extra("id_token").(string)
 | 
			
		||||
    if !ok {
 | 
			
		||||
        // handle missing token
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Parse and verify ID Token payload.
 | 
			
		||||
    idToken, err := verifier.Verify(ctx, rawIDToken)
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        // handle error
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Extract custom claims
 | 
			
		||||
    var claims struct {
 | 
			
		||||
        Email    string `json:"email"`
 | 
			
		||||
        Verified bool   `json:"email_verified"`
 | 
			
		||||
    }
 | 
			
		||||
    if err := idToken.Claims(&claims); err != nil {
 | 
			
		||||
        // handle error
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										61
									
								
								vendor/github.com/coreos/go-oidc/code-of-conduct.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										61
									
								
								vendor/github.com/coreos/go-oidc/code-of-conduct.md
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,61 +0,0 @@
 | 
			
		||||
## CoreOS Community Code of Conduct
 | 
			
		||||
 | 
			
		||||
### Contributor Code of Conduct
 | 
			
		||||
 | 
			
		||||
As contributors and maintainers of this project, and in the interest of
 | 
			
		||||
fostering an open and welcoming community, we pledge to respect all people who
 | 
			
		||||
contribute through reporting issues, posting feature requests, updating
 | 
			
		||||
documentation, submitting pull requests or patches, and other activities.
 | 
			
		||||
 | 
			
		||||
We are committed to making participation in this project a harassment-free
 | 
			
		||||
experience for everyone, regardless of level of experience, gender, gender
 | 
			
		||||
identity and expression, sexual orientation, disability, personal appearance,
 | 
			
		||||
body size, race, ethnicity, age, religion, or nationality.
 | 
			
		||||
 | 
			
		||||
Examples of unacceptable behavior by participants include:
 | 
			
		||||
 | 
			
		||||
* The use of sexualized language or imagery
 | 
			
		||||
* Personal attacks
 | 
			
		||||
* Trolling or insulting/derogatory comments
 | 
			
		||||
* Public or private harassment
 | 
			
		||||
* Publishing others' private information, such as physical or electronic addresses, without explicit permission
 | 
			
		||||
* Other unethical or unprofessional conduct.
 | 
			
		||||
 | 
			
		||||
Project maintainers have the right and responsibility to remove, edit, or
 | 
			
		||||
reject comments, commits, code, wiki edits, issues, and other contributions
 | 
			
		||||
that are not aligned to this Code of Conduct. By adopting this Code of Conduct,
 | 
			
		||||
project maintainers commit themselves to fairly and consistently applying these
 | 
			
		||||
principles to every aspect of managing this project. Project maintainers who do
 | 
			
		||||
not follow or enforce the Code of Conduct may be permanently removed from the
 | 
			
		||||
project team.
 | 
			
		||||
 | 
			
		||||
This code of conduct applies both within project spaces and in public spaces
 | 
			
		||||
when an individual is representing the project or its community.
 | 
			
		||||
 | 
			
		||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
 | 
			
		||||
reported by contacting a project maintainer, Brandon Philips
 | 
			
		||||
<brandon.philips@coreos.com>, and/or Rithu John <rithu.john@coreos.com>.
 | 
			
		||||
 | 
			
		||||
This Code of Conduct is adapted from the Contributor Covenant
 | 
			
		||||
(http://contributor-covenant.org), version 1.2.0, available at
 | 
			
		||||
http://contributor-covenant.org/version/1/2/0/
 | 
			
		||||
 | 
			
		||||
### CoreOS Events Code of Conduct
 | 
			
		||||
 | 
			
		||||
CoreOS events are working conferences intended for professional networking and
 | 
			
		||||
collaboration in the CoreOS community. Attendees are expected to behave
 | 
			
		||||
according to professional standards and in accordance with their employer’s
 | 
			
		||||
policies on appropriate workplace behavior.
 | 
			
		||||
 | 
			
		||||
While at CoreOS events or related social networking opportunities, attendees
 | 
			
		||||
should not engage in discriminatory or offensive speech or actions including
 | 
			
		||||
but not limited to gender, sexuality, race, age, disability, or religion.
 | 
			
		||||
Speakers should be especially aware of these concerns.
 | 
			
		||||
 | 
			
		||||
CoreOS does not condone any statements by speakers contrary to these standards.
 | 
			
		||||
CoreOS reserves the right to deny entrance and/or eject from an event (without
 | 
			
		||||
refund) any individual found to be engaging in discriminatory or offensive
 | 
			
		||||
speech or actions.
 | 
			
		||||
 | 
			
		||||
Please bring any concerns to the immediate attention of designated on-site
 | 
			
		||||
staff, Brandon Philips <brandon.philips@coreos.com>, and/or Rithu John <rithu.john@coreos.com>.
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user