mirror of
https://github.com/mudler/luet.git
synced 2025-08-30 21:52:10 +00:00
Update vendor
This commit is contained in:
parent
5b4e930fc3
commit
a6b6909dc4
5
go.sum
5
go.sum
@ -832,6 +832,7 @@ github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f h1:WyCn68lTiy
|
|||||||
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f/go.mod h1:/iRjX3DdSK956SzsUdV55J+wIsQ+2IBWmBrB4RvZfk4=
|
github.com/philopon/go-toposort v0.0.0-20170620085441-9be86dbd762f/go.mod h1:/iRjX3DdSK956SzsUdV55J+wIsQ+2IBWmBrB4RvZfk4=
|
||||||
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
|
||||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@ -876,6 +877,8 @@ github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa
|
|||||||
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
|
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
|
||||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||||
|
github.com/rancher-sandbox/gofilecache v0.0.0-20210330135715-becdeff5df15 h1:w8tg3snxZF0UHTVmYq7DDPkC3lehwFC/4EwVTAxFeWg=
|
||||||
|
github.com/rancher-sandbox/gofilecache v0.0.0-20210330135715-becdeff5df15/go.mod h1:+Uhkjp4zCSryD4cpHhEu8uz4fIQ533t6Lv6M6pSVIKQ=
|
||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
@ -885,6 +888,8 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
|
|||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/rootless-containers/proto v0.1.0 h1:gS1JOMEtk1YDYHCzBAf/url+olMJbac7MTrgSeP6zh4=
|
github.com/rootless-containers/proto v0.1.0 h1:gS1JOMEtk1YDYHCzBAf/url+olMJbac7MTrgSeP6zh4=
|
||||||
github.com/rootless-containers/proto v0.1.0/go.mod h1:vgkUFZbQd0gcE/K/ZwtE4MYjZPu0UNHLXIQxhyqAFh8=
|
github.com/rootless-containers/proto v0.1.0/go.mod h1:vgkUFZbQd0gcE/K/ZwtE4MYjZPu0UNHLXIQxhyqAFh8=
|
||||||
github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg=
|
github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg=
|
||||||
|
3
vendor/github.com/rancher-sandbox/gofilecache/.gitignore
generated
vendored
Normal file
3
vendor/github.com/rancher-sandbox/gofilecache/.gitignore
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
temp/**
|
||||||
|
main.*
|
||||||
|
gofilecache
|
27
vendor/github.com/rancher-sandbox/gofilecache/LICENSE
generated
vendored
Normal file
27
vendor/github.com/rancher-sandbox/gofilecache/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2020 The Go Authors, SUSE LLC. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* 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.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"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 THE COPYRIGHT
|
||||||
|
OWNER 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.
|
38
vendor/github.com/rancher-sandbox/gofilecache/README.md
generated
vendored
Normal file
38
vendor/github.com/rancher-sandbox/gofilecache/README.md
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# GOFILECACHE
|
||||||
|
|
||||||
|
This is a simple filecache derived from golangs buildcache.
|
||||||
|
|
||||||
|
## How to use
|
||||||
|
|
||||||
|
```golang
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha512"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"github.com/rancher-sandbox/gofilecache"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Initialise cache
|
||||||
|
cache := gofilecache.InitCache("temp/")
|
||||||
|
// pick an example textfile to add to the cache
|
||||||
|
testFile := "/usr/lib/os-release"
|
||||||
|
file, _ := os.Open(testFile)
|
||||||
|
defer file.Close()
|
||||||
|
// generate a hash under which the entry can be found in the cache
|
||||||
|
// for simplicity we use the filename here
|
||||||
|
actionID := sha512.Sum512([]byte("os-release"))
|
||||||
|
|
||||||
|
// store the files contents to the cache
|
||||||
|
cache.Put(actionID, file)
|
||||||
|
|
||||||
|
// retrieve the filename from the cache
|
||||||
|
fileName, _, _ := cache.GetFile(actionID)
|
||||||
|
|
||||||
|
// get the files contents
|
||||||
|
_, _ = ioutil.ReadFile(fileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
536
vendor/github.com/rancher-sandbox/gofilecache/cache.go
generated
vendored
Normal file
536
vendor/github.com/rancher-sandbox/gofilecache/cache.go
generated
vendored
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
// Copyright 2017 The Go Authors, SUSE LLC. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package cache implements a build artifact cache.
|
||||||
|
package gofilecache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha512"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rogpeppe/go-internal/lockedfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An ActionID is a cache action key, the hash of a complete description of a
|
||||||
|
// repeatable computation (command line, environment variables,
|
||||||
|
// input file contents, executable contents).
|
||||||
|
type ActionID [HashSize]byte
|
||||||
|
|
||||||
|
// An OutputID is a cache output key, the hash of an output of a computation.
|
||||||
|
type OutputID [HashSize]byte
|
||||||
|
|
||||||
|
// A Cache is a package cache, backed by a file system directory tree.
|
||||||
|
type Cache struct {
|
||||||
|
dir string
|
||||||
|
now func() time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open opens and returns the cache in the given directory.
|
||||||
|
//
|
||||||
|
// It is safe for multiple processes on a single machine to use the
|
||||||
|
// same cache directory in a local file system simultaneously.
|
||||||
|
// They will coordinate using operating system file locks and may
|
||||||
|
// duplicate effort but will not corrupt the cache.
|
||||||
|
//
|
||||||
|
// However, it is NOT safe for multiple processes on different machines
|
||||||
|
// to share a cache directory (for example, if the directory were stored
|
||||||
|
// in a network file system). File locking is notoriously unreliable in
|
||||||
|
// network file systems and may not suffice to protect the cache.
|
||||||
|
//
|
||||||
|
func Open(dir string) (*Cache, error) {
|
||||||
|
info, err := os.Stat(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !info.IsDir() {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
name := filepath.Join(dir, fmt.Sprintf("%02x", i))
|
||||||
|
if err := os.MkdirAll(name, 0777); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c := &Cache{
|
||||||
|
dir: dir,
|
||||||
|
now: time.Now,
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// fileName returns the name of the file corresponding to the given id.
|
||||||
|
func (c *Cache) fileName(id [HashSize]byte, key string) string {
|
||||||
|
return filepath.Join(c.dir, fmt.Sprintf("%02x", id[0]), fmt.Sprintf("%x", id)+"-"+key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An entryNotFoundError indicates that a cache entry was not found, with an
|
||||||
|
// optional underlying reason.
|
||||||
|
type entryNotFoundError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *entryNotFoundError) Error() string {
|
||||||
|
if e.Err == nil {
|
||||||
|
return "cache entry not found"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("cache entry not found: %v", e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *entryNotFoundError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// action entry file is "v1 <hex id> <hex out> <decimal size space-padded to 20 bytes> <unixnano space-padded to 20 bytes>\n"
|
||||||
|
hexSize = HashSize * 2
|
||||||
|
entrySize = 2 + 1 + hexSize + 1 + hexSize + 1 + 20 + 1 + 20 + 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// verify controls whether to run the cache in verify mode.
|
||||||
|
// In verify mode, the cache always returns errMissing from Get
|
||||||
|
// but then double-checks in Put that the data being written
|
||||||
|
// exactly matches any existing entry. This provides an easy
|
||||||
|
// way to detect program behavior that would have been different
|
||||||
|
// had the cache entry been returned from Get.
|
||||||
|
//
|
||||||
|
// verify is enabled by setting the environment variable
|
||||||
|
// GODEBUG=gocacheverify=1.
|
||||||
|
var verify = false
|
||||||
|
|
||||||
|
var errVerifyMode = errors.New("gocacheverify=1")
|
||||||
|
|
||||||
|
// DebugTest is set when GODEBUG=gocachetest=1 is in the environment.
|
||||||
|
var DebugTest = false
|
||||||
|
|
||||||
|
func init() { initEnv() }
|
||||||
|
|
||||||
|
func initEnv() {
|
||||||
|
verify = false
|
||||||
|
debugHash = false
|
||||||
|
debug := strings.Split(os.Getenv("GODEBUG"), ",")
|
||||||
|
for _, f := range debug {
|
||||||
|
if f == "gocacheverify=1" {
|
||||||
|
verify = true
|
||||||
|
}
|
||||||
|
if f == "gocachehash=1" {
|
||||||
|
debugHash = true
|
||||||
|
}
|
||||||
|
if f == "gocachetest=1" {
|
||||||
|
DebugTest = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get looks up the action ID in the cache,
|
||||||
|
// returning the corresponding output ID and file size, if any.
|
||||||
|
// Note that finding an output ID does not guarantee that the
|
||||||
|
// saved file for that output ID is still available.
|
||||||
|
func (c *Cache) Get(id ActionID) (Entry, error) {
|
||||||
|
if verify {
|
||||||
|
return Entry{}, &entryNotFoundError{Err: errVerifyMode}
|
||||||
|
}
|
||||||
|
return c.get(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Entry struct {
|
||||||
|
OutputID OutputID
|
||||||
|
Size int64
|
||||||
|
Time time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// get is Get but does not respect verify mode, so that Put can use it.
|
||||||
|
func (c *Cache) get(id ActionID) (Entry, error) {
|
||||||
|
missing := func(reason error) (Entry, error) {
|
||||||
|
return Entry{}, &entryNotFoundError{Err: reason}
|
||||||
|
}
|
||||||
|
f, err := os.Open(c.fileName(id, "a"))
|
||||||
|
if err != nil {
|
||||||
|
return missing(err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
entry := make([]byte, entrySize+1) // +1 to detect whether f is too long
|
||||||
|
if n, err := io.ReadFull(f, entry); n > entrySize {
|
||||||
|
return missing(errors.New("too long"))
|
||||||
|
} else if err != io.ErrUnexpectedEOF {
|
||||||
|
if err == io.EOF {
|
||||||
|
return missing(errors.New("file is empty"))
|
||||||
|
}
|
||||||
|
return missing(err)
|
||||||
|
} else if n < entrySize {
|
||||||
|
return missing(errors.New("entry file incomplete"))
|
||||||
|
}
|
||||||
|
if entry[0] != 'v' || entry[1] != '1' || entry[2] != ' ' || entry[3+hexSize] != ' ' || entry[3+hexSize+1+hexSize] != ' ' || entry[3+hexSize+1+hexSize+1+20] != ' ' || entry[entrySize-1] != '\n' {
|
||||||
|
return missing(errors.New("invalid header"))
|
||||||
|
}
|
||||||
|
eid, entry := entry[3:3+hexSize], entry[3+hexSize:]
|
||||||
|
eout, entry := entry[1:1+hexSize], entry[1+hexSize:]
|
||||||
|
esize, entry := entry[1:1+20], entry[1+20:]
|
||||||
|
etime, entry := entry[1:1+20], entry[1+20:]
|
||||||
|
var buf [HashSize]byte
|
||||||
|
if _, err := hex.Decode(buf[:], eid); err != nil {
|
||||||
|
return missing(fmt.Errorf("decoding ID: %v", err))
|
||||||
|
} else if buf != id {
|
||||||
|
return missing(errors.New("mismatched ID"))
|
||||||
|
}
|
||||||
|
if _, err := hex.Decode(buf[:], eout); err != nil {
|
||||||
|
return missing(fmt.Errorf("decoding output ID: %v", err))
|
||||||
|
}
|
||||||
|
i := 0
|
||||||
|
for i < len(esize) && esize[i] == ' ' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
size, err := strconv.ParseInt(string(esize[i:]), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return missing(fmt.Errorf("parsing size: %v", err))
|
||||||
|
} else if size < 0 {
|
||||||
|
return missing(errors.New("negative size"))
|
||||||
|
}
|
||||||
|
i = 0
|
||||||
|
for i < len(etime) && etime[i] == ' ' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
tm, err := strconv.ParseInt(string(etime[i:]), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return missing(fmt.Errorf("parsing timestamp: %v", err))
|
||||||
|
} else if tm < 0 {
|
||||||
|
return missing(errors.New("negative timestamp"))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.used(c.fileName(id, "a"))
|
||||||
|
|
||||||
|
return Entry{buf, size, time.Unix(0, tm)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFile looks up the action ID in the cache and returns
|
||||||
|
// the name of the corresponding data file.
|
||||||
|
func (c *Cache) GetFile(id ActionID) (file string, entry Entry, err error) {
|
||||||
|
entry, err = c.Get(id)
|
||||||
|
if err != nil {
|
||||||
|
return "", Entry{}, err
|
||||||
|
}
|
||||||
|
file = c.OutputFile(entry.OutputID)
|
||||||
|
info, err := os.Stat(file)
|
||||||
|
if err != nil {
|
||||||
|
return "", Entry{}, &entryNotFoundError{Err: err}
|
||||||
|
}
|
||||||
|
if info.Size() != entry.Size {
|
||||||
|
return "", Entry{}, &entryNotFoundError{Err: errors.New("file incomplete")}
|
||||||
|
}
|
||||||
|
return file, entry, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytes looks up the action ID in the cache and returns
|
||||||
|
// the corresponding output bytes.
|
||||||
|
// GetBytes should only be used for data that can be expected to fit in memory.
|
||||||
|
func (c *Cache) GetBytes(id ActionID) ([]byte, Entry, error) {
|
||||||
|
entry, err := c.Get(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, entry, err
|
||||||
|
}
|
||||||
|
data, _ := ioutil.ReadFile(c.OutputFile(entry.OutputID))
|
||||||
|
if sha512.Sum512(data) != entry.OutputID {
|
||||||
|
return nil, entry, &entryNotFoundError{Err: errors.New("bad checksum")}
|
||||||
|
}
|
||||||
|
return data, entry, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OutputFile returns the name of the cache file storing output with the given OutputID.
|
||||||
|
func (c *Cache) OutputFile(out OutputID) string {
|
||||||
|
file := c.fileName(out, "d")
|
||||||
|
c.used(file)
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time constants for cache expiration.
|
||||||
|
//
|
||||||
|
// We set the mtime on a cache file on each use, but at most one per mtimeInterval (1 hour),
|
||||||
|
// to avoid causing many unnecessary inode updates. The mtimes therefore
|
||||||
|
// roughly reflect "time of last use" but may in fact be older by at most an hour.
|
||||||
|
//
|
||||||
|
// We scan the cache for entries to delete at most once per trimInterval (1 day).
|
||||||
|
//
|
||||||
|
// When we do scan the cache, we delete entries that have not been used for
|
||||||
|
// at least trimLimit (5 days). Statistics gathered from a month of usage by
|
||||||
|
// Go developers found that essentially all reuse of cached entries happened
|
||||||
|
// within 5 days of the previous reuse. See golang.org/issue/22990.
|
||||||
|
const (
|
||||||
|
mtimeInterval = 1 * time.Hour
|
||||||
|
trimInterval = 24 * time.Hour
|
||||||
|
trimLimit = 5 * 24 * time.Hour
|
||||||
|
)
|
||||||
|
|
||||||
|
// used makes a best-effort attempt to update mtime on file,
|
||||||
|
// so that mtime reflects cache access time.
|
||||||
|
//
|
||||||
|
// Because the reflection only needs to be approximate,
|
||||||
|
// and to reduce the amount of disk activity caused by using
|
||||||
|
// cache entries, used only updates the mtime if the current
|
||||||
|
// mtime is more than an hour old. This heuristic eliminates
|
||||||
|
// nearly all of the mtime updates that would otherwise happen,
|
||||||
|
// while still keeping the mtimes useful for cache trimming.
|
||||||
|
func (c *Cache) used(file string) {
|
||||||
|
info, err := os.Stat(file)
|
||||||
|
if err == nil && c.now().Sub(info.ModTime()) < mtimeInterval {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
os.Chtimes(file, c.now(), c.now())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim removes old cache entries that are likely not to be reused.
|
||||||
|
func (c *Cache) Trim() {
|
||||||
|
now := c.now()
|
||||||
|
|
||||||
|
// We maintain in dir/trim.txt the time of the last completed cache trim.
|
||||||
|
// If the cache has been trimmed recently enough, do nothing.
|
||||||
|
// This is the common case.
|
||||||
|
// If the trim file is corrupt, detected if the file can't be parsed, or the
|
||||||
|
// trim time is too far in the future, attempt the trim anyway. It's possible that
|
||||||
|
// the cache was full when the corruption happened. Attempting a trim on
|
||||||
|
// an empty cache is cheap, so there wouldn't be a big performance hit in that case.
|
||||||
|
if data, err := lockedfile.Read(filepath.Join(c.dir, "trim.txt")); err == nil {
|
||||||
|
if t, err := strconv.ParseInt(strings.TrimSpace(string(data)), 10, 64); err == nil {
|
||||||
|
lastTrim := time.Unix(t, 0)
|
||||||
|
if d := now.Sub(lastTrim); d < trimInterval && d > -mtimeInterval {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim each of the 256 subdirectories.
|
||||||
|
// We subtract an additional mtimeInterval
|
||||||
|
// to account for the imprecision of our "last used" mtimes.
|
||||||
|
cutoff := now.Add(-trimLimit - mtimeInterval)
|
||||||
|
for i := 0; i < 256; i++ {
|
||||||
|
subdir := filepath.Join(c.dir, fmt.Sprintf("%02x", i))
|
||||||
|
c.trimSubdir(subdir, cutoff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore errors from here: if we don't write the complete timestamp, the
|
||||||
|
// cache will appear older than it is, and we'll trim it again next time.
|
||||||
|
var b bytes.Buffer
|
||||||
|
fmt.Fprintf(&b, "%d", now.Unix())
|
||||||
|
if err := lockedfile.Write(filepath.Join(c.dir, "trim.txt"), &b, 0666); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// trimSubdir trims a single cache subdirectory.
|
||||||
|
func (c *Cache) trimSubdir(subdir string, cutoff time.Time) {
|
||||||
|
// Read all directory entries from subdir before removing
|
||||||
|
// any files, in case removing files invalidates the file offset
|
||||||
|
// in the directory scan. Also, ignore error from f.Readdirnames,
|
||||||
|
// because we don't care about reporting the error and we still
|
||||||
|
// want to process any entries found before the error.
|
||||||
|
f, err := os.Open(subdir)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
names, _ := f.Readdirnames(-1)
|
||||||
|
f.Close()
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
// Remove only cache entries (xxxx-a and xxxx-d).
|
||||||
|
if !strings.HasSuffix(name, "-a") && !strings.HasSuffix(name, "-d") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entry := filepath.Join(subdir, name)
|
||||||
|
info, err := os.Stat(entry)
|
||||||
|
if err == nil && info.ModTime().Before(cutoff) {
|
||||||
|
os.Remove(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// putIndexEntry adds an entry to the cache recording that executing the action
|
||||||
|
// with the given id produces an output with the given output id (hash) and size.
|
||||||
|
func (c *Cache) putIndexEntry(id ActionID, out OutputID, size int64, allowVerify bool) error {
|
||||||
|
// Note: We expect that for one reason or another it may happen
|
||||||
|
// that repeating an action produces a different output hash
|
||||||
|
// (for example, if the output contains a time stamp or temp dir name).
|
||||||
|
// While not ideal, this is also not a correctness problem, so we
|
||||||
|
// don't make a big deal about it. In particular, we leave the action
|
||||||
|
// cache entries writable specifically so that they can be overwritten.
|
||||||
|
//
|
||||||
|
// Setting GODEBUG=gocacheverify=1 does make a big deal:
|
||||||
|
// in verify mode we are double-checking that the cache entries
|
||||||
|
// are entirely reproducible. As just noted, this may be unrealistic
|
||||||
|
// in some cases but the check is also useful for shaking out real bugs.
|
||||||
|
entry := fmt.Sprintf("v1 %x %x %20d %20d\n", id, out, size, time.Now().UnixNano())
|
||||||
|
if verify && allowVerify {
|
||||||
|
old, err := c.get(id)
|
||||||
|
if err == nil && (old.OutputID != out || old.Size != size) {
|
||||||
|
// panic to show stack trace, so we can see what code is generating this cache entry.
|
||||||
|
msg := fmt.Sprintf("go: internal cache error: cache verify failed: id=%x changed:<<<\n%s\n>>>\nold: %x %d\nnew: %x %d", id, reverseHash(id), out, size, old.OutputID, old.Size)
|
||||||
|
panic(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file := c.fileName(id, "a")
|
||||||
|
|
||||||
|
// Copy file to cache directory.
|
||||||
|
mode := os.O_WRONLY | os.O_CREATE
|
||||||
|
f, err := os.OpenFile(file, mode, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = f.WriteString(entry)
|
||||||
|
if err == nil {
|
||||||
|
// Truncate the file only *after* writing it.
|
||||||
|
// (This should be a no-op, but truncate just in case of previous corruption.)
|
||||||
|
//
|
||||||
|
// This differs from os.WriteFile, which truncates to 0 *before* writing
|
||||||
|
// via os.O_TRUNC. Truncating only after writing ensures that a second write
|
||||||
|
// of the same content to the same file is idempotent, and does not — even
|
||||||
|
// temporarily! — undo the effect of the first write.
|
||||||
|
err = f.Truncate(int64(len(entry)))
|
||||||
|
}
|
||||||
|
if closeErr := f.Close(); err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// TODO(bcmills): This Remove potentially races with another go command writing to file.
|
||||||
|
// Can we eliminate it?
|
||||||
|
os.Remove(file)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
os.Chtimes(file, c.now(), c.now()) // mainly for tests
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put stores the given output in the cache as the output for the action ID.
|
||||||
|
// It may read file twice. The content of file must not change between the two passes.
|
||||||
|
func (c *Cache) Put(id ActionID, file io.ReadSeeker) (OutputID, int64, error) {
|
||||||
|
return c.put(id, file, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutNoVerify is like Put but disables the verify check
|
||||||
|
// when GODEBUG=goverifycache=1 is set.
|
||||||
|
// It is meant for data that is OK to cache but that we expect to vary slightly from run to run,
|
||||||
|
// like test output containing times and the like.
|
||||||
|
func (c *Cache) PutNoVerify(id ActionID, file io.ReadSeeker) (OutputID, int64, error) {
|
||||||
|
return c.put(id, file, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Cache) put(id ActionID, file io.ReadSeeker, allowVerify bool) (OutputID, int64, error) {
|
||||||
|
// Compute output ID.
|
||||||
|
h := sha512.New()
|
||||||
|
if _, err := file.Seek(0, 0); err != nil {
|
||||||
|
return OutputID{}, 0, err
|
||||||
|
}
|
||||||
|
size, err := io.Copy(h, file)
|
||||||
|
if err != nil {
|
||||||
|
return OutputID{}, 0, err
|
||||||
|
}
|
||||||
|
var out OutputID
|
||||||
|
h.Sum(out[:0])
|
||||||
|
|
||||||
|
// Copy to cached output file (if not already present).
|
||||||
|
if err := c.copyFile(file, out, size); err != nil {
|
||||||
|
return out, size, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add to cache index.
|
||||||
|
return out, size, c.putIndexEntry(id, out, size, allowVerify)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutBytes stores the given bytes in the cache as the output for the action ID.
|
||||||
|
func (c *Cache) PutBytes(id ActionID, data []byte) error {
|
||||||
|
_, _, err := c.Put(id, bytes.NewReader(data))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// copyFile copies file into the cache, expecting it to have the given
|
||||||
|
// output ID and size, if that file is not present already.
|
||||||
|
func (c *Cache) copyFile(file io.ReadSeeker, out OutputID, size int64) error {
|
||||||
|
name := c.fileName(out, "d")
|
||||||
|
info, err := os.Stat(name)
|
||||||
|
if err == nil && info.Size() == size {
|
||||||
|
// Check hash.
|
||||||
|
if f, err := os.Open(name); err == nil {
|
||||||
|
h := sha512.New()
|
||||||
|
io.Copy(h, f)
|
||||||
|
f.Close()
|
||||||
|
var out2 OutputID
|
||||||
|
h.Sum(out2[:0])
|
||||||
|
if out == out2 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Hash did not match. Fall through and rewrite file.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy file to cache directory.
|
||||||
|
mode := os.O_RDWR | os.O_CREATE
|
||||||
|
if err == nil && info.Size() > size { // shouldn't happen but fix in case
|
||||||
|
mode |= os.O_TRUNC
|
||||||
|
}
|
||||||
|
f, err := os.OpenFile(name, mode, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
if size == 0 {
|
||||||
|
// File now exists with correct size.
|
||||||
|
// Only one possible zero-length file, so contents are OK too.
|
||||||
|
// Early return here makes sure there's a "last byte" for code below.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// From here on, if any of the I/O writing the file fails,
|
||||||
|
// we make a best-effort attempt to truncate the file f
|
||||||
|
// before returning, to avoid leaving bad bytes in the file.
|
||||||
|
|
||||||
|
// Copy file to f, but also into h to double-check hash.
|
||||||
|
if _, err := file.Seek(0, 0); err != nil {
|
||||||
|
f.Truncate(0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h := sha512.New()
|
||||||
|
w := io.MultiWriter(f, h)
|
||||||
|
if _, err := io.CopyN(w, file, size-1); err != nil {
|
||||||
|
f.Truncate(0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Check last byte before writing it; writing it will make the size match
|
||||||
|
// what other processes expect to find and might cause them to start
|
||||||
|
// using the file.
|
||||||
|
buf := make([]byte, 1)
|
||||||
|
if _, err := file.Read(buf); err != nil {
|
||||||
|
f.Truncate(0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
h.Write(buf)
|
||||||
|
sum := h.Sum(nil)
|
||||||
|
if !bytes.Equal(sum, out[:]) {
|
||||||
|
f.Truncate(0)
|
||||||
|
return fmt.Errorf("file content changed underfoot")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit cache file entry.
|
||||||
|
if _, err := f.Write(buf); err != nil {
|
||||||
|
f.Truncate(0)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
// Data might not have been written,
|
||||||
|
// but file may look like it is the right size.
|
||||||
|
// To be extra careful, remove cached file.
|
||||||
|
os.Remove(name)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
os.Chtimes(name, c.now(), c.now()) // mainly for tests
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
5
vendor/github.com/rancher-sandbox/gofilecache/go.mod
generated
vendored
Normal file
5
vendor/github.com/rancher-sandbox/gofilecache/go.mod
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module github.com/rancher-sandbox/gofilecache
|
||||||
|
|
||||||
|
go 1.16
|
||||||
|
|
||||||
|
require github.com/rogpeppe/go-internal v1.8.0
|
8
vendor/github.com/rancher-sandbox/gofilecache/go.sum
generated
vendored
Normal file
8
vendor/github.com/rancher-sandbox/gofilecache/go.sum
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
34
vendor/github.com/rancher-sandbox/gofilecache/gofilecache.go
generated
vendored
Normal file
34
vendor/github.com/rancher-sandbox/gofilecache/gofilecache.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2017 The Go Authors, SUSE LLC. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gofilecache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
const cacheREADME = `This directory holds a cache directory tree.
|
||||||
|
This has been created using github.com/rancher-sandbox/gofilecache/
|
||||||
|
`
|
||||||
|
|
||||||
|
func InitCache(cacheDir string) *Cache {
|
||||||
|
if err := os.MkdirAll(cacheDir, 0777); err != nil {
|
||||||
|
log.Fatalf("failed to initialize build cache at %s: %s\n", cacheDir, err)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(filepath.Join(cacheDir, "README")); err != nil {
|
||||||
|
// Best effort.
|
||||||
|
ioutil.WriteFile(filepath.Join(cacheDir, "README"), []byte(cacheREADME), 0666)
|
||||||
|
}
|
||||||
|
|
||||||
|
c, err := Open(cacheDir)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to initialize build cache at %s: %s\n", cacheDir, err)
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
var ()
|
174
vendor/github.com/rancher-sandbox/gofilecache/hash.go
generated
vendored
Normal file
174
vendor/github.com/rancher-sandbox/gofilecache/hash.go
generated
vendored
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package gofilecache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha512"
|
||||||
|
"fmt"
|
||||||
|
"hash"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var debugHash = false // set when GODEBUG=gocachehash=1
|
||||||
|
|
||||||
|
// HashSize is the number of bytes in a hash.
|
||||||
|
const HashSize = 64
|
||||||
|
|
||||||
|
// A Hash provides access to the canonical hash function used to index the cache.
|
||||||
|
// The current implementation uses salted SHA512, but clients must not assume this.
|
||||||
|
type Hash struct {
|
||||||
|
h hash.Hash
|
||||||
|
name string // for debugging
|
||||||
|
buf *bytes.Buffer // for verify
|
||||||
|
}
|
||||||
|
|
||||||
|
// hashSalt is a salt string added to the beginning of every hash
|
||||||
|
// created by NewHash. Using the Go version makes sure that different
|
||||||
|
// versions of the go command (or even different Git commits during
|
||||||
|
// work on the development branch) do not address the same cache
|
||||||
|
// entries, so that a bug in one version does not affect the execution
|
||||||
|
// of other versions. This salt will result in additional ActionID files
|
||||||
|
// in the cache, but not additional copies of the large output files,
|
||||||
|
// which are still addressed by unsalted SHA512.
|
||||||
|
var hashSalt = []byte(runtime.Version())
|
||||||
|
|
||||||
|
// Subkey returns an action ID corresponding to mixing a parent
|
||||||
|
// action ID with a string description of the subkey.
|
||||||
|
func Subkey(parent ActionID, desc string) ActionID {
|
||||||
|
h := sha512.New()
|
||||||
|
h.Write([]byte("subkey:"))
|
||||||
|
h.Write(parent[:])
|
||||||
|
h.Write([]byte(desc))
|
||||||
|
var out ActionID
|
||||||
|
h.Sum(out[:0])
|
||||||
|
if debugHash {
|
||||||
|
fmt.Fprintf(os.Stderr, "HASH subkey %x %q = %x\n", parent, desc, out)
|
||||||
|
}
|
||||||
|
if verify {
|
||||||
|
hashDebug.Lock()
|
||||||
|
hashDebug.m[out] = fmt.Sprintf("subkey %x %q", parent, desc)
|
||||||
|
hashDebug.Unlock()
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHash returns a new Hash.
|
||||||
|
// The caller is expected to Write data to it and then call Sum.
|
||||||
|
func NewHash(name string) *Hash {
|
||||||
|
h := &Hash{h: sha512.New(), name: name}
|
||||||
|
if debugHash {
|
||||||
|
fmt.Fprintf(os.Stderr, "HASH[%s]\n", h.name)
|
||||||
|
}
|
||||||
|
h.Write(hashSalt)
|
||||||
|
if verify {
|
||||||
|
h.buf = new(bytes.Buffer)
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes data to the running hash.
|
||||||
|
func (h *Hash) Write(b []byte) (int, error) {
|
||||||
|
if debugHash {
|
||||||
|
fmt.Fprintf(os.Stderr, "HASH[%s]: %q\n", h.name, b)
|
||||||
|
}
|
||||||
|
if h.buf != nil {
|
||||||
|
h.buf.Write(b)
|
||||||
|
}
|
||||||
|
return h.h.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum returns the hash of the data written previously.
|
||||||
|
func (h *Hash) Sum() [HashSize]byte {
|
||||||
|
var out [HashSize]byte
|
||||||
|
h.h.Sum(out[:0])
|
||||||
|
if debugHash {
|
||||||
|
fmt.Fprintf(os.Stderr, "HASH[%s]: %x\n", h.name, out)
|
||||||
|
}
|
||||||
|
if h.buf != nil {
|
||||||
|
hashDebug.Lock()
|
||||||
|
if hashDebug.m == nil {
|
||||||
|
hashDebug.m = make(map[[HashSize]byte]string)
|
||||||
|
}
|
||||||
|
hashDebug.m[out] = h.buf.String()
|
||||||
|
hashDebug.Unlock()
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// In GODEBUG=gocacheverify=1 mode,
|
||||||
|
// hashDebug holds the input to every computed hash ID,
|
||||||
|
// so that we can work backward from the ID involved in a
|
||||||
|
// cache entry mismatch to a description of what should be there.
|
||||||
|
var hashDebug struct {
|
||||||
|
sync.Mutex
|
||||||
|
m map[[HashSize]byte]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// reverseHash returns the input used to compute the hash id.
|
||||||
|
func reverseHash(id [HashSize]byte) string {
|
||||||
|
hashDebug.Lock()
|
||||||
|
s := hashDebug.m[id]
|
||||||
|
hashDebug.Unlock()
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
var hashFileCache struct {
|
||||||
|
sync.Mutex
|
||||||
|
m map[string][HashSize]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileHash returns the hash of the named file.
|
||||||
|
// It caches repeated lookups for a given file,
|
||||||
|
// and the cache entry for a file can be initialized
|
||||||
|
// using SetFileHash.
|
||||||
|
// The hash used by FileHash is not the same as
|
||||||
|
// the hash used by NewHash.
|
||||||
|
func FileHash(file string) ([HashSize]byte, error) {
|
||||||
|
hashFileCache.Lock()
|
||||||
|
out, ok := hashFileCache.m[file]
|
||||||
|
hashFileCache.Unlock()
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
h := sha512.New()
|
||||||
|
f, err := os.Open(file)
|
||||||
|
if err != nil {
|
||||||
|
if debugHash {
|
||||||
|
fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
|
||||||
|
}
|
||||||
|
return [HashSize]byte{}, err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(h, f)
|
||||||
|
f.Close()
|
||||||
|
if err != nil {
|
||||||
|
if debugHash {
|
||||||
|
fmt.Fprintf(os.Stderr, "HASH %s: %v\n", file, err)
|
||||||
|
}
|
||||||
|
return [HashSize]byte{}, err
|
||||||
|
}
|
||||||
|
h.Sum(out[:0])
|
||||||
|
if debugHash {
|
||||||
|
fmt.Fprintf(os.Stderr, "HASH %s: %x\n", file, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
SetFileHash(file, out)
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetFileHash sets the hash returned by FileHash for file.
|
||||||
|
func SetFileHash(file string, sum [HashSize]byte) {
|
||||||
|
hashFileCache.Lock()
|
||||||
|
if hashFileCache.m == nil {
|
||||||
|
hashFileCache.m = make(map[string][HashSize]byte)
|
||||||
|
}
|
||||||
|
hashFileCache.m[file] = sum
|
||||||
|
hashFileCache.Unlock()
|
||||||
|
}
|
27
vendor/github.com/rogpeppe/go-internal/LICENSE
generated
vendored
Normal file
27
vendor/github.com/rogpeppe/go-internal/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
Copyright (c) 2018 The Go Authors. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* 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.
|
||||||
|
* Neither the name of Google Inc. nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"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 THE COPYRIGHT
|
||||||
|
OWNER 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.
|
7
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/mksyscall.go
generated
vendored
Normal file
7
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/mksyscall.go
generated
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go psapi_windows.go symlink_windows.go
|
20
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/psapi_windows.go
generated
vendored
Normal file
20
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/psapi_windows.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
type PROCESS_MEMORY_COUNTERS struct {
|
||||||
|
CB uint32
|
||||||
|
PageFaultCount uint32
|
||||||
|
PeakWorkingSetSize uintptr
|
||||||
|
WorkingSetSize uintptr
|
||||||
|
QuotaPeakPagedPoolUsage uintptr
|
||||||
|
QuotaPagedPoolUsage uintptr
|
||||||
|
QuotaPeakNonPagedPoolUsage uintptr
|
||||||
|
QuotaNonPagedPoolUsage uintptr
|
||||||
|
PagefileUsage uintptr
|
||||||
|
PeakPagefileUsage uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) = psapi.GetProcessMemoryInfo
|
64
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/reparse_windows.go
generated
vendored
Normal file
64
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/reparse_windows.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
const (
|
||||||
|
FSCTL_SET_REPARSE_POINT = 0x000900A4
|
||||||
|
IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
|
||||||
|
|
||||||
|
SYMLINK_FLAG_RELATIVE = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// These structures are described
|
||||||
|
// in https://msdn.microsoft.com/en-us/library/cc232007.aspx
|
||||||
|
// and https://msdn.microsoft.com/en-us/library/cc232006.aspx.
|
||||||
|
|
||||||
|
// REPARSE_DATA_BUFFER_HEADER is a common part of REPARSE_DATA_BUFFER structure.
|
||||||
|
type REPARSE_DATA_BUFFER_HEADER struct {
|
||||||
|
ReparseTag uint32
|
||||||
|
// The size, in bytes, of the reparse data that follows
|
||||||
|
// the common portion of the REPARSE_DATA_BUFFER element.
|
||||||
|
// This value is the length of the data starting at the
|
||||||
|
// SubstituteNameOffset field.
|
||||||
|
ReparseDataLength uint16
|
||||||
|
Reserved uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type SymbolicLinkReparseBuffer struct {
|
||||||
|
// The integer that contains the offset, in bytes,
|
||||||
|
// of the substitute name string in the PathBuffer array,
|
||||||
|
// computed as an offset from byte 0 of PathBuffer. Note that
|
||||||
|
// this offset must be divided by 2 to get the array index.
|
||||||
|
SubstituteNameOffset uint16
|
||||||
|
// The integer that contains the length, in bytes, of the
|
||||||
|
// substitute name string. If this string is null-terminated,
|
||||||
|
// SubstituteNameLength does not include the Unicode null character.
|
||||||
|
SubstituteNameLength uint16
|
||||||
|
// PrintNameOffset is similar to SubstituteNameOffset.
|
||||||
|
PrintNameOffset uint16
|
||||||
|
// PrintNameLength is similar to SubstituteNameLength.
|
||||||
|
PrintNameLength uint16
|
||||||
|
// Flags specifies whether the substitute name is a full path name or
|
||||||
|
// a path name relative to the directory containing the symbolic link.
|
||||||
|
Flags uint32
|
||||||
|
PathBuffer [1]uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type MountPointReparseBuffer struct {
|
||||||
|
// The integer that contains the offset, in bytes,
|
||||||
|
// of the substitute name string in the PathBuffer array,
|
||||||
|
// computed as an offset from byte 0 of PathBuffer. Note that
|
||||||
|
// this offset must be divided by 2 to get the array index.
|
||||||
|
SubstituteNameOffset uint16
|
||||||
|
// The integer that contains the length, in bytes, of the
|
||||||
|
// substitute name string. If this string is null-terminated,
|
||||||
|
// SubstituteNameLength does not include the Unicode null character.
|
||||||
|
SubstituteNameLength uint16
|
||||||
|
// PrintNameOffset is similar to SubstituteNameOffset.
|
||||||
|
PrintNameOffset uint16
|
||||||
|
// PrintNameLength is similar to SubstituteNameLength.
|
||||||
|
PrintNameLength uint16
|
||||||
|
PathBuffer [1]uint16
|
||||||
|
}
|
128
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/security_windows.go
generated
vendored
Normal file
128
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/security_windows.go
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SecurityAnonymous = 0
|
||||||
|
SecurityIdentification = 1
|
||||||
|
SecurityImpersonation = 2
|
||||||
|
SecurityDelegation = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys ImpersonateSelf(impersonationlevel uint32) (err error) = advapi32.ImpersonateSelf
|
||||||
|
//sys RevertToSelf() (err error) = advapi32.RevertToSelf
|
||||||
|
|
||||||
|
const (
|
||||||
|
TOKEN_ADJUST_PRIVILEGES = 0x0020
|
||||||
|
SE_PRIVILEGE_ENABLED = 0x00000002
|
||||||
|
)
|
||||||
|
|
||||||
|
type LUID struct {
|
||||||
|
LowPart uint32
|
||||||
|
HighPart int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type LUID_AND_ATTRIBUTES struct {
|
||||||
|
Luid LUID
|
||||||
|
Attributes uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type TOKEN_PRIVILEGES struct {
|
||||||
|
PrivilegeCount uint32
|
||||||
|
Privileges [1]LUID_AND_ATTRIBUTES
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys OpenThreadToken(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) = advapi32.OpenThreadToken
|
||||||
|
//sys LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (err error) = advapi32.LookupPrivilegeValueW
|
||||||
|
//sys adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) [true] = advapi32.AdjustTokenPrivileges
|
||||||
|
|
||||||
|
func AdjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) error {
|
||||||
|
ret, err := adjustTokenPrivileges(token, disableAllPrivileges, newstate, buflen, prevstate, returnlen)
|
||||||
|
if ret == 0 {
|
||||||
|
// AdjustTokenPrivileges call failed
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// AdjustTokenPrivileges call succeeded
|
||||||
|
if err == syscall.EINVAL {
|
||||||
|
// GetLastError returned ERROR_SUCCESS
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) = advapi32.DuplicateTokenEx
|
||||||
|
//sys SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation uintptr, tokenInformationLength uint32) (err error) = advapi32.SetTokenInformation
|
||||||
|
|
||||||
|
type SID_AND_ATTRIBUTES struct {
|
||||||
|
Sid *syscall.SID
|
||||||
|
Attributes uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type TOKEN_MANDATORY_LABEL struct {
|
||||||
|
Label SID_AND_ATTRIBUTES
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tml *TOKEN_MANDATORY_LABEL) Size() uint32 {
|
||||||
|
return uint32(unsafe.Sizeof(TOKEN_MANDATORY_LABEL{})) + syscall.GetLengthSid(tml.Label.Sid)
|
||||||
|
}
|
||||||
|
|
||||||
|
const SE_GROUP_INTEGRITY = 0x00000020
|
||||||
|
|
||||||
|
type TokenType uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
TokenPrimary TokenType = 1
|
||||||
|
TokenImpersonation TokenType = 2
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) = userenv.GetProfilesDirectoryW
|
||||||
|
|
||||||
|
const (
|
||||||
|
LG_INCLUDE_INDIRECT = 0x1
|
||||||
|
MAX_PREFERRED_LENGTH = 0xFFFFFFFF
|
||||||
|
)
|
||||||
|
|
||||||
|
type LocalGroupUserInfo0 struct {
|
||||||
|
Name *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserInfo4 struct {
|
||||||
|
Name *uint16
|
||||||
|
Password *uint16
|
||||||
|
PasswordAge uint32
|
||||||
|
Priv uint32
|
||||||
|
HomeDir *uint16
|
||||||
|
Comment *uint16
|
||||||
|
Flags uint32
|
||||||
|
ScriptPath *uint16
|
||||||
|
AuthFlags uint32
|
||||||
|
FullName *uint16
|
||||||
|
UsrComment *uint16
|
||||||
|
Parms *uint16
|
||||||
|
Workstations *uint16
|
||||||
|
LastLogon uint32
|
||||||
|
LastLogoff uint32
|
||||||
|
AcctExpires uint32
|
||||||
|
MaxStorage uint32
|
||||||
|
UnitsPerWeek uint32
|
||||||
|
LogonHours *byte
|
||||||
|
BadPwCount uint32
|
||||||
|
NumLogons uint32
|
||||||
|
LogonServer *uint16
|
||||||
|
CountryCode uint32
|
||||||
|
CodePage uint32
|
||||||
|
UserSid *syscall.SID
|
||||||
|
PrimaryGroupID uint32
|
||||||
|
Profile *uint16
|
||||||
|
HomeDirDrive *uint16
|
||||||
|
PasswordExpired uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, flags uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32) (neterr error) = netapi32.NetUserGetLocalGroups
|
39
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/symlink_windows.go
generated
vendored
Normal file
39
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/symlink_windows.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const (
|
||||||
|
ERROR_INVALID_PARAMETER syscall.Errno = 87
|
||||||
|
|
||||||
|
// symlink support for CreateSymbolicLink() starting with Windows 10 (1703, v10.0.14972)
|
||||||
|
SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2
|
||||||
|
|
||||||
|
// FileInformationClass values
|
||||||
|
FileBasicInfo = 0 // FILE_BASIC_INFO
|
||||||
|
FileStandardInfo = 1 // FILE_STANDARD_INFO
|
||||||
|
FileNameInfo = 2 // FILE_NAME_INFO
|
||||||
|
FileStreamInfo = 7 // FILE_STREAM_INFO
|
||||||
|
FileCompressionInfo = 8 // FILE_COMPRESSION_INFO
|
||||||
|
FileAttributeTagInfo = 9 // FILE_ATTRIBUTE_TAG_INFO
|
||||||
|
FileIdBothDirectoryInfo = 0xa // FILE_ID_BOTH_DIR_INFO
|
||||||
|
FileIdBothDirectoryRestartInfo = 0xb // FILE_ID_BOTH_DIR_INFO
|
||||||
|
FileRemoteProtocolInfo = 0xd // FILE_REMOTE_PROTOCOL_INFO
|
||||||
|
FileFullDirectoryInfo = 0xe // FILE_FULL_DIR_INFO
|
||||||
|
FileFullDirectoryRestartInfo = 0xf // FILE_FULL_DIR_INFO
|
||||||
|
FileStorageInfo = 0x10 // FILE_STORAGE_INFO
|
||||||
|
FileAlignmentInfo = 0x11 // FILE_ALIGNMENT_INFO
|
||||||
|
FileIdInfo = 0x12 // FILE_ID_INFO
|
||||||
|
FileIdExtdDirectoryInfo = 0x13 // FILE_ID_EXTD_DIR_INFO
|
||||||
|
FileIdExtdDirectoryRestartInfo = 0x14 // FILE_ID_EXTD_DIR_INFO
|
||||||
|
)
|
||||||
|
|
||||||
|
type FILE_ATTRIBUTE_TAG_INFO struct {
|
||||||
|
FileAttributes uint32
|
||||||
|
ReparseTag uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys GetFileInformationByHandleEx(handle syscall.Handle, class uint32, info *byte, bufsize uint32) (err error)
|
307
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/syscall_windows.go
generated
vendored
Normal file
307
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/syscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ERROR_SHARING_VIOLATION syscall.Errno = 32
|
||||||
|
ERROR_LOCK_VIOLATION syscall.Errno = 33
|
||||||
|
ERROR_NOT_SUPPORTED syscall.Errno = 50
|
||||||
|
ERROR_CALL_NOT_IMPLEMENTED syscall.Errno = 120
|
||||||
|
ERROR_INVALID_NAME syscall.Errno = 123
|
||||||
|
ERROR_LOCK_FAILED syscall.Errno = 167
|
||||||
|
ERROR_NO_UNICODE_TRANSLATION syscall.Errno = 1113
|
||||||
|
)
|
||||||
|
|
||||||
|
const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
|
||||||
|
|
||||||
|
const (
|
||||||
|
IF_TYPE_OTHER = 1
|
||||||
|
IF_TYPE_ETHERNET_CSMACD = 6
|
||||||
|
IF_TYPE_ISO88025_TOKENRING = 9
|
||||||
|
IF_TYPE_PPP = 23
|
||||||
|
IF_TYPE_SOFTWARE_LOOPBACK = 24
|
||||||
|
IF_TYPE_ATM = 37
|
||||||
|
IF_TYPE_IEEE80211 = 71
|
||||||
|
IF_TYPE_TUNNEL = 131
|
||||||
|
IF_TYPE_IEEE1394 = 144
|
||||||
|
)
|
||||||
|
|
||||||
|
type SocketAddress struct {
|
||||||
|
Sockaddr *syscall.RawSockaddrAny
|
||||||
|
SockaddrLength int32
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterUnicastAddress struct {
|
||||||
|
Length uint32
|
||||||
|
Flags uint32
|
||||||
|
Next *IpAdapterUnicastAddress
|
||||||
|
Address SocketAddress
|
||||||
|
PrefixOrigin int32
|
||||||
|
SuffixOrigin int32
|
||||||
|
DadState int32
|
||||||
|
ValidLifetime uint32
|
||||||
|
PreferredLifetime uint32
|
||||||
|
LeaseLifetime uint32
|
||||||
|
OnLinkPrefixLength uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterAnycastAddress struct {
|
||||||
|
Length uint32
|
||||||
|
Flags uint32
|
||||||
|
Next *IpAdapterAnycastAddress
|
||||||
|
Address SocketAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterMulticastAddress struct {
|
||||||
|
Length uint32
|
||||||
|
Flags uint32
|
||||||
|
Next *IpAdapterMulticastAddress
|
||||||
|
Address SocketAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterDnsServerAdapter struct {
|
||||||
|
Length uint32
|
||||||
|
Reserved uint32
|
||||||
|
Next *IpAdapterDnsServerAdapter
|
||||||
|
Address SocketAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterPrefix struct {
|
||||||
|
Length uint32
|
||||||
|
Flags uint32
|
||||||
|
Next *IpAdapterPrefix
|
||||||
|
Address SocketAddress
|
||||||
|
PrefixLength uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type IpAdapterAddresses struct {
|
||||||
|
Length uint32
|
||||||
|
IfIndex uint32
|
||||||
|
Next *IpAdapterAddresses
|
||||||
|
AdapterName *byte
|
||||||
|
FirstUnicastAddress *IpAdapterUnicastAddress
|
||||||
|
FirstAnycastAddress *IpAdapterAnycastAddress
|
||||||
|
FirstMulticastAddress *IpAdapterMulticastAddress
|
||||||
|
FirstDnsServerAddress *IpAdapterDnsServerAdapter
|
||||||
|
DnsSuffix *uint16
|
||||||
|
Description *uint16
|
||||||
|
FriendlyName *uint16
|
||||||
|
PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte
|
||||||
|
PhysicalAddressLength uint32
|
||||||
|
Flags uint32
|
||||||
|
Mtu uint32
|
||||||
|
IfType uint32
|
||||||
|
OperStatus uint32
|
||||||
|
Ipv6IfIndex uint32
|
||||||
|
ZoneIndices [16]uint32
|
||||||
|
FirstPrefix *IpAdapterPrefix
|
||||||
|
/* more fields might be present here. */
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
IfOperStatusUp = 1
|
||||||
|
IfOperStatusDown = 2
|
||||||
|
IfOperStatusTesting = 3
|
||||||
|
IfOperStatusUnknown = 4
|
||||||
|
IfOperStatusDormant = 5
|
||||||
|
IfOperStatusNotPresent = 6
|
||||||
|
IfOperStatusLowerLayerDown = 7
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
|
||||||
|
//sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
|
||||||
|
//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
|
||||||
|
//sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
|
||||||
|
|
||||||
|
const (
|
||||||
|
WSA_FLAG_OVERLAPPED = 0x01
|
||||||
|
WSA_FLAG_NO_HANDLE_INHERIT = 0x80
|
||||||
|
|
||||||
|
WSAEMSGSIZE syscall.Errno = 10040
|
||||||
|
|
||||||
|
MSG_PEEK = 0x2
|
||||||
|
MSG_TRUNC = 0x0100
|
||||||
|
MSG_CTRUNC = 0x0200
|
||||||
|
|
||||||
|
socket_error = uintptr(^uint32(0))
|
||||||
|
)
|
||||||
|
|
||||||
|
var WSAID_WSASENDMSG = syscall.GUID{
|
||||||
|
Data1: 0xa441e712,
|
||||||
|
Data2: 0x754f,
|
||||||
|
Data3: 0x43ca,
|
||||||
|
Data4: [8]byte{0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d},
|
||||||
|
}
|
||||||
|
|
||||||
|
var WSAID_WSARECVMSG = syscall.GUID{
|
||||||
|
Data1: 0xf689d7c8,
|
||||||
|
Data2: 0x6f1f,
|
||||||
|
Data3: 0x436b,
|
||||||
|
Data4: [8]byte{0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22},
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendRecvMsgFunc struct {
|
||||||
|
once sync.Once
|
||||||
|
sendAddr uintptr
|
||||||
|
recvAddr uintptr
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type WSAMsg struct {
|
||||||
|
Name *syscall.RawSockaddrAny
|
||||||
|
Namelen int32
|
||||||
|
Buffers *syscall.WSABuf
|
||||||
|
BufferCount uint32
|
||||||
|
Control syscall.WSABuf
|
||||||
|
Flags uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = ws2_32.WSASocketW
|
||||||
|
|
||||||
|
func loadWSASendRecvMsg() error {
|
||||||
|
sendRecvMsgFunc.once.Do(func() {
|
||||||
|
var s syscall.Handle
|
||||||
|
s, sendRecvMsgFunc.err = syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
|
||||||
|
if sendRecvMsgFunc.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer syscall.CloseHandle(s)
|
||||||
|
var n uint32
|
||||||
|
sendRecvMsgFunc.err = syscall.WSAIoctl(s,
|
||||||
|
syscall.SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||||
|
(*byte)(unsafe.Pointer(&WSAID_WSARECVMSG)),
|
||||||
|
uint32(unsafe.Sizeof(WSAID_WSARECVMSG)),
|
||||||
|
(*byte)(unsafe.Pointer(&sendRecvMsgFunc.recvAddr)),
|
||||||
|
uint32(unsafe.Sizeof(sendRecvMsgFunc.recvAddr)),
|
||||||
|
&n, nil, 0)
|
||||||
|
if sendRecvMsgFunc.err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sendRecvMsgFunc.err = syscall.WSAIoctl(s,
|
||||||
|
syscall.SIO_GET_EXTENSION_FUNCTION_POINTER,
|
||||||
|
(*byte)(unsafe.Pointer(&WSAID_WSASENDMSG)),
|
||||||
|
uint32(unsafe.Sizeof(WSAID_WSASENDMSG)),
|
||||||
|
(*byte)(unsafe.Pointer(&sendRecvMsgFunc.sendAddr)),
|
||||||
|
uint32(unsafe.Sizeof(sendRecvMsgFunc.sendAddr)),
|
||||||
|
&n, nil, 0)
|
||||||
|
})
|
||||||
|
return sendRecvMsgFunc.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func WSASendMsg(fd syscall.Handle, msg *WSAMsg, flags uint32, bytesSent *uint32, overlapped *syscall.Overlapped, croutine *byte) error {
|
||||||
|
err := loadWSASendRecvMsg()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.sendAddr, 6, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(flags), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)))
|
||||||
|
if r1 == socket_error {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func WSARecvMsg(fd syscall.Handle, msg *WSAMsg, bytesReceived *uint32, overlapped *syscall.Overlapped, croutine *byte) error {
|
||||||
|
err := loadWSASendRecvMsg()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
r1, _, e1 := syscall.Syscall6(sendRecvMsgFunc.recvAddr, 5, uintptr(fd), uintptr(unsafe.Pointer(msg)), uintptr(unsafe.Pointer(bytesReceived)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0)
|
||||||
|
if r1 == socket_error {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ComputerNameNetBIOS = 0
|
||||||
|
ComputerNameDnsHostname = 1
|
||||||
|
ComputerNameDnsDomain = 2
|
||||||
|
ComputerNameDnsFullyQualified = 3
|
||||||
|
ComputerNamePhysicalNetBIOS = 4
|
||||||
|
ComputerNamePhysicalDnsHostname = 5
|
||||||
|
ComputerNamePhysicalDnsDomain = 6
|
||||||
|
ComputerNamePhysicalDnsFullyQualified = 7
|
||||||
|
ComputerNameMax = 8
|
||||||
|
|
||||||
|
MOVEFILE_REPLACE_EXISTING = 0x1
|
||||||
|
MOVEFILE_COPY_ALLOWED = 0x2
|
||||||
|
MOVEFILE_DELAY_UNTIL_REBOOT = 0x4
|
||||||
|
MOVEFILE_WRITE_THROUGH = 0x8
|
||||||
|
MOVEFILE_CREATE_HARDLINK = 0x10
|
||||||
|
MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20
|
||||||
|
)
|
||||||
|
|
||||||
|
func Rename(oldpath, newpath string) error {
|
||||||
|
from, err := syscall.UTF16PtrFromString(oldpath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
to, err := syscall.UTF16PtrFromString(newpath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) = kernel32.LockFileEx
|
||||||
|
//sys UnlockFileEx(file syscall.Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) = kernel32.UnlockFileEx
|
||||||
|
|
||||||
|
const (
|
||||||
|
LOCKFILE_FAIL_IMMEDIATELY = 0x00000001
|
||||||
|
LOCKFILE_EXCLUSIVE_LOCK = 0x00000002
|
||||||
|
)
|
||||||
|
|
||||||
|
const MB_ERR_INVALID_CHARS = 8
|
||||||
|
|
||||||
|
//sys GetACP() (acp uint32) = kernel32.GetACP
|
||||||
|
//sys GetConsoleCP() (ccp uint32) = kernel32.GetConsoleCP
|
||||||
|
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
|
||||||
|
//sys GetCurrentThread() (pseudoHandle syscall.Handle, err error) = kernel32.GetCurrentThread
|
||||||
|
|
||||||
|
const STYPE_DISKTREE = 0x00
|
||||||
|
|
||||||
|
type SHARE_INFO_2 struct {
|
||||||
|
Netname *uint16
|
||||||
|
Type uint32
|
||||||
|
Remark *uint16
|
||||||
|
Permissions uint32
|
||||||
|
MaxUses uint32
|
||||||
|
CurrentUses uint32
|
||||||
|
Path *uint16
|
||||||
|
Passwd *uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
//sys NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) = netapi32.NetShareAdd
|
||||||
|
//sys NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) = netapi32.NetShareDel
|
||||||
|
|
||||||
|
const (
|
||||||
|
FILE_NAME_NORMALIZED = 0x0
|
||||||
|
FILE_NAME_OPENED = 0x8
|
||||||
|
|
||||||
|
VOLUME_NAME_DOS = 0x0
|
||||||
|
VOLUME_NAME_GUID = 0x1
|
||||||
|
VOLUME_NAME_NONE = 0x4
|
||||||
|
VOLUME_NAME_NT = 0x2
|
||||||
|
)
|
||||||
|
|
||||||
|
//sys GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) = kernel32.GetFinalPathNameByHandleW
|
||||||
|
|
||||||
|
func LoadGetFinalPathNameByHandle() error {
|
||||||
|
return procGetFinalPathNameByHandleW.Find()
|
||||||
|
}
|
28
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/sysdll/sysdll.go
generated
vendored
Normal file
28
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/sysdll/sysdll.go
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package sysdll is an internal leaf package that records and reports
|
||||||
|
// which Windows DLL names are used by Go itself. These DLLs are then
|
||||||
|
// only loaded from the System32 directory. See Issue 14959.
|
||||||
|
package sysdll
|
||||||
|
|
||||||
|
// IsSystemDLL reports whether the named dll key (a base name, like
|
||||||
|
// "foo.dll") is a system DLL which should only be loaded from the
|
||||||
|
// Windows SYSTEM32 directory.
|
||||||
|
//
|
||||||
|
// Filenames are case sensitive, but that doesn't matter because
|
||||||
|
// the case registered with Add is also the same case used with
|
||||||
|
// LoadDLL later.
|
||||||
|
//
|
||||||
|
// It has no associated mutex and should only be mutated serially
|
||||||
|
// (currently: during init), and not concurrent with DLL loading.
|
||||||
|
var IsSystemDLL = map[string]bool{}
|
||||||
|
|
||||||
|
// Add notes that dll is a system32 DLL which should only be loaded
|
||||||
|
// from the Windows SYSTEM32 directory. It returns its argument back,
|
||||||
|
// for ease of use in generated code.
|
||||||
|
func Add(dll string) string {
|
||||||
|
IsSystemDLL[dll] = true
|
||||||
|
return dll
|
||||||
|
}
|
363
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/zsyscall_windows.go
generated
vendored
Normal file
363
vendor/github.com/rogpeppe/go-internal/internal/syscall/windows/zsyscall_windows.go
generated
vendored
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
// Code generated by 'go generate'; DO NOT EDIT.
|
||||||
|
|
||||||
|
package windows
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/rogpeppe/go-internal/internal/syscall/windows/sysdll"
|
||||||
|
)
|
||||||
|
|
||||||
|
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 (
|
||||||
|
modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll"))
|
||||||
|
modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll"))
|
||||||
|
modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll"))
|
||||||
|
modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll"))
|
||||||
|
modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll"))
|
||||||
|
moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll"))
|
||||||
|
modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll"))
|
||||||
|
|
||||||
|
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
|
||||||
|
procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
|
||||||
|
procMoveFileExW = modkernel32.NewProc("MoveFileExW")
|
||||||
|
procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW")
|
||||||
|
procWSASocketW = modws2_32.NewProc("WSASocketW")
|
||||||
|
procLockFileEx = modkernel32.NewProc("LockFileEx")
|
||||||
|
procUnlockFileEx = modkernel32.NewProc("UnlockFileEx")
|
||||||
|
procGetACP = modkernel32.NewProc("GetACP")
|
||||||
|
procGetConsoleCP = modkernel32.NewProc("GetConsoleCP")
|
||||||
|
procMultiByteToWideChar = modkernel32.NewProc("MultiByteToWideChar")
|
||||||
|
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
|
||||||
|
procNetShareAdd = modnetapi32.NewProc("NetShareAdd")
|
||||||
|
procNetShareDel = modnetapi32.NewProc("NetShareDel")
|
||||||
|
procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
|
||||||
|
procImpersonateSelf = modadvapi32.NewProc("ImpersonateSelf")
|
||||||
|
procRevertToSelf = modadvapi32.NewProc("RevertToSelf")
|
||||||
|
procOpenThreadToken = modadvapi32.NewProc("OpenThreadToken")
|
||||||
|
procLookupPrivilegeValueW = modadvapi32.NewProc("LookupPrivilegeValueW")
|
||||||
|
procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges")
|
||||||
|
procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx")
|
||||||
|
procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation")
|
||||||
|
procGetProfilesDirectoryW = moduserenv.NewProc("GetProfilesDirectoryW")
|
||||||
|
procNetUserGetLocalGroups = modnetapi32.NewProc("NetUserGetLocalGroups")
|
||||||
|
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
|
||||||
|
procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
errcode = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nameformat), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)))
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags))
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(procGetModuleFileNameW.Addr(), 3, uintptr(module), uintptr(unsafe.Pointer(fn)), uintptr(len))
|
||||||
|
n = uint32(r0)
|
||||||
|
if n == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func WSASocket(af int32, typ int32, protocol int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (handle syscall.Handle, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall6(procWSASocketW.Addr(), 6, uintptr(af), uintptr(typ), uintptr(protocol), uintptr(unsafe.Pointer(protinfo)), uintptr(group), uintptr(flags))
|
||||||
|
handle = syscall.Handle(r0)
|
||||||
|
if handle == syscall.InvalidHandle {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(file), uintptr(flags), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped)))
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnlockFileEx(file syscall.Handle, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procUnlockFileEx.Addr(), 5, uintptr(file), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetACP() (acp uint32) {
|
||||||
|
r0, _, _ := syscall.Syscall(procGetACP.Addr(), 0, 0, 0, 0)
|
||||||
|
acp = uint32(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetConsoleCP() (ccp uint32) {
|
||||||
|
r0, _, _ := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0)
|
||||||
|
ccp = uint32(r0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall6(procMultiByteToWideChar.Addr(), 6, uintptr(codePage), uintptr(dwFlags), uintptr(unsafe.Pointer(str)), uintptr(nstr), uintptr(unsafe.Pointer(wchar)), uintptr(nwchar))
|
||||||
|
nwrite = int32(r0)
|
||||||
|
if nwrite == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCurrentThread() (pseudoHandle syscall.Handle, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall(procGetCurrentThread.Addr(), 0, 0, 0, 0)
|
||||||
|
pseudoHandle = syscall.Handle(r0)
|
||||||
|
if pseudoHandle == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetShareAdd(serverName *uint16, level uint32, buf *byte, parmErr *uint16) (neterr error) {
|
||||||
|
r0, _, _ := syscall.Syscall6(procNetShareAdd.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(parmErr)), 0, 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
neterr = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetShareDel(serverName *uint16, netName *uint16, reserved uint32) (neterr error) {
|
||||||
|
r0, _, _ := syscall.Syscall(procNetShareDel.Addr(), 3, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(netName)), uintptr(reserved))
|
||||||
|
if r0 != 0 {
|
||||||
|
neterr = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFinalPathNameByHandle(file syscall.Handle, filePath *uint16, filePathSize uint32, flags uint32) (n uint32, err error) {
|
||||||
|
r0, _, e1 := syscall.Syscall6(procGetFinalPathNameByHandleW.Addr(), 4, uintptr(file), uintptr(unsafe.Pointer(filePath)), uintptr(filePathSize), uintptr(flags), 0, 0)
|
||||||
|
n = uint32(r0)
|
||||||
|
if n == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ImpersonateSelf(impersonationlevel uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procImpersonateSelf.Addr(), 1, uintptr(impersonationlevel), 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(h syscall.Handle, access uint32, openasself bool, token *syscall.Token) (err error) {
|
||||||
|
var _p0 uint32
|
||||||
|
if openasself {
|
||||||
|
_p0 = 1
|
||||||
|
} else {
|
||||||
|
_p0 = 0
|
||||||
|
}
|
||||||
|
r1, _, e1 := syscall.Syscall6(procOpenThreadToken.Addr(), 4, uintptr(h), uintptr(access), uintptr(_p0), uintptr(unsafe.Pointer(token)), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func LookupPrivilegeValue(systemname *uint16, name *uint16, luid *LUID) (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 adjustTokenPrivileges(token syscall.Token, disableAllPrivileges bool, newstate *TOKEN_PRIVILEGES, buflen uint32, prevstate *TOKEN_PRIVILEGES, returnlen *uint32) (ret uint32, err error) {
|
||||||
|
var _p0 uint32
|
||||||
|
if disableAllPrivileges {
|
||||||
|
_p0 = 1
|
||||||
|
} else {
|
||||||
|
_p0 = 0
|
||||||
|
}
|
||||||
|
r0, _, e1 := syscall.Syscall6(procAdjustTokenPrivileges.Addr(), 6, uintptr(token), uintptr(_p0), uintptr(unsafe.Pointer(newstate)), uintptr(buflen), uintptr(unsafe.Pointer(prevstate)), uintptr(unsafe.Pointer(returnlen)))
|
||||||
|
ret = uint32(r0)
|
||||||
|
if true {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DuplicateTokenEx(hExistingToken syscall.Token, dwDesiredAccess uint32, lpTokenAttributes *syscall.SecurityAttributes, impersonationLevel uint32, tokenType TokenType, phNewToken *syscall.Token) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procDuplicateTokenEx.Addr(), 6, uintptr(hExistingToken), uintptr(dwDesiredAccess), uintptr(unsafe.Pointer(lpTokenAttributes)), uintptr(impersonationLevel), uintptr(tokenType), uintptr(unsafe.Pointer(phNewToken)))
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32, tokenInformation uintptr, tokenInformationLength uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procSetTokenInformation.Addr(), 4, uintptr(tokenHandle), uintptr(tokenInformationClass), uintptr(tokenInformation), uintptr(tokenInformationLength), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProfilesDirectory(dir *uint16, dirLen *uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procGetProfilesDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(unsafe.Pointer(dirLen)), 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func NetUserGetLocalGroups(serverName *uint16, userName *uint16, level uint32, flags uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32) (neterr error) {
|
||||||
|
r0, _, _ := syscall.Syscall9(procNetUserGetLocalGroups.Addr(), 8, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(flags), uintptr(unsafe.Pointer(buf)), uintptr(prefMaxLen), uintptr(unsafe.Pointer(entriesRead)), uintptr(unsafe.Pointer(totalEntries)), 0)
|
||||||
|
if r0 != 0 {
|
||||||
|
neterr = syscall.Errno(r0)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetProcessMemoryInfo(handle syscall.Handle, memCounters *PROCESS_MEMORY_COUNTERS, cb uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall(procGetProcessMemoryInfo.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(memCounters)), uintptr(cb))
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFileInformationByHandleEx(handle syscall.Handle, class uint32, info *byte, bufsize uint32) (err error) {
|
||||||
|
r1, _, e1 := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(), 4, uintptr(handle), uintptr(class), uintptr(unsafe.Pointer(info)), uintptr(bufsize), 0, 0)
|
||||||
|
if r1 == 0 {
|
||||||
|
if e1 != 0 {
|
||||||
|
err = errnoErr(e1)
|
||||||
|
} else {
|
||||||
|
err = syscall.EINVAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
98
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock.go
generated
vendored
Normal file
98
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package filelock provides a platform-independent API for advisory file
|
||||||
|
// locking. Calls to functions in this package on platforms that do not support
|
||||||
|
// advisory locks will return errors for which IsNotSupported returns true.
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A File provides the minimal set of methods required to lock an open file.
|
||||||
|
// File implementations must be usable as map keys.
|
||||||
|
// The usual implementation is *os.File.
|
||||||
|
type File interface {
|
||||||
|
// Name returns the name of the file.
|
||||||
|
Name() string
|
||||||
|
|
||||||
|
// Fd returns a valid file descriptor.
|
||||||
|
// (If the File is an *os.File, it must not be closed.)
|
||||||
|
Fd() uintptr
|
||||||
|
|
||||||
|
// Stat returns the FileInfo structure describing file.
|
||||||
|
Stat() (os.FileInfo, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock places an advisory write lock on the file, blocking until it can be
|
||||||
|
// locked.
|
||||||
|
//
|
||||||
|
// If Lock returns nil, no other process will be able to place a read or write
|
||||||
|
// lock on the file until this process exits, closes f, or calls Unlock on it.
|
||||||
|
//
|
||||||
|
// If f's descriptor is already read- or write-locked, the behavior of Lock is
|
||||||
|
// unspecified.
|
||||||
|
//
|
||||||
|
// Closing the file may or may not release the lock promptly. Callers should
|
||||||
|
// ensure that Unlock is always called when Lock succeeds.
|
||||||
|
func Lock(f File) error {
|
||||||
|
return lock(f, writeLock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RLock places an advisory read lock on the file, blocking until it can be locked.
|
||||||
|
//
|
||||||
|
// If RLock returns nil, no other process will be able to place a write lock on
|
||||||
|
// the file until this process exits, closes f, or calls Unlock on it.
|
||||||
|
//
|
||||||
|
// If f is already read- or write-locked, the behavior of RLock is unspecified.
|
||||||
|
//
|
||||||
|
// Closing the file may or may not release the lock promptly. Callers should
|
||||||
|
// ensure that Unlock is always called if RLock succeeds.
|
||||||
|
func RLock(f File) error {
|
||||||
|
return lock(f, readLock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock removes an advisory lock placed on f by this process.
|
||||||
|
//
|
||||||
|
// The caller must not attempt to unlock a file that is not locked.
|
||||||
|
func Unlock(f File) error {
|
||||||
|
return unlock(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the name of the function corresponding to lt
|
||||||
|
// (Lock, RLock, or Unlock).
|
||||||
|
func (lt lockType) String() string {
|
||||||
|
switch lt {
|
||||||
|
case readLock:
|
||||||
|
return "RLock"
|
||||||
|
case writeLock:
|
||||||
|
return "Lock"
|
||||||
|
default:
|
||||||
|
return "Unlock"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotSupported returns a boolean indicating whether the error is known to
|
||||||
|
// report that a function is not supported (possibly for a specific input).
|
||||||
|
// It is satisfied by ErrNotSupported as well as some syscall errors.
|
||||||
|
func IsNotSupported(err error) bool {
|
||||||
|
return isNotSupported(underlyingError(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
var ErrNotSupported = errors.New("operation not supported")
|
||||||
|
|
||||||
|
// underlyingError returns the underlying error for known os error types.
|
||||||
|
func underlyingError(err error) error {
|
||||||
|
switch err := err.(type) {
|
||||||
|
case *os.PathError:
|
||||||
|
return err.Err
|
||||||
|
case *os.LinkError:
|
||||||
|
return err.Err
|
||||||
|
case *os.SyscallError:
|
||||||
|
return err.Err
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
219
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_fcntl.go
generated
vendored
Normal file
219
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_fcntl.go
generated
vendored
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build aix solaris
|
||||||
|
|
||||||
|
// This code implements the filelock API using POSIX 'fcntl' locks, which attach
|
||||||
|
// to an (inode, process) pair rather than a file descriptor. To avoid unlocking
|
||||||
|
// files prematurely when the same file is opened through different descriptors,
|
||||||
|
// we allow only one read-lock at a time.
|
||||||
|
//
|
||||||
|
// Most platforms provide some alternative API, such as an 'flock' system call
|
||||||
|
// or an F_OFD_SETLK command for 'fcntl', that allows for better concurrency and
|
||||||
|
// does not require per-inode bookkeeping in the application.
|
||||||
|
//
|
||||||
|
// TODO(golang.org/issue/35618): add a syscall.Flock binding for Illumos and
|
||||||
|
// switch it over to use filelock_unix.go.
|
||||||
|
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lockType int16
|
||||||
|
|
||||||
|
const (
|
||||||
|
readLock lockType = syscall.F_RDLCK
|
||||||
|
writeLock lockType = syscall.F_WRLCK
|
||||||
|
)
|
||||||
|
|
||||||
|
type inode = uint64 // type of syscall.Stat_t.Ino
|
||||||
|
|
||||||
|
type inodeLock struct {
|
||||||
|
owner File
|
||||||
|
queue []<-chan File
|
||||||
|
}
|
||||||
|
|
||||||
|
type token struct{}
|
||||||
|
|
||||||
|
var (
|
||||||
|
mu sync.Mutex
|
||||||
|
inodes = map[File]inode{}
|
||||||
|
locks = map[inode]inodeLock{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(f File, lt lockType) (err error) {
|
||||||
|
// POSIX locks apply per inode and process, and the lock for an inode is
|
||||||
|
// released when *any* descriptor for that inode is closed. So we need to
|
||||||
|
// synchronize access to each inode internally, and must serialize lock and
|
||||||
|
// unlock calls that refer to the same inode through different descriptors.
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ino := fi.Sys().(*syscall.Stat_t).Ino
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
if i, dup := inodes[f]; dup && i != ino {
|
||||||
|
mu.Unlock()
|
||||||
|
return &os.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: errors.New("inode for file changed since last Lock or RLock"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inodes[f] = ino
|
||||||
|
|
||||||
|
var wait chan File
|
||||||
|
l := locks[ino]
|
||||||
|
if l.owner == f {
|
||||||
|
// This file already owns the lock, but the call may change its lock type.
|
||||||
|
} else if l.owner == nil {
|
||||||
|
// No owner: it's ours now.
|
||||||
|
l.owner = f
|
||||||
|
} else {
|
||||||
|
// Already owned: add a channel to wait on.
|
||||||
|
wait = make(chan File)
|
||||||
|
l.queue = append(l.queue, wait)
|
||||||
|
}
|
||||||
|
locks[ino] = l
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
if wait != nil {
|
||||||
|
wait <- f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spurious EDEADLK errors arise on platforms that compute deadlock graphs at
|
||||||
|
// the process, rather than thread, level. Consider processes P and Q, with
|
||||||
|
// threads P.1, P.2, and Q.3. The following trace is NOT a deadlock, but will be
|
||||||
|
// reported as a deadlock on systems that consider only process granularity:
|
||||||
|
//
|
||||||
|
// P.1 locks file A.
|
||||||
|
// Q.3 locks file B.
|
||||||
|
// Q.3 blocks on file A.
|
||||||
|
// P.2 blocks on file B. (This is erroneously reported as a deadlock.)
|
||||||
|
// P.1 unlocks file A.
|
||||||
|
// Q.3 unblocks and locks file A.
|
||||||
|
// Q.3 unlocks files A and B.
|
||||||
|
// P.2 unblocks and locks file B.
|
||||||
|
// P.2 unlocks file B.
|
||||||
|
//
|
||||||
|
// These spurious errors were observed in practice on AIX and Solaris in
|
||||||
|
// cmd/go: see https://golang.org/issue/32817.
|
||||||
|
//
|
||||||
|
// We work around this bug by treating EDEADLK as always spurious. If there
|
||||||
|
// really is a lock-ordering bug between the interacting processes, it will
|
||||||
|
// become a livelock instead, but that's not appreciably worse than if we had
|
||||||
|
// a proper flock implementation (which generally does not even attempt to
|
||||||
|
// diagnose deadlocks).
|
||||||
|
//
|
||||||
|
// In the above example, that changes the trace to:
|
||||||
|
//
|
||||||
|
// P.1 locks file A.
|
||||||
|
// Q.3 locks file B.
|
||||||
|
// Q.3 blocks on file A.
|
||||||
|
// P.2 spuriously fails to lock file B and goes to sleep.
|
||||||
|
// P.1 unlocks file A.
|
||||||
|
// Q.3 unblocks and locks file A.
|
||||||
|
// Q.3 unlocks files A and B.
|
||||||
|
// P.2 wakes up and locks file B.
|
||||||
|
// P.2 unlocks file B.
|
||||||
|
//
|
||||||
|
// We know that the retry loop will not introduce a *spurious* livelock
|
||||||
|
// because, according to the POSIX specification, EDEADLK is only to be
|
||||||
|
// returned when “the lock is blocked by a lock from another process”.
|
||||||
|
// If that process is blocked on some lock that we are holding, then the
|
||||||
|
// resulting livelock is due to a real deadlock (and would manifest as such
|
||||||
|
// when using, for example, the flock implementation of this package).
|
||||||
|
// If the other process is *not* blocked on some other lock that we are
|
||||||
|
// holding, then it will eventually release the requested lock.
|
||||||
|
|
||||||
|
nextSleep := 1 * time.Millisecond
|
||||||
|
const maxSleep = 500 * time.Millisecond
|
||||||
|
for {
|
||||||
|
err = setlkw(f.Fd(), lt)
|
||||||
|
if err != syscall.EDEADLK {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(nextSleep)
|
||||||
|
|
||||||
|
nextSleep += nextSleep
|
||||||
|
if nextSleep > maxSleep {
|
||||||
|
nextSleep = maxSleep
|
||||||
|
}
|
||||||
|
// Apply 10% jitter to avoid synchronizing collisions when we finally unblock.
|
||||||
|
nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
unlock(f)
|
||||||
|
return &os.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(f File) error {
|
||||||
|
var owner File
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
ino, ok := inodes[f]
|
||||||
|
if ok {
|
||||||
|
owner = locks[ino].owner
|
||||||
|
}
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
if owner != f {
|
||||||
|
panic("unlock called on a file that is not locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := setlkw(f.Fd(), syscall.F_UNLCK)
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
l := locks[ino]
|
||||||
|
if len(l.queue) == 0 {
|
||||||
|
// No waiters: remove the map entry.
|
||||||
|
delete(locks, ino)
|
||||||
|
} else {
|
||||||
|
// The first waiter is sending us their file now.
|
||||||
|
// Receive it and update the queue.
|
||||||
|
l.owner = <-l.queue[0]
|
||||||
|
l.queue = l.queue[1:]
|
||||||
|
locks[ino] = l
|
||||||
|
}
|
||||||
|
delete(inodes, f)
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// setlkw calls FcntlFlock with F_SETLKW for the entire file indicated by fd.
|
||||||
|
func setlkw(fd uintptr, lt lockType) error {
|
||||||
|
for {
|
||||||
|
err := syscall.FcntlFlock(fd, syscall.F_SETLKW, &syscall.Flock_t{
|
||||||
|
Type: int16(lt),
|
||||||
|
Whence: io.SeekStart,
|
||||||
|
Start: 0,
|
||||||
|
Len: 0, // All bytes.
|
||||||
|
})
|
||||||
|
if err != syscall.EINTR {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNotSupported(err error) bool {
|
||||||
|
return err == syscall.ENOSYS || err == syscall.ENOTSUP || err == syscall.EOPNOTSUPP || err == ErrNotSupported
|
||||||
|
}
|
36
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_other.go
generated
vendored
Normal file
36
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_other.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!plan9,!solaris,!windows
|
||||||
|
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
type lockType int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
readLock = iota + 1
|
||||||
|
writeLock
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(f File, lt lockType) error {
|
||||||
|
return &os.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: ErrNotSupported,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(f File) error {
|
||||||
|
return &os.PathError{
|
||||||
|
Op: "Unlock",
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: ErrNotSupported,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNotSupported(err error) bool {
|
||||||
|
return err == ErrNotSupported
|
||||||
|
}
|
38
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_plan9.go
generated
vendored
Normal file
38
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_plan9.go
generated
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build plan9
|
||||||
|
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lockType int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
readLock = iota + 1
|
||||||
|
writeLock
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(f File, lt lockType) error {
|
||||||
|
return &os.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: ErrNotSupported,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(f File) error {
|
||||||
|
return &os.PathError{
|
||||||
|
Op: "Unlock",
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: ErrNotSupported,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNotSupported(err error) bool {
|
||||||
|
return err == ErrNotSupported
|
||||||
|
}
|
44
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_unix.go
generated
vendored
Normal file
44
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_unix.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build darwin dragonfly freebsd linux netbsd openbsd
|
||||||
|
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lockType int16
|
||||||
|
|
||||||
|
const (
|
||||||
|
readLock lockType = syscall.LOCK_SH
|
||||||
|
writeLock lockType = syscall.LOCK_EX
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(f File, lt lockType) (err error) {
|
||||||
|
for {
|
||||||
|
err = syscall.Flock(int(f.Fd()), int(lt))
|
||||||
|
if err != syscall.EINTR {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return &os.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(f File) error {
|
||||||
|
return lock(f, syscall.LOCK_UN)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNotSupported(err error) bool {
|
||||||
|
return err == syscall.ENOSYS || err == syscall.ENOTSUP || err == syscall.EOPNOTSUPP || err == ErrNotSupported
|
||||||
|
}
|
67
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_windows.go
generated
vendored
Normal file
67
vendor/github.com/rogpeppe/go-internal/lockedfile/internal/filelock/filelock_windows.go
generated
vendored
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build windows
|
||||||
|
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/rogpeppe/go-internal/internal/syscall/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lockType uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
readLock lockType = 0
|
||||||
|
writeLock lockType = windows.LOCKFILE_EXCLUSIVE_LOCK
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
reserved = 0
|
||||||
|
allBytes = ^uint32(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(f File, lt lockType) error {
|
||||||
|
// Per https://golang.org/issue/19098, “Programs currently expect the Fd
|
||||||
|
// method to return a handle that uses ordinary synchronous I/O.”
|
||||||
|
// However, LockFileEx still requires an OVERLAPPED structure,
|
||||||
|
// which contains the file offset of the beginning of the lock range.
|
||||||
|
// We want to lock the entire file, so we leave the offset as zero.
|
||||||
|
ol := new(syscall.Overlapped)
|
||||||
|
|
||||||
|
err := windows.LockFileEx(syscall.Handle(f.Fd()), uint32(lt), reserved, allBytes, allBytes, ol)
|
||||||
|
if err != nil {
|
||||||
|
return &os.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(f File) error {
|
||||||
|
ol := new(syscall.Overlapped)
|
||||||
|
err := windows.UnlockFileEx(syscall.Handle(f.Fd()), reserved, allBytes, allBytes, ol)
|
||||||
|
if err != nil {
|
||||||
|
return &os.PathError{
|
||||||
|
Op: "Unlock",
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNotSupported(err error) bool {
|
||||||
|
switch err {
|
||||||
|
case windows.ERROR_NOT_SUPPORTED, windows.ERROR_CALL_NOT_IMPLEMENTED, ErrNotSupported:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
122
vendor/github.com/rogpeppe/go-internal/lockedfile/lockedfile.go
generated
vendored
Normal file
122
vendor/github.com/rogpeppe/go-internal/lockedfile/lockedfile.go
generated
vendored
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package lockedfile creates and manipulates files whose contents should only
|
||||||
|
// change atomically.
|
||||||
|
package lockedfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A File is a locked *os.File.
|
||||||
|
//
|
||||||
|
// Closing the file releases the lock.
|
||||||
|
//
|
||||||
|
// If the program exits while a file is locked, the operating system releases
|
||||||
|
// the lock but may not do so promptly: callers must ensure that all locked
|
||||||
|
// files are closed before exiting.
|
||||||
|
type File struct {
|
||||||
|
osFile
|
||||||
|
closed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// osFile embeds a *os.File while keeping the pointer itself unexported.
|
||||||
|
// (When we close a File, it must be the same file descriptor that we opened!)
|
||||||
|
type osFile struct {
|
||||||
|
*os.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenFile is like os.OpenFile, but returns a locked file.
|
||||||
|
// If flag includes os.O_WRONLY or os.O_RDWR, the file is write-locked;
|
||||||
|
// otherwise, it is read-locked.
|
||||||
|
func OpenFile(name string, flag int, perm os.FileMode) (*File, error) {
|
||||||
|
var (
|
||||||
|
f = new(File)
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
f.osFile.File, err = openFile(name, flag, perm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Although the operating system will drop locks for open files when the go
|
||||||
|
// command exits, we want to hold locks for as little time as possible, and we
|
||||||
|
// especially don't want to leave a file locked after we're done with it. Our
|
||||||
|
// Close method is what releases the locks, so use a finalizer to report
|
||||||
|
// missing Close calls on a best-effort basis.
|
||||||
|
runtime.SetFinalizer(f, func(f *File) {
|
||||||
|
panic(fmt.Sprintf("lockedfile.File %s became unreachable without a call to Close", f.Name()))
|
||||||
|
})
|
||||||
|
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open is like os.Open, but returns a read-locked file.
|
||||||
|
func Open(name string) (*File, error) {
|
||||||
|
return OpenFile(name, os.O_RDONLY, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create is like os.Create, but returns a write-locked file.
|
||||||
|
func Create(name string) (*File, error) {
|
||||||
|
return OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Edit creates the named file with mode 0666 (before umask),
|
||||||
|
// but does not truncate existing contents.
|
||||||
|
//
|
||||||
|
// If Edit succeeds, methods on the returned File can be used for I/O.
|
||||||
|
// The associated file descriptor has mode O_RDWR and the file is write-locked.
|
||||||
|
func Edit(name string) (*File, error) {
|
||||||
|
return OpenFile(name, os.O_RDWR|os.O_CREATE, 0666)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close unlocks and closes the underlying file.
|
||||||
|
//
|
||||||
|
// Close may be called multiple times; all calls after the first will return a
|
||||||
|
// non-nil error.
|
||||||
|
func (f *File) Close() error {
|
||||||
|
if f.closed {
|
||||||
|
return &os.PathError{
|
||||||
|
Op: "close",
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: os.ErrClosed,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.closed = true
|
||||||
|
|
||||||
|
err := closeFile(f.osFile.File)
|
||||||
|
runtime.SetFinalizer(f, nil)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read opens the named file with a read-lock and returns its contents.
|
||||||
|
func Read(name string) ([]byte, error) {
|
||||||
|
f, err := Open(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
return ioutil.ReadAll(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write opens the named file (creating it with the given permissions if needed),
|
||||||
|
// then write-locks it and overwrites it with the given content.
|
||||||
|
func Write(name string, content io.Reader, perm os.FileMode) (err error) {
|
||||||
|
f, err := OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = io.Copy(f, content)
|
||||||
|
if closeErr := f.Close(); err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
64
vendor/github.com/rogpeppe/go-internal/lockedfile/lockedfile_filelock.go
generated
vendored
Normal file
64
vendor/github.com/rogpeppe/go-internal/lockedfile/lockedfile_filelock.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !plan9
|
||||||
|
|
||||||
|
package lockedfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/rogpeppe/go-internal/lockedfile/internal/filelock"
|
||||||
|
)
|
||||||
|
|
||||||
|
func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
||||||
|
// On BSD systems, we could add the O_SHLOCK or O_EXLOCK flag to the OpenFile
|
||||||
|
// call instead of locking separately, but we have to support separate locking
|
||||||
|
// calls for Linux and Windows anyway, so it's simpler to use that approach
|
||||||
|
// consistently.
|
||||||
|
|
||||||
|
f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch flag & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR) {
|
||||||
|
case os.O_WRONLY, os.O_RDWR:
|
||||||
|
err = filelock.Lock(f)
|
||||||
|
default:
|
||||||
|
err = filelock.RLock(f)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
f.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if flag&os.O_TRUNC == os.O_TRUNC {
|
||||||
|
if err := f.Truncate(0); err != nil {
|
||||||
|
// The documentation for os.O_TRUNC says “if possible, truncate file when
|
||||||
|
// opened”, but doesn't define “possible” (golang.org/issue/28699).
|
||||||
|
// We'll treat regular files (and symlinks to regular files) as “possible”
|
||||||
|
// and ignore errors for the rest.
|
||||||
|
if fi, statErr := f.Stat(); statErr != nil || fi.Mode().IsRegular() {
|
||||||
|
filelock.Unlock(f)
|
||||||
|
f.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeFile(f *os.File) error {
|
||||||
|
// Since locking syscalls operate on file descriptors, we must unlock the file
|
||||||
|
// while the descriptor is still valid — that is, before the file is closed —
|
||||||
|
// and avoid unlocking files that are already closed.
|
||||||
|
err := filelock.Unlock(f)
|
||||||
|
|
||||||
|
if closeErr := f.Close(); err == nil {
|
||||||
|
err = closeErr
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
93
vendor/github.com/rogpeppe/go-internal/lockedfile/lockedfile_plan9.go
generated
vendored
Normal file
93
vendor/github.com/rogpeppe/go-internal/lockedfile/lockedfile_plan9.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build plan9
|
||||||
|
|
||||||
|
package lockedfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Opening an exclusive-use file returns an error.
|
||||||
|
// The expected error strings are:
|
||||||
|
//
|
||||||
|
// - "open/create -- file is locked" (cwfs, kfs)
|
||||||
|
// - "exclusive lock" (fossil)
|
||||||
|
// - "exclusive use file already open" (ramfs)
|
||||||
|
var lockedErrStrings = [...]string{
|
||||||
|
"file is locked",
|
||||||
|
"exclusive lock",
|
||||||
|
"exclusive use file already open",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Even though plan9 doesn't support the Lock/RLock/Unlock functions to
|
||||||
|
// manipulate already-open files, IsLocked is still meaningful: os.OpenFile
|
||||||
|
// itself may return errors that indicate that a file with the ModeExclusive bit
|
||||||
|
// set is already open.
|
||||||
|
func isLocked(err error) bool {
|
||||||
|
s := err.Error()
|
||||||
|
|
||||||
|
for _, frag := range lockedErrStrings {
|
||||||
|
if strings.Contains(s, frag) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func openFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
||||||
|
// Plan 9 uses a mode bit instead of explicit lock/unlock syscalls.
|
||||||
|
//
|
||||||
|
// Per http://man.cat-v.org/plan_9/5/stat: “Exclusive use files may be open
|
||||||
|
// for I/O by only one fid at a time across all clients of the server. If a
|
||||||
|
// second open is attempted, it draws an error.”
|
||||||
|
//
|
||||||
|
// So we can try to open a locked file, but if it fails we're on our own to
|
||||||
|
// figure out when it becomes available. We'll use exponential backoff with
|
||||||
|
// some jitter and an arbitrary limit of 500ms.
|
||||||
|
|
||||||
|
// If the file was unpacked or created by some other program, it might not
|
||||||
|
// have the ModeExclusive bit set. Set it before we call OpenFile, so that we
|
||||||
|
// can be confident that a successful OpenFile implies exclusive use.
|
||||||
|
if fi, err := os.Stat(name); err == nil {
|
||||||
|
if fi.Mode()&os.ModeExclusive == 0 {
|
||||||
|
if err := os.Chmod(name, fi.Mode()|os.ModeExclusive); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if !os.IsNotExist(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nextSleep := 1 * time.Millisecond
|
||||||
|
const maxSleep = 500 * time.Millisecond
|
||||||
|
for {
|
||||||
|
f, err := os.OpenFile(name, flag, perm|os.ModeExclusive)
|
||||||
|
if err == nil {
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isLocked(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(nextSleep)
|
||||||
|
|
||||||
|
nextSleep += nextSleep
|
||||||
|
if nextSleep > maxSleep {
|
||||||
|
nextSleep = maxSleep
|
||||||
|
}
|
||||||
|
// Apply 10% jitter to avoid synchronizing collisions.
|
||||||
|
nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func closeFile(f *os.File) error {
|
||||||
|
return f.Close()
|
||||||
|
}
|
60
vendor/github.com/rogpeppe/go-internal/lockedfile/mutex.go
generated
vendored
Normal file
60
vendor/github.com/rogpeppe/go-internal/lockedfile/mutex.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package lockedfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Mutex provides mutual exclusion within and across processes by locking a
|
||||||
|
// well-known file. Such a file generally guards some other part of the
|
||||||
|
// filesystem: for example, a Mutex file in a directory might guard access to
|
||||||
|
// the entire tree rooted in that directory.
|
||||||
|
//
|
||||||
|
// Mutex does not implement sync.Locker: unlike a sync.Mutex, a lockedfile.Mutex
|
||||||
|
// can fail to lock (e.g. if there is a permission error in the filesystem).
|
||||||
|
//
|
||||||
|
// Like a sync.Mutex, a Mutex may be included as a field of a larger struct but
|
||||||
|
// must not be copied after first use. The Path field must be set before first
|
||||||
|
// use and must not be change thereafter.
|
||||||
|
type Mutex struct {
|
||||||
|
Path string // The path to the well-known lock file. Must be non-empty.
|
||||||
|
}
|
||||||
|
|
||||||
|
// MutexAt returns a new Mutex with Path set to the given non-empty path.
|
||||||
|
func MutexAt(path string) *Mutex {
|
||||||
|
if path == "" {
|
||||||
|
panic("lockedfile.MutexAt: path must be non-empty")
|
||||||
|
}
|
||||||
|
return &Mutex{Path: path}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mu *Mutex) String() string {
|
||||||
|
return fmt.Sprintf("lockedfile.Mutex(%s)", mu.Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock attempts to lock the Mutex.
|
||||||
|
//
|
||||||
|
// If successful, Lock returns a non-nil unlock function: it is provided as a
|
||||||
|
// return-value instead of a separate method to remind the caller to check the
|
||||||
|
// accompanying error. (See https://golang.org/issue/20803.)
|
||||||
|
func (mu *Mutex) Lock() (unlock func(), err error) {
|
||||||
|
if mu.Path == "" {
|
||||||
|
panic("lockedfile.Mutex: missing Path during Lock")
|
||||||
|
}
|
||||||
|
|
||||||
|
// We could use either O_RDWR or O_WRONLY here. If we choose O_RDWR and the
|
||||||
|
// file at mu.Path is write-only, the call to OpenFile will fail with a
|
||||||
|
// permission error. That's actually what we want: if we add an RLock method
|
||||||
|
// in the future, it should call OpenFile with O_RDONLY and will require the
|
||||||
|
// files must be readable, so we should not let the caller make any
|
||||||
|
// assumptions about Mutex working with write-only files.
|
||||||
|
f, err := OpenFile(mu.Path, os.O_RDWR|os.O_CREATE, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return func() { f.Close() }, nil
|
||||||
|
}
|
8
vendor/modules.txt
vendored
8
vendor/modules.txt
vendored
@ -458,6 +458,14 @@ github.com/prometheus/common/model
|
|||||||
github.com/prometheus/procfs
|
github.com/prometheus/procfs
|
||||||
github.com/prometheus/procfs/internal/fs
|
github.com/prometheus/procfs/internal/fs
|
||||||
github.com/prometheus/procfs/internal/util
|
github.com/prometheus/procfs/internal/util
|
||||||
|
# github.com/rancher-sandbox/gofilecache v0.0.0-20210330135715-becdeff5df15
|
||||||
|
## explicit
|
||||||
|
github.com/rancher-sandbox/gofilecache
|
||||||
|
# github.com/rogpeppe/go-internal v1.8.0
|
||||||
|
github.com/rogpeppe/go-internal/internal/syscall/windows
|
||||||
|
github.com/rogpeppe/go-internal/internal/syscall/windows/sysdll
|
||||||
|
github.com/rogpeppe/go-internal/lockedfile
|
||||||
|
github.com/rogpeppe/go-internal/lockedfile/internal/filelock
|
||||||
# github.com/rootless-containers/proto v0.1.0
|
# github.com/rootless-containers/proto v0.1.0
|
||||||
github.com/rootless-containers/proto/go-proto
|
github.com/rootless-containers/proto/go-proto
|
||||||
# github.com/russross/blackfriday/v2 v2.1.0
|
# github.com/russross/blackfriday/v2 v2.1.0
|
||||||
|
Loading…
Reference in New Issue
Block a user