Remove vendor folder
This commit is contained in:
parent
df34848caa
commit
f29b54d11c
2217 changed files with 0 additions and 1088029 deletions
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 @@
|
||||||
[![Build Status](https://travis-ci.org/beevik/etree.svg?branch=master)](https://travis-ci.org/beevik/etree)
|
|
||||||
[![GoDoc](https://godoc.org/github.com/beevik/etree?status.svg)](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
|
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/cespare/xxhash?status.svg)](https://godoc.org/github.com/cespare/xxhash)
|
|
||||||
[![Build Status](https://travis-ci.org/cespare/xxhash.svg?branch=master)](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
|
|
||||||
|
|
||||||
[![GoDoc](https://godoc.org/github.com/coreos/go-oidc?status.svg)](https://godoc.org/github.com/coreos/go-oidc)
|
|
||||||
[![Build Status](https://travis-ci.org/coreos/go-oidc.png?branch=master)](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>.
|
|
20
vendor/github.com/coreos/go-oidc/jose.go
generated
vendored
20
vendor/github.com/coreos/go-oidc/jose.go
generated
vendored
|
@ -1,20 +0,0 @@
|
||||||
// +build !golint
|
|
||||||
|
|
||||||
// Don't lint this file. We don't want to have to add a comment to each constant.
|
|
||||||
|
|
||||||
package oidc
|
|
||||||
|
|
||||||
const (
|
|
||||||
// JOSE asymmetric signing algorithm values as defined by RFC 7518
|
|
||||||
//
|
|
||||||
// see: https://tools.ietf.org/html/rfc7518#section-3.1
|
|
||||||
RS256 = "RS256" // RSASSA-PKCS-v1.5 using SHA-256
|
|
||||||
RS384 = "RS384" // RSASSA-PKCS-v1.5 using SHA-384
|
|
||||||
RS512 = "RS512" // RSASSA-PKCS-v1.5 using SHA-512
|
|
||||||
ES256 = "ES256" // ECDSA using P-256 and SHA-256
|
|
||||||
ES384 = "ES384" // ECDSA using P-384 and SHA-384
|
|
||||||
ES512 = "ES512" // ECDSA using P-521 and SHA-512
|
|
||||||
PS256 = "PS256" // RSASSA-PSS using SHA256 and MGF1-SHA256
|
|
||||||
PS384 = "PS384" // RSASSA-PSS using SHA384 and MGF1-SHA384
|
|
||||||
PS512 = "PS512" // RSASSA-PSS using SHA512 and MGF1-SHA512
|
|
||||||
)
|
|
228
vendor/github.com/coreos/go-oidc/jwks.go
generated
vendored
228
vendor/github.com/coreos/go-oidc/jwks.go
generated
vendored
|
@ -1,228 +0,0 @@
|
||||||
package oidc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/pquerna/cachecontrol"
|
|
||||||
jose "gopkg.in/square/go-jose.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// keysExpiryDelta is the allowed clock skew between a client and the OpenID Connect
|
|
||||||
// server.
|
|
||||||
//
|
|
||||||
// When keys expire, they are valid for this amount of time after.
|
|
||||||
//
|
|
||||||
// If the keys have not expired, and an ID Token claims it was signed by a key not in
|
|
||||||
// the cache, if and only if the keys expire in this amount of time, the keys will be
|
|
||||||
// updated.
|
|
||||||
const keysExpiryDelta = 30 * time.Second
|
|
||||||
|
|
||||||
// NewRemoteKeySet returns a KeySet that can validate JSON web tokens by using HTTP
|
|
||||||
// GETs to fetch JSON web token sets hosted at a remote URL. This is automatically
|
|
||||||
// used by NewProvider using the URLs returned by OpenID Connect discovery, but is
|
|
||||||
// exposed for providers that don't support discovery or to prevent round trips to the
|
|
||||||
// discovery URL.
|
|
||||||
//
|
|
||||||
// The returned KeySet is a long lived verifier that caches keys based on cache-control
|
|
||||||
// headers. Reuse a common remote key set instead of creating new ones as needed.
|
|
||||||
//
|
|
||||||
// The behavior of the returned KeySet is undefined once the context is canceled.
|
|
||||||
func NewRemoteKeySet(ctx context.Context, jwksURL string) KeySet {
|
|
||||||
return newRemoteKeySet(ctx, jwksURL, time.Now)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRemoteKeySet(ctx context.Context, jwksURL string, now func() time.Time) *remoteKeySet {
|
|
||||||
if now == nil {
|
|
||||||
now = time.Now
|
|
||||||
}
|
|
||||||
return &remoteKeySet{jwksURL: jwksURL, ctx: ctx, now: now}
|
|
||||||
}
|
|
||||||
|
|
||||||
type remoteKeySet struct {
|
|
||||||
jwksURL string
|
|
||||||
ctx context.Context
|
|
||||||
now func() time.Time
|
|
||||||
|
|
||||||
// guard all other fields
|
|
||||||
mu sync.Mutex
|
|
||||||
|
|
||||||
// inflight suppresses parallel execution of updateKeys and allows
|
|
||||||
// multiple goroutines to wait for its result.
|
|
||||||
inflight *inflight
|
|
||||||
|
|
||||||
// A set of cached keys and their expiry.
|
|
||||||
cachedKeys []jose.JSONWebKey
|
|
||||||
expiry time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// inflight is used to wait on some in-flight request from multiple goroutines.
|
|
||||||
type inflight struct {
|
|
||||||
doneCh chan struct{}
|
|
||||||
|
|
||||||
keys []jose.JSONWebKey
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func newInflight() *inflight {
|
|
||||||
return &inflight{doneCh: make(chan struct{})}
|
|
||||||
}
|
|
||||||
|
|
||||||
// wait returns a channel that multiple goroutines can receive on. Once it returns
|
|
||||||
// a value, the inflight request is done and result() can be inspected.
|
|
||||||
func (i *inflight) wait() <-chan struct{} {
|
|
||||||
return i.doneCh
|
|
||||||
}
|
|
||||||
|
|
||||||
// done can only be called by a single goroutine. It records the result of the
|
|
||||||
// inflight request and signals other goroutines that the result is safe to
|
|
||||||
// inspect.
|
|
||||||
func (i *inflight) done(keys []jose.JSONWebKey, err error) {
|
|
||||||
i.keys = keys
|
|
||||||
i.err = err
|
|
||||||
close(i.doneCh)
|
|
||||||
}
|
|
||||||
|
|
||||||
// result cannot be called until the wait() channel has returned a value.
|
|
||||||
func (i *inflight) result() ([]jose.JSONWebKey, error) {
|
|
||||||
return i.keys, i.err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *remoteKeySet) VerifySignature(ctx context.Context, jwt string) ([]byte, error) {
|
|
||||||
jws, err := jose.ParseSigned(jwt)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: malformed jwt: %v", err)
|
|
||||||
}
|
|
||||||
return r.verify(ctx, jws)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *remoteKeySet) verify(ctx context.Context, jws *jose.JSONWebSignature) ([]byte, error) {
|
|
||||||
// We don't support JWTs signed with multiple signatures.
|
|
||||||
keyID := ""
|
|
||||||
for _, sig := range jws.Signatures {
|
|
||||||
keyID = sig.Header.KeyID
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
keys, expiry := r.keysFromCache()
|
|
||||||
|
|
||||||
// Don't check expiry yet. This optimizes for when the provider is unavailable.
|
|
||||||
for _, key := range keys {
|
|
||||||
if keyID == "" || key.KeyID == keyID {
|
|
||||||
if payload, err := jws.Verify(&key); err == nil {
|
|
||||||
return payload, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !r.now().Add(keysExpiryDelta).After(expiry) {
|
|
||||||
// Keys haven't expired, don't refresh.
|
|
||||||
return nil, errors.New("failed to verify id token signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
keys, err := r.keysFromRemote(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("fetching keys %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, key := range keys {
|
|
||||||
if keyID == "" || key.KeyID == keyID {
|
|
||||||
if payload, err := jws.Verify(&key); err == nil {
|
|
||||||
return payload, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil, errors.New("failed to verify id token signature")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *remoteKeySet) keysFromCache() (keys []jose.JSONWebKey, expiry time.Time) {
|
|
||||||
r.mu.Lock()
|
|
||||||
defer r.mu.Unlock()
|
|
||||||
return r.cachedKeys, r.expiry
|
|
||||||
}
|
|
||||||
|
|
||||||
// keysFromRemote syncs the key set from the remote set, records the values in the
|
|
||||||
// cache, and returns the key set.
|
|
||||||
func (r *remoteKeySet) keysFromRemote(ctx context.Context) ([]jose.JSONWebKey, error) {
|
|
||||||
// Need to lock to inspect the inflight request field.
|
|
||||||
r.mu.Lock()
|
|
||||||
// If there's not a current inflight request, create one.
|
|
||||||
if r.inflight == nil {
|
|
||||||
r.inflight = newInflight()
|
|
||||||
|
|
||||||
// This goroutine has exclusive ownership over the current inflight
|
|
||||||
// request. It releases the resource by nil'ing the inflight field
|
|
||||||
// once the goroutine is done.
|
|
||||||
go func() {
|
|
||||||
// Sync keys and finish inflight when that's done.
|
|
||||||
keys, expiry, err := r.updateKeys()
|
|
||||||
|
|
||||||
r.inflight.done(keys, err)
|
|
||||||
|
|
||||||
// Lock to update the keys and indicate that there is no longer an
|
|
||||||
// inflight request.
|
|
||||||
r.mu.Lock()
|
|
||||||
defer r.mu.Unlock()
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
r.cachedKeys = keys
|
|
||||||
r.expiry = expiry
|
|
||||||
}
|
|
||||||
|
|
||||||
// Free inflight so a different request can run.
|
|
||||||
r.inflight = nil
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
inflight := r.inflight
|
|
||||||
r.mu.Unlock()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return nil, ctx.Err()
|
|
||||||
case <-inflight.wait():
|
|
||||||
return inflight.result()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *remoteKeySet) updateKeys() ([]jose.JSONWebKey, time.Time, error) {
|
|
||||||
req, err := http.NewRequest("GET", r.jwksURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, time.Time{}, fmt.Errorf("oidc: can't create request: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := doRequest(r.ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, time.Time{}, fmt.Errorf("oidc: get keys failed %v", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, time.Time{}, fmt.Errorf("unable to read response body: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return nil, time.Time{}, fmt.Errorf("oidc: get keys failed: %s %s", resp.Status, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
var keySet jose.JSONWebKeySet
|
|
||||||
err = unmarshalResp(resp, body, &keySet)
|
|
||||||
if err != nil {
|
|
||||||
return nil, time.Time{}, fmt.Errorf("oidc: failed to decode keys: %v %s", err, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the server doesn't provide cache control headers, assume the
|
|
||||||
// keys expire immediately.
|
|
||||||
expiry := r.now()
|
|
||||||
|
|
||||||
_, e, err := cachecontrol.CachableResponse(req, resp, cachecontrol.Options{})
|
|
||||||
if err == nil && e.After(expiry) {
|
|
||||||
expiry = e
|
|
||||||
}
|
|
||||||
return keySet.Keys, expiry, nil
|
|
||||||
}
|
|
409
vendor/github.com/coreos/go-oidc/oidc.go
generated
vendored
409
vendor/github.com/coreos/go-oidc/oidc.go
generated
vendored
|
@ -1,409 +0,0 @@
|
||||||
// Package oidc implements OpenID Connect client logic for the golang.org/x/oauth2 package.
|
|
||||||
package oidc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"hash"
|
|
||||||
"io/ioutil"
|
|
||||||
"mime"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
jose "gopkg.in/square/go-jose.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ScopeOpenID is the mandatory scope for all OpenID Connect OAuth2 requests.
|
|
||||||
ScopeOpenID = "openid"
|
|
||||||
|
|
||||||
// ScopeOfflineAccess is an optional scope defined by OpenID Connect for requesting
|
|
||||||
// OAuth2 refresh tokens.
|
|
||||||
//
|
|
||||||
// Support for this scope differs between OpenID Connect providers. For instance
|
|
||||||
// Google rejects it, favoring appending "access_type=offline" as part of the
|
|
||||||
// authorization request instead.
|
|
||||||
//
|
|
||||||
// See: https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
|
|
||||||
ScopeOfflineAccess = "offline_access"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
errNoAtHash = errors.New("id token did not have an access token hash")
|
|
||||||
errInvalidAtHash = errors.New("access token hash does not match value in ID token")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ClientContext returns a new Context that carries the provided HTTP client.
|
|
||||||
//
|
|
||||||
// This method sets the same context key used by the golang.org/x/oauth2 package,
|
|
||||||
// so the returned context works for that package too.
|
|
||||||
//
|
|
||||||
// myClient := &http.Client{}
|
|
||||||
// ctx := oidc.ClientContext(parentContext, myClient)
|
|
||||||
//
|
|
||||||
// // This will use the custom client
|
|
||||||
// provider, err := oidc.NewProvider(ctx, "https://accounts.example.com")
|
|
||||||
//
|
|
||||||
func ClientContext(ctx context.Context, client *http.Client) context.Context {
|
|
||||||
return context.WithValue(ctx, oauth2.HTTPClient, client)
|
|
||||||
}
|
|
||||||
|
|
||||||
func doRequest(ctx context.Context, req *http.Request) (*http.Response, error) {
|
|
||||||
client := http.DefaultClient
|
|
||||||
if c, ok := ctx.Value(oauth2.HTTPClient).(*http.Client); ok {
|
|
||||||
client = c
|
|
||||||
}
|
|
||||||
return client.Do(req.WithContext(ctx))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provider represents an OpenID Connect server's configuration.
|
|
||||||
type Provider struct {
|
|
||||||
issuer string
|
|
||||||
authURL string
|
|
||||||
tokenURL string
|
|
||||||
userInfoURL string
|
|
||||||
algorithms []string
|
|
||||||
|
|
||||||
// Raw claims returned by the server.
|
|
||||||
rawClaims []byte
|
|
||||||
|
|
||||||
remoteKeySet KeySet
|
|
||||||
}
|
|
||||||
|
|
||||||
type cachedKeys struct {
|
|
||||||
keys []jose.JSONWebKey
|
|
||||||
expiry time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type providerJSON struct {
|
|
||||||
Issuer string `json:"issuer"`
|
|
||||||
AuthURL string `json:"authorization_endpoint"`
|
|
||||||
TokenURL string `json:"token_endpoint"`
|
|
||||||
JWKSURL string `json:"jwks_uri"`
|
|
||||||
UserInfoURL string `json:"userinfo_endpoint"`
|
|
||||||
Algorithms []string `json:"id_token_signing_alg_values_supported"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// supportedAlgorithms is a list of algorithms explicitly supported by this
|
|
||||||
// package. If a provider supports other algorithms, such as HS256 or none,
|
|
||||||
// those values won't be passed to the IDTokenVerifier.
|
|
||||||
var supportedAlgorithms = map[string]bool{
|
|
||||||
RS256: true,
|
|
||||||
RS384: true,
|
|
||||||
RS512: true,
|
|
||||||
ES256: true,
|
|
||||||
ES384: true,
|
|
||||||
ES512: true,
|
|
||||||
PS256: true,
|
|
||||||
PS384: true,
|
|
||||||
PS512: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewProvider uses the OpenID Connect discovery mechanism to construct a Provider.
|
|
||||||
//
|
|
||||||
// The issuer is the URL identifier for the service. For example: "https://accounts.google.com"
|
|
||||||
// or "https://login.salesforce.com".
|
|
||||||
func NewProvider(ctx context.Context, issuer string) (*Provider, error) {
|
|
||||||
wellKnown := strings.TrimSuffix(issuer, "/") + "/.well-known/openid-configuration"
|
|
||||||
req, err := http.NewRequest("GET", wellKnown, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
resp, err := doRequest(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to read response body: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return nil, fmt.Errorf("%s: %s", resp.Status, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
var p providerJSON
|
|
||||||
err = unmarshalResp(resp, body, &p)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: failed to decode provider discovery object: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.Issuer != issuer {
|
|
||||||
return nil, fmt.Errorf("oidc: issuer did not match the issuer returned by provider, expected %q got %q", issuer, p.Issuer)
|
|
||||||
}
|
|
||||||
var algs []string
|
|
||||||
for _, a := range p.Algorithms {
|
|
||||||
if supportedAlgorithms[a] {
|
|
||||||
algs = append(algs, a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &Provider{
|
|
||||||
issuer: p.Issuer,
|
|
||||||
authURL: p.AuthURL,
|
|
||||||
tokenURL: p.TokenURL,
|
|
||||||
userInfoURL: p.UserInfoURL,
|
|
||||||
algorithms: algs,
|
|
||||||
rawClaims: body,
|
|
||||||
remoteKeySet: NewRemoteKeySet(ctx, p.JWKSURL),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Claims unmarshals raw fields returned by the server during discovery.
|
|
||||||
//
|
|
||||||
// var claims struct {
|
|
||||||
// ScopesSupported []string `json:"scopes_supported"`
|
|
||||||
// ClaimsSupported []string `json:"claims_supported"`
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if err := provider.Claims(&claims); err != nil {
|
|
||||||
// // handle unmarshaling error
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// For a list of fields defined by the OpenID Connect spec see:
|
|
||||||
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
|
||||||
func (p *Provider) Claims(v interface{}) error {
|
|
||||||
if p.rawClaims == nil {
|
|
||||||
return errors.New("oidc: claims not set")
|
|
||||||
}
|
|
||||||
return json.Unmarshal(p.rawClaims, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Endpoint returns the OAuth2 auth and token endpoints for the given provider.
|
|
||||||
func (p *Provider) Endpoint() oauth2.Endpoint {
|
|
||||||
return oauth2.Endpoint{AuthURL: p.authURL, TokenURL: p.tokenURL}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserInfo represents the OpenID Connect userinfo claims.
|
|
||||||
type UserInfo struct {
|
|
||||||
Subject string `json:"sub"`
|
|
||||||
Profile string `json:"profile"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
EmailVerified bool `json:"email_verified"`
|
|
||||||
|
|
||||||
claims []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// Claims unmarshals the raw JSON object claims into the provided object.
|
|
||||||
func (u *UserInfo) Claims(v interface{}) error {
|
|
||||||
if u.claims == nil {
|
|
||||||
return errors.New("oidc: claims not set")
|
|
||||||
}
|
|
||||||
return json.Unmarshal(u.claims, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UserInfo uses the token source to query the provider's user info endpoint.
|
|
||||||
func (p *Provider) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource) (*UserInfo, error) {
|
|
||||||
if p.userInfoURL == "" {
|
|
||||||
return nil, errors.New("oidc: user info endpoint is not supported by this provider")
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", p.userInfoURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: create GET request: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := tokenSource.Token()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: get access token: %v", err)
|
|
||||||
}
|
|
||||||
token.SetAuthHeader(req)
|
|
||||||
|
|
||||||
resp, err := doRequest(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return nil, fmt.Errorf("%s: %s", resp.Status, body)
|
|
||||||
}
|
|
||||||
|
|
||||||
var userInfo UserInfo
|
|
||||||
if err := json.Unmarshal(body, &userInfo); err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: failed to decode userinfo: %v", err)
|
|
||||||
}
|
|
||||||
userInfo.claims = body
|
|
||||||
return &userInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IDToken is an OpenID Connect extension that provides a predictable representation
|
|
||||||
// of an authorization event.
|
|
||||||
//
|
|
||||||
// The ID Token only holds fields OpenID Connect requires. To access additional
|
|
||||||
// claims returned by the server, use the Claims method.
|
|
||||||
type IDToken struct {
|
|
||||||
// The URL of the server which issued this token. OpenID Connect
|
|
||||||
// requires this value always be identical to the URL used for
|
|
||||||
// initial discovery.
|
|
||||||
//
|
|
||||||
// Note: Because of a known issue with Google Accounts' implementation
|
|
||||||
// this value may differ when using Google.
|
|
||||||
//
|
|
||||||
// See: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo
|
|
||||||
Issuer string
|
|
||||||
|
|
||||||
// The client ID, or set of client IDs, that this token is issued for. For
|
|
||||||
// common uses, this is the client that initialized the auth flow.
|
|
||||||
//
|
|
||||||
// This package ensures the audience contains an expected value.
|
|
||||||
Audience []string
|
|
||||||
|
|
||||||
// A unique string which identifies the end user.
|
|
||||||
Subject string
|
|
||||||
|
|
||||||
// Expiry of the token. Ths package will not process tokens that have
|
|
||||||
// expired unless that validation is explicitly turned off.
|
|
||||||
Expiry time.Time
|
|
||||||
// When the token was issued by the provider.
|
|
||||||
IssuedAt time.Time
|
|
||||||
|
|
||||||
// Initial nonce provided during the authentication redirect.
|
|
||||||
//
|
|
||||||
// This package does NOT provided verification on the value of this field
|
|
||||||
// and it's the user's responsibility to ensure it contains a valid value.
|
|
||||||
Nonce string
|
|
||||||
|
|
||||||
// at_hash claim, if set in the ID token. Callers can verify an access token
|
|
||||||
// that corresponds to the ID token using the VerifyAccessToken method.
|
|
||||||
AccessTokenHash string
|
|
||||||
|
|
||||||
// signature algorithm used for ID token, needed to compute a verification hash of an
|
|
||||||
// access token
|
|
||||||
sigAlgorithm string
|
|
||||||
|
|
||||||
// Raw payload of the id_token.
|
|
||||||
claims []byte
|
|
||||||
|
|
||||||
// Map of distributed claim names to claim sources
|
|
||||||
distributedClaims map[string]claimSource
|
|
||||||
}
|
|
||||||
|
|
||||||
// Claims unmarshals the raw JSON payload of the ID Token into a provided struct.
|
|
||||||
//
|
|
||||||
// idToken, err := idTokenVerifier.Verify(rawIDToken)
|
|
||||||
// if err != nil {
|
|
||||||
// // handle error
|
|
||||||
// }
|
|
||||||
// var claims struct {
|
|
||||||
// Email string `json:"email"`
|
|
||||||
// EmailVerified bool `json:"email_verified"`
|
|
||||||
// }
|
|
||||||
// if err := idToken.Claims(&claims); err != nil {
|
|
||||||
// // handle error
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
func (i *IDToken) Claims(v interface{}) error {
|
|
||||||
if i.claims == nil {
|
|
||||||
return errors.New("oidc: claims not set")
|
|
||||||
}
|
|
||||||
return json.Unmarshal(i.claims, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// VerifyAccessToken verifies that the hash of the access token that corresponds to the iD token
|
|
||||||
// matches the hash in the id token. It returns an error if the hashes don't match.
|
|
||||||
// It is the caller's responsibility to ensure that the optional access token hash is present for the ID token
|
|
||||||
// before calling this method. See https://openid.net/specs/openid-connect-core-1_0.html#CodeIDToken
|
|
||||||
func (i *IDToken) VerifyAccessToken(accessToken string) error {
|
|
||||||
if i.AccessTokenHash == "" {
|
|
||||||
return errNoAtHash
|
|
||||||
}
|
|
||||||
var h hash.Hash
|
|
||||||
switch i.sigAlgorithm {
|
|
||||||
case RS256, ES256, PS256:
|
|
||||||
h = sha256.New()
|
|
||||||
case RS384, ES384, PS384:
|
|
||||||
h = sha512.New384()
|
|
||||||
case RS512, ES512, PS512:
|
|
||||||
h = sha512.New()
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("oidc: unsupported signing algorithm %q", i.sigAlgorithm)
|
|
||||||
}
|
|
||||||
h.Write([]byte(accessToken)) // hash documents that Write will never return an error
|
|
||||||
sum := h.Sum(nil)[:h.Size()/2]
|
|
||||||
actual := base64.RawURLEncoding.EncodeToString(sum)
|
|
||||||
if actual != i.AccessTokenHash {
|
|
||||||
return errInvalidAtHash
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type idToken struct {
|
|
||||||
Issuer string `json:"iss"`
|
|
||||||
Subject string `json:"sub"`
|
|
||||||
Audience audience `json:"aud"`
|
|
||||||
Expiry jsonTime `json:"exp"`
|
|
||||||
IssuedAt jsonTime `json:"iat"`
|
|
||||||
NotBefore *jsonTime `json:"nbf"`
|
|
||||||
Nonce string `json:"nonce"`
|
|
||||||
AtHash string `json:"at_hash"`
|
|
||||||
ClaimNames map[string]string `json:"_claim_names"`
|
|
||||||
ClaimSources map[string]claimSource `json:"_claim_sources"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type claimSource struct {
|
|
||||||
Endpoint string `json:"endpoint"`
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type audience []string
|
|
||||||
|
|
||||||
func (a *audience) UnmarshalJSON(b []byte) error {
|
|
||||||
var s string
|
|
||||||
if json.Unmarshal(b, &s) == nil {
|
|
||||||
*a = audience{s}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var auds []string
|
|
||||||
if err := json.Unmarshal(b, &auds); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*a = audience(auds)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type jsonTime time.Time
|
|
||||||
|
|
||||||
func (j *jsonTime) UnmarshalJSON(b []byte) error {
|
|
||||||
var n json.Number
|
|
||||||
if err := json.Unmarshal(b, &n); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var unix int64
|
|
||||||
|
|
||||||
if t, err := n.Int64(); err == nil {
|
|
||||||
unix = t
|
|
||||||
} else {
|
|
||||||
f, err := n.Float64()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
unix = int64(f)
|
|
||||||
}
|
|
||||||
*j = jsonTime(time.Unix(unix, 0))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func unmarshalResp(r *http.Response, body []byte, v interface{}) error {
|
|
||||||
err := json.Unmarshal(body, &v)
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
ct := r.Header.Get("Content-Type")
|
|
||||||
mediaType, _, parseErr := mime.ParseMediaType(ct)
|
|
||||||
if parseErr == nil && mediaType == "application/json" {
|
|
||||||
return fmt.Errorf("got Content-Type = application/json, but could not unmarshal as JSON: %v", err)
|
|
||||||
}
|
|
||||||
return fmt.Errorf("expected Content-Type = application/json, got %q: %v", ct, err)
|
|
||||||
}
|
|
16
vendor/github.com/coreos/go-oidc/test
generated
vendored
16
vendor/github.com/coreos/go-oidc/test
generated
vendored
|
@ -1,16 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Filter out any files with a !golint build tag.
|
|
||||||
LINTABLE=$( go list -tags=golint -f '
|
|
||||||
{{- range $i, $file := .GoFiles -}}
|
|
||||||
{{ $file }} {{ end }}
|
|
||||||
{{ range $i, $file := .TestGoFiles -}}
|
|
||||||
{{ $file }} {{ end }}' github.com/coreos/go-oidc )
|
|
||||||
|
|
||||||
go test -v -i -race github.com/coreos/go-oidc/...
|
|
||||||
go test -v -race github.com/coreos/go-oidc/...
|
|
||||||
golint -set_exit_status $LINTABLE
|
|
||||||
go vet github.com/coreos/go-oidc/...
|
|
||||||
go build -v ./example/...
|
|
336
vendor/github.com/coreos/go-oidc/verify.go
generated
vendored
336
vendor/github.com/coreos/go-oidc/verify.go
generated
vendored
|
@ -1,336 +0,0 @@
|
||||||
package oidc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
jose "gopkg.in/square/go-jose.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
issuerGoogleAccounts = "https://accounts.google.com"
|
|
||||||
issuerGoogleAccountsNoScheme = "accounts.google.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
// KeySet is a set of publc JSON Web Keys that can be used to validate the signature
|
|
||||||
// of JSON web tokens. This is expected to be backed by a remote key set through
|
|
||||||
// provider metadata discovery or an in-memory set of keys delivered out-of-band.
|
|
||||||
type KeySet interface {
|
|
||||||
// VerifySignature parses the JSON web token, verifies the signature, and returns
|
|
||||||
// the raw payload. Header and claim fields are validated by other parts of the
|
|
||||||
// package. For example, the KeySet does not need to check values such as signature
|
|
||||||
// algorithm, issuer, and audience since the IDTokenVerifier validates these values
|
|
||||||
// independently.
|
|
||||||
//
|
|
||||||
// If VerifySignature makes HTTP requests to verify the token, it's expected to
|
|
||||||
// use any HTTP client associated with the context through ClientContext.
|
|
||||||
VerifySignature(ctx context.Context, jwt string) (payload []byte, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IDTokenVerifier provides verification for ID Tokens.
|
|
||||||
type IDTokenVerifier struct {
|
|
||||||
keySet KeySet
|
|
||||||
config *Config
|
|
||||||
issuer string
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVerifier returns a verifier manually constructed from a key set and issuer URL.
|
|
||||||
//
|
|
||||||
// It's easier to use provider discovery to construct an IDTokenVerifier than creating
|
|
||||||
// one directly. This method is intended to be used with provider that don't support
|
|
||||||
// metadata discovery, or avoiding round trips when the key set URL is already known.
|
|
||||||
//
|
|
||||||
// This constructor can be used to create a verifier directly using the issuer URL and
|
|
||||||
// JSON Web Key Set URL without using discovery:
|
|
||||||
//
|
|
||||||
// keySet := oidc.NewRemoteKeySet(ctx, "https://www.googleapis.com/oauth2/v3/certs")
|
|
||||||
// verifier := oidc.NewVerifier("https://accounts.google.com", keySet, config)
|
|
||||||
//
|
|
||||||
// Since KeySet is an interface, this constructor can also be used to supply custom
|
|
||||||
// public key sources. For example, if a user wanted to supply public keys out-of-band
|
|
||||||
// and hold them statically in-memory:
|
|
||||||
//
|
|
||||||
// // Custom KeySet implementation.
|
|
||||||
// keySet := newStatisKeySet(publicKeys...)
|
|
||||||
//
|
|
||||||
// // Verifier uses the custom KeySet implementation.
|
|
||||||
// verifier := oidc.NewVerifier("https://auth.example.com", keySet, config)
|
|
||||||
//
|
|
||||||
func NewVerifier(issuerURL string, keySet KeySet, config *Config) *IDTokenVerifier {
|
|
||||||
return &IDTokenVerifier{keySet: keySet, config: config, issuer: issuerURL}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config is the configuration for an IDTokenVerifier.
|
|
||||||
type Config struct {
|
|
||||||
// Expected audience of the token. For a majority of the cases this is expected to be
|
|
||||||
// the ID of the client that initialized the login flow. It may occasionally differ if
|
|
||||||
// the provider supports the authorizing party (azp) claim.
|
|
||||||
//
|
|
||||||
// If not provided, users must explicitly set SkipClientIDCheck.
|
|
||||||
ClientID string
|
|
||||||
// If specified, only this set of algorithms may be used to sign the JWT.
|
|
||||||
//
|
|
||||||
// If the IDTokenVerifier is created from a provider with (*Provider).Verifier, this
|
|
||||||
// defaults to the set of algorithms the provider supports. Otherwise this values
|
|
||||||
// defaults to RS256.
|
|
||||||
SupportedSigningAlgs []string
|
|
||||||
|
|
||||||
// If true, no ClientID check performed. Must be true if ClientID field is empty.
|
|
||||||
SkipClientIDCheck bool
|
|
||||||
// If true, token expiry is not checked.
|
|
||||||
SkipExpiryCheck bool
|
|
||||||
|
|
||||||
// SkipIssuerCheck is intended for specialized cases where the the caller wishes to
|
|
||||||
// defer issuer validation. When enabled, callers MUST independently verify the Token's
|
|
||||||
// Issuer is a known good value.
|
|
||||||
//
|
|
||||||
// Mismatched issuers often indicate client mis-configuration. If mismatches are
|
|
||||||
// unexpected, evaluate if the provided issuer URL is incorrect instead of enabling
|
|
||||||
// this option.
|
|
||||||
SkipIssuerCheck bool
|
|
||||||
|
|
||||||
// Time function to check Token expiry. Defaults to time.Now
|
|
||||||
Now func() time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verifier returns an IDTokenVerifier that uses the provider's key set to verify JWTs.
|
|
||||||
//
|
|
||||||
// The returned IDTokenVerifier is tied to the Provider's context and its behavior is
|
|
||||||
// undefined once the Provider's context is canceled.
|
|
||||||
func (p *Provider) Verifier(config *Config) *IDTokenVerifier {
|
|
||||||
if len(config.SupportedSigningAlgs) == 0 && len(p.algorithms) > 0 {
|
|
||||||
// Make a copy so we don't modify the config values.
|
|
||||||
cp := &Config{}
|
|
||||||
*cp = *config
|
|
||||||
cp.SupportedSigningAlgs = p.algorithms
|
|
||||||
config = cp
|
|
||||||
}
|
|
||||||
return NewVerifier(p.issuer, p.remoteKeySet, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseJWT(p string) ([]byte, error) {
|
|
||||||
parts := strings.Split(p, ".")
|
|
||||||
if len(parts) < 2 {
|
|
||||||
return nil, fmt.Errorf("oidc: malformed jwt, expected 3 parts got %d", len(parts))
|
|
||||||
}
|
|
||||||
payload, err := base64.RawURLEncoding.DecodeString(parts[1])
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: malformed jwt payload: %v", err)
|
|
||||||
}
|
|
||||||
return payload, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func contains(sli []string, ele string) bool {
|
|
||||||
for _, s := range sli {
|
|
||||||
if s == ele {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the Claims from the distributed JWT token
|
|
||||||
func resolveDistributedClaim(ctx context.Context, verifier *IDTokenVerifier, src claimSource) ([]byte, error) {
|
|
||||||
req, err := http.NewRequest("GET", src.Endpoint, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("malformed request: %v", err)
|
|
||||||
}
|
|
||||||
if src.AccessToken != "" {
|
|
||||||
req.Header.Set("Authorization", "Bearer "+src.AccessToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := doRequest(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: Request to endpoint failed: %v", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to read response body: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
return nil, fmt.Errorf("oidc: request failed: %v", resp.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := verifier.Verify(ctx, string(body))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("malformed response body: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return token.claims, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseClaim(raw []byte, name string, v interface{}) error {
|
|
||||||
var parsed map[string]json.RawMessage
|
|
||||||
if err := json.Unmarshal(raw, &parsed); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
val, ok := parsed[name]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("claim doesn't exist: %s", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return json.Unmarshal([]byte(val), v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify parses a raw ID Token, verifies it's been signed by the provider, preforms
|
|
||||||
// any additional checks depending on the Config, and returns the payload.
|
|
||||||
//
|
|
||||||
// Verify does NOT do nonce validation, which is the callers responsibility.
|
|
||||||
//
|
|
||||||
// See: https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
|
|
||||||
//
|
|
||||||
// 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 error
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// token, err := verifier.Verify(ctx, rawIDToken)
|
|
||||||
//
|
|
||||||
func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*IDToken, error) {
|
|
||||||
jws, err := jose.ParseSigned(rawIDToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: malformed jwt: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Throw out tokens with invalid claims before trying to verify the token. This lets
|
|
||||||
// us do cheap checks before possibly re-syncing keys.
|
|
||||||
payload, err := parseJWT(rawIDToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: malformed jwt: %v", err)
|
|
||||||
}
|
|
||||||
var token idToken
|
|
||||||
if err := json.Unmarshal(payload, &token); err != nil {
|
|
||||||
return nil, fmt.Errorf("oidc: failed to unmarshal claims: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
distributedClaims := make(map[string]claimSource)
|
|
||||||
|
|
||||||
//step through the token to map claim names to claim sources"
|
|
||||||
for cn, src := range token.ClaimNames {
|
|
||||||
if src == "" {
|
|
||||||
return nil, fmt.Errorf("oidc: failed to obtain source from claim name")
|
|
||||||
}
|
|
||||||
s, ok := token.ClaimSources[src]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("oidc: source does not exist")
|
|
||||||
}
|
|
||||||
distributedClaims[cn] = s
|
|
||||||
}
|
|
||||||
|
|
||||||
t := &IDToken{
|
|
||||||
Issuer: token.Issuer,
|
|
||||||
Subject: token.Subject,
|
|
||||||
Audience: []string(token.Audience),
|
|
||||||
Expiry: time.Time(token.Expiry),
|
|
||||||
IssuedAt: time.Time(token.IssuedAt),
|
|
||||||
Nonce: token.Nonce,
|
|
||||||
AccessTokenHash: token.AtHash,
|
|
||||||
claims: payload,
|
|
||||||
distributedClaims: distributedClaims,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check issuer.
|
|
||||||
if !v.config.SkipIssuerCheck && t.Issuer != v.issuer {
|
|
||||||
// Google sometimes returns "accounts.google.com" as the issuer claim instead of
|
|
||||||
// the required "https://accounts.google.com". Detect this case and allow it only
|
|
||||||
// for Google.
|
|
||||||
//
|
|
||||||
// We will not add hooks to let other providers go off spec like this.
|
|
||||||
if !(v.issuer == issuerGoogleAccounts && t.Issuer == issuerGoogleAccountsNoScheme) {
|
|
||||||
return nil, fmt.Errorf("oidc: id token issued by a different provider, expected %q got %q", v.issuer, t.Issuer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a client ID has been provided, make sure it's part of the audience. SkipClientIDCheck must be true if ClientID is empty.
|
|
||||||
//
|
|
||||||
// This check DOES NOT ensure that the ClientID is the party to which the ID Token was issued (i.e. Authorized party).
|
|
||||||
if !v.config.SkipClientIDCheck {
|
|
||||||
if v.config.ClientID != "" {
|
|
||||||
if !contains(t.Audience, v.config.ClientID) {
|
|
||||||
return nil, fmt.Errorf("oidc: expected audience %q got %q", v.config.ClientID, t.Audience)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("oidc: invalid configuration, clientID must be provided or SkipClientIDCheck must be set")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a SkipExpiryCheck is false, make sure token is not expired.
|
|
||||||
if !v.config.SkipExpiryCheck {
|
|
||||||
now := time.Now
|
|
||||||
if v.config.Now != nil {
|
|
||||||
now = v.config.Now
|
|
||||||
}
|
|
||||||
nowTime := now()
|
|
||||||
|
|
||||||
if t.Expiry.Before(nowTime) {
|
|
||||||
return nil, fmt.Errorf("oidc: token is expired (Token Expiry: %v)", t.Expiry)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If nbf claim is provided in token, ensure that it is indeed in the past.
|
|
||||||
if token.NotBefore != nil {
|
|
||||||
nbfTime := time.Time(*token.NotBefore)
|
|
||||||
leeway := 1 * time.Minute
|
|
||||||
|
|
||||||
if nowTime.Add(leeway).Before(nbfTime) {
|
|
||||||
return nil, fmt.Errorf("oidc: current time %v before the nbf (not before) time: %v", nowTime, nbfTime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch len(jws.Signatures) {
|
|
||||||
case 0:
|
|
||||||
return nil, fmt.Errorf("oidc: id token not signed")
|
|
||||||
case 1:
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("oidc: multiple signatures on id token not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
sig := jws.Signatures[0]
|
|
||||||
supportedSigAlgs := v.config.SupportedSigningAlgs
|
|
||||||
if len(supportedSigAlgs) == 0 {
|
|
||||||
supportedSigAlgs = []string{RS256}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !contains(supportedSigAlgs, sig.Header.Algorithm) {
|
|
||||||
return nil, fmt.Errorf("oidc: id token signed with unsupported algorithm, expected %q got %q", supportedSigAlgs, sig.Header.Algorithm)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.sigAlgorithm = sig.Header.Algorithm
|
|
||||||
|
|
||||||
gotPayload, err := v.keySet.VerifySignature(ctx, rawIDToken)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to verify signature: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the payload returned by the square actually matches the payload parsed earlier.
|
|
||||||
if !bytes.Equal(gotPayload, payload) {
|
|
||||||
return nil, errors.New("oidc: internal error, payload parsed did not match previous payload")
|
|
||||||
}
|
|
||||||
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nonce returns an auth code option which requires the ID Token created by the
|
|
||||||
// OpenID Connect provider to contain the specified nonce.
|
|
||||||
func Nonce(nonce string) oauth2.AuthCodeOption {
|
|
||||||
return oauth2.SetAuthURLParam("nonce", nonce)
|
|
||||||
}
|
|
191
vendor/github.com/coreos/go-systemd/LICENSE
generated
vendored
191
vendor/github.com/coreos/go-systemd/LICENSE
generated
vendored
|
@ -1,191 +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:
|
|
||||||
|
|
||||||
You must give any other recipients of the Work or Derivative Works a copy of
|
|
||||||
this License; and
|
|
||||||
You must cause any modified files to carry prominent notices stating that You
|
|
||||||
changed the files; and
|
|
||||||
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
|
|
||||||
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.
|
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue