mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Bump docker commit
Signed-off-by: Brian Goff <cpuguy83@gmail.com> (cherry picked from commit aae1b0e116d0c4ee0e46494864d1540fec22ced3) Signed-off-by: selansen <elango.siva@docker.com>
This commit is contained in:
parent
28ec64d2e5
commit
e07681c8ca
9 changed files with 769 additions and 4 deletions
|
@ -10,6 +10,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/docker/docker/pkg/plugins"
|
"github.com/docker/docker/pkg/plugins"
|
||||||
"github.com/docker/docker/pkg/reexec"
|
"github.com/docker/docker/pkg/reexec"
|
||||||
"github.com/docker/libnetwork"
|
"github.com/docker/libnetwork"
|
||||||
|
@ -209,7 +210,7 @@ func TestUnknownDriver(t *testing.T) {
|
||||||
t.Fatal("Expected to fail. But instead succeeded")
|
t.Fatal("Expected to fail. But instead succeeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := err.(types.NotFoundError); !ok {
|
if errdefs.IsNotFound(err) {
|
||||||
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -221,7 +222,7 @@ func TestNilRemoteDriver(t *testing.T) {
|
||||||
t.Fatal("Expected to fail. But instead succeeded")
|
t.Fatal("Expected to fail. But instead succeeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := err.(types.NotFoundError); !ok {
|
if !errdefs.IsNotFound(err) {
|
||||||
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
t.Fatalf("Did not fail with expected error. Actual error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1396,7 +1397,7 @@ func TestValidRemoteDriver(t *testing.T) {
|
||||||
libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
|
libnetwork.NetworkOptionGeneric(getEmptyGenericOption()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Only fail if we could not find the plugin driver
|
// Only fail if we could not find the plugin driver
|
||||||
if _, ok := err.(types.NotFoundError); ok {
|
if errdefs.IsNotFound(err) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
@ -14,8 +14,8 @@ github.com/coreos/go-systemd v17
|
||||||
github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
|
github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
|
||||||
github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
|
github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
|
||||||
|
|
||||||
github.com/docker/docker 162ba6016def672690ee4a1f3978368853a1e149
|
|
||||||
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
|
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
|
||||||
|
github.com/docker/docker 71cd53e4a197b303c6ba086bd584ffd67a884281
|
||||||
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||||
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
|
||||||
github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
|
github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
|
||||||
|
|
74
libnetwork/vendor/github.com/docker/docker/errdefs/defs.go
generated
vendored
Normal file
74
libnetwork/vendor/github.com/docker/docker/errdefs/defs.go
generated
vendored
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
package errdefs // import "github.com/docker/docker/errdefs"
|
||||||
|
|
||||||
|
// ErrNotFound signals that the requested object doesn't exist
|
||||||
|
type ErrNotFound interface {
|
||||||
|
NotFound()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrInvalidParameter signals that the user input is invalid
|
||||||
|
type ErrInvalidParameter interface {
|
||||||
|
InvalidParameter()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrConflict signals that some internal state conflicts with the requested action and can't be performed.
|
||||||
|
// A change in state should be able to clear this error.
|
||||||
|
type ErrConflict interface {
|
||||||
|
Conflict()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnauthorized is used to signify that the user is not authorized to perform a specific action
|
||||||
|
type ErrUnauthorized interface {
|
||||||
|
Unauthorized()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnavailable signals that the requested action/subsystem is not available.
|
||||||
|
type ErrUnavailable interface {
|
||||||
|
Unavailable()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrForbidden signals that the requested action cannot be performed under any circumstances.
|
||||||
|
// When a ErrForbidden is returned, the caller should never retry the action.
|
||||||
|
type ErrForbidden interface {
|
||||||
|
Forbidden()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrSystem signals that some internal error occurred.
|
||||||
|
// An example of this would be a failed mount request.
|
||||||
|
type ErrSystem interface {
|
||||||
|
System()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNotModified signals that an action can't be performed because it's already in the desired state
|
||||||
|
type ErrNotModified interface {
|
||||||
|
NotModified()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrAlreadyExists is a special case of ErrConflict which signals that the desired object already exists
|
||||||
|
type ErrAlreadyExists interface {
|
||||||
|
AlreadyExists()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNotImplemented signals that the requested action/feature is not implemented on the system as configured.
|
||||||
|
type ErrNotImplemented interface {
|
||||||
|
NotImplemented()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUnknown signals that the kind of error that occurred is not known.
|
||||||
|
type ErrUnknown interface {
|
||||||
|
Unknown()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrCancelled signals that the action was cancelled.
|
||||||
|
type ErrCancelled interface {
|
||||||
|
Cancelled()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDeadline signals that the deadline was reached before the action completed.
|
||||||
|
type ErrDeadline interface {
|
||||||
|
DeadlineExceeded()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrDataLoss indicates that data was lost or there is data corruption.
|
||||||
|
type ErrDataLoss interface {
|
||||||
|
DataLoss()
|
||||||
|
}
|
8
libnetwork/vendor/github.com/docker/docker/errdefs/doc.go
generated
vendored
Normal file
8
libnetwork/vendor/github.com/docker/docker/errdefs/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
// Package errdefs defines a set of error interfaces that packages should use for communicating classes of errors.
|
||||||
|
// Errors that cross the package boundary should implement one (and only one) of these interfaces.
|
||||||
|
//
|
||||||
|
// Packages should not reference these interfaces directly, only implement them.
|
||||||
|
// To check if a particular error implements one of these interfaces, there are helper
|
||||||
|
// functions provided (e.g. `Is<SomeError>`) which can be used rather than asserting the interfaces directly.
|
||||||
|
// If you must assert on these interfaces, be sure to check the causal chain (`err.Cause()`).
|
||||||
|
package errdefs // import "github.com/docker/docker/errdefs"
|
240
libnetwork/vendor/github.com/docker/docker/errdefs/helpers.go
generated
vendored
Normal file
240
libnetwork/vendor/github.com/docker/docker/errdefs/helpers.go
generated
vendored
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
package errdefs // import "github.com/docker/docker/errdefs"
|
||||||
|
|
||||||
|
import "context"
|
||||||
|
|
||||||
|
type errNotFound struct{ error }
|
||||||
|
|
||||||
|
func (errNotFound) NotFound() {}
|
||||||
|
|
||||||
|
func (e errNotFound) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotFound is a helper to create an error of the class with the same name from any error type
|
||||||
|
func NotFound(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errNotFound{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errInvalidParameter struct{ error }
|
||||||
|
|
||||||
|
func (errInvalidParameter) InvalidParameter() {}
|
||||||
|
|
||||||
|
func (e errInvalidParameter) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidParameter is a helper to create an error of the class with the same name from any error type
|
||||||
|
func InvalidParameter(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errInvalidParameter{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errConflict struct{ error }
|
||||||
|
|
||||||
|
func (errConflict) Conflict() {}
|
||||||
|
|
||||||
|
func (e errConflict) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conflict is a helper to create an error of the class with the same name from any error type
|
||||||
|
func Conflict(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errConflict{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errUnauthorized struct{ error }
|
||||||
|
|
||||||
|
func (errUnauthorized) Unauthorized() {}
|
||||||
|
|
||||||
|
func (e errUnauthorized) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unauthorized is a helper to create an error of the class with the same name from any error type
|
||||||
|
func Unauthorized(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errUnauthorized{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errUnavailable struct{ error }
|
||||||
|
|
||||||
|
func (errUnavailable) Unavailable() {}
|
||||||
|
|
||||||
|
func (e errUnavailable) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable is a helper to create an error of the class with the same name from any error type
|
||||||
|
func Unavailable(err error) error {
|
||||||
|
return errUnavailable{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errForbidden struct{ error }
|
||||||
|
|
||||||
|
func (errForbidden) Forbidden() {}
|
||||||
|
|
||||||
|
func (e errForbidden) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forbidden is a helper to create an error of the class with the same name from any error type
|
||||||
|
func Forbidden(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errForbidden{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errSystem struct{ error }
|
||||||
|
|
||||||
|
func (errSystem) System() {}
|
||||||
|
|
||||||
|
func (e errSystem) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// System is a helper to create an error of the class with the same name from any error type
|
||||||
|
func System(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errSystem{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errNotModified struct{ error }
|
||||||
|
|
||||||
|
func (errNotModified) NotModified() {}
|
||||||
|
|
||||||
|
func (e errNotModified) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotModified is a helper to create an error of the class with the same name from any error type
|
||||||
|
func NotModified(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errNotModified{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errAlreadyExists struct{ error }
|
||||||
|
|
||||||
|
func (errAlreadyExists) AlreadyExists() {}
|
||||||
|
|
||||||
|
func (e errAlreadyExists) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlreadyExists is a helper to create an error of the class with the same name from any error type
|
||||||
|
func AlreadyExists(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errAlreadyExists{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errNotImplemented struct{ error }
|
||||||
|
|
||||||
|
func (errNotImplemented) NotImplemented() {}
|
||||||
|
|
||||||
|
func (e errNotImplemented) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotImplemented is a helper to create an error of the class with the same name from any error type
|
||||||
|
func NotImplemented(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errNotImplemented{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errUnknown struct{ error }
|
||||||
|
|
||||||
|
func (errUnknown) Unknown() {}
|
||||||
|
|
||||||
|
func (e errUnknown) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown is a helper to create an error of the class with the same name from any error type
|
||||||
|
func Unknown(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errUnknown{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errCancelled struct{ error }
|
||||||
|
|
||||||
|
func (errCancelled) Cancelled() {}
|
||||||
|
|
||||||
|
func (e errCancelled) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancelled is a helper to create an error of the class with the same name from any error type
|
||||||
|
func Cancelled(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errCancelled{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errDeadline struct{ error }
|
||||||
|
|
||||||
|
func (errDeadline) DeadlineExceeded() {}
|
||||||
|
|
||||||
|
func (e errDeadline) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deadline is a helper to create an error of the class with the same name from any error type
|
||||||
|
func Deadline(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errDeadline{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
type errDataLoss struct{ error }
|
||||||
|
|
||||||
|
func (errDataLoss) DataLoss() {}
|
||||||
|
|
||||||
|
func (e errDataLoss) Cause() error {
|
||||||
|
return e.error
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataLoss is a helper to create an error of the class with the same name from any error type
|
||||||
|
func DataLoss(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errDataLoss{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromContext returns the error class from the passed in context
|
||||||
|
func FromContext(ctx context.Context) error {
|
||||||
|
e := ctx.Err()
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if e == context.Canceled {
|
||||||
|
return Cancelled(e)
|
||||||
|
}
|
||||||
|
if e == context.DeadlineExceeded {
|
||||||
|
return Deadline(e)
|
||||||
|
}
|
||||||
|
return Unknown(e)
|
||||||
|
}
|
114
libnetwork/vendor/github.com/docker/docker/errdefs/is.go
generated
vendored
Normal file
114
libnetwork/vendor/github.com/docker/docker/errdefs/is.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
package errdefs // import "github.com/docker/docker/errdefs"
|
||||||
|
|
||||||
|
type causer interface {
|
||||||
|
Cause() error
|
||||||
|
}
|
||||||
|
|
||||||
|
func getImplementer(err error) error {
|
||||||
|
switch e := err.(type) {
|
||||||
|
case
|
||||||
|
ErrNotFound,
|
||||||
|
ErrInvalidParameter,
|
||||||
|
ErrConflict,
|
||||||
|
ErrUnauthorized,
|
||||||
|
ErrUnavailable,
|
||||||
|
ErrForbidden,
|
||||||
|
ErrSystem,
|
||||||
|
ErrNotModified,
|
||||||
|
ErrAlreadyExists,
|
||||||
|
ErrNotImplemented,
|
||||||
|
ErrCancelled,
|
||||||
|
ErrDeadline,
|
||||||
|
ErrDataLoss,
|
||||||
|
ErrUnknown:
|
||||||
|
return err
|
||||||
|
case causer:
|
||||||
|
return getImplementer(e.Cause())
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotFound returns if the passed in error is an ErrNotFound
|
||||||
|
func IsNotFound(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrNotFound)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsInvalidParameter returns if the passed in error is an ErrInvalidParameter
|
||||||
|
func IsInvalidParameter(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrInvalidParameter)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsConflict returns if the passed in error is an ErrConflict
|
||||||
|
func IsConflict(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrConflict)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsUnauthorized returns if the passed in error is an ErrUnauthorized
|
||||||
|
func IsUnauthorized(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrUnauthorized)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsUnavailable returns if the passed in error is an ErrUnavailable
|
||||||
|
func IsUnavailable(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrUnavailable)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsForbidden returns if the passed in error is an ErrForbidden
|
||||||
|
func IsForbidden(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrForbidden)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSystem returns if the passed in error is an ErrSystem
|
||||||
|
func IsSystem(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrSystem)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotModified returns if the passed in error is a NotModified error
|
||||||
|
func IsNotModified(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrNotModified)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsAlreadyExists returns if the passed in error is a AlreadyExists error
|
||||||
|
func IsAlreadyExists(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrAlreadyExists)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotImplemented returns if the passed in error is an ErrNotImplemented
|
||||||
|
func IsNotImplemented(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrNotImplemented)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsUnknown returns if the passed in error is an ErrUnknown
|
||||||
|
func IsUnknown(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrUnknown)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCancelled returns if the passed in error is an ErrCancelled
|
||||||
|
func IsCancelled(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrCancelled)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDeadline returns if the passed in error is an ErrDeadline
|
||||||
|
func IsDeadline(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrDeadline)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsDataLoss returns if the passed in error is an ErrDataLoss
|
||||||
|
func IsDataLoss(err error) bool {
|
||||||
|
_, ok := getImplementer(err).(ErrDataLoss)
|
||||||
|
return ok
|
||||||
|
}
|
144
libnetwork/vendor/github.com/docker/docker/pkg/symlink/fs.go
generated
vendored
Normal file
144
libnetwork/vendor/github.com/docker/docker/pkg/symlink/fs.go
generated
vendored
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
// Copyright 2012 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.BSD file.
|
||||||
|
|
||||||
|
// This code is a modified version of path/filepath/symlink.go from the Go standard library.
|
||||||
|
|
||||||
|
package symlink // import "github.com/docker/docker/pkg/symlink"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FollowSymlinkInScope is a wrapper around evalSymlinksInScope that returns an
|
||||||
|
// absolute path. This function handles paths in a platform-agnostic manner.
|
||||||
|
func FollowSymlinkInScope(path, root string) (string, error) {
|
||||||
|
path, err := filepath.Abs(filepath.FromSlash(path))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
root, err = filepath.Abs(filepath.FromSlash(root))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return evalSymlinksInScope(path, root)
|
||||||
|
}
|
||||||
|
|
||||||
|
// evalSymlinksInScope will evaluate symlinks in `path` within a scope `root` and return
|
||||||
|
// a result guaranteed to be contained within the scope `root`, at the time of the call.
|
||||||
|
// Symlinks in `root` are not evaluated and left as-is.
|
||||||
|
// Errors encountered while attempting to evaluate symlinks in path will be returned.
|
||||||
|
// Non-existing paths are valid and do not constitute an error.
|
||||||
|
// `path` has to contain `root` as a prefix, or else an error will be returned.
|
||||||
|
// Trying to break out from `root` does not constitute an error.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// If /foo/bar -> /outside,
|
||||||
|
// FollowSymlinkInScope("/foo/bar", "/foo") == "/foo/outside" instead of "/outside"
|
||||||
|
//
|
||||||
|
// IMPORTANT: it is the caller's responsibility to call evalSymlinksInScope *after* relevant symlinks
|
||||||
|
// are created and not to create subsequently, additional symlinks that could potentially make a
|
||||||
|
// previously-safe path, unsafe. Example: if /foo/bar does not exist, evalSymlinksInScope("/foo/bar", "/foo")
|
||||||
|
// would return "/foo/bar". If one makes /foo/bar a symlink to /baz subsequently, then "/foo/bar" should
|
||||||
|
// no longer be considered safely contained in "/foo".
|
||||||
|
func evalSymlinksInScope(path, root string) (string, error) {
|
||||||
|
root = filepath.Clean(root)
|
||||||
|
if path == root {
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(path, root) {
|
||||||
|
return "", errors.New("evalSymlinksInScope: " + path + " is not in " + root)
|
||||||
|
}
|
||||||
|
const maxIter = 255
|
||||||
|
originalPath := path
|
||||||
|
// given root of "/a" and path of "/a/b/../../c" we want path to be "/b/../../c"
|
||||||
|
path = path[len(root):]
|
||||||
|
if root == string(filepath.Separator) {
|
||||||
|
path = string(filepath.Separator) + path
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(path, string(filepath.Separator)) {
|
||||||
|
return "", errors.New("evalSymlinksInScope: " + path + " is not in " + root)
|
||||||
|
}
|
||||||
|
path = filepath.Clean(path)
|
||||||
|
// consume path by taking each frontmost path element,
|
||||||
|
// expanding it if it's a symlink, and appending it to b
|
||||||
|
var b bytes.Buffer
|
||||||
|
// b here will always be considered to be the "current absolute path inside
|
||||||
|
// root" when we append paths to it, we also append a slash and use
|
||||||
|
// filepath.Clean after the loop to trim the trailing slash
|
||||||
|
for n := 0; path != ""; n++ {
|
||||||
|
if n > maxIter {
|
||||||
|
return "", errors.New("evalSymlinksInScope: too many links in " + originalPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// find next path component, p
|
||||||
|
i := strings.IndexRune(path, filepath.Separator)
|
||||||
|
var p string
|
||||||
|
if i == -1 {
|
||||||
|
p, path = path, ""
|
||||||
|
} else {
|
||||||
|
p, path = path[:i], path[i+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if p == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// this takes a b.String() like "b/../" and a p like "c" and turns it
|
||||||
|
// into "/b/../c" which then gets filepath.Cleaned into "/c" and then
|
||||||
|
// root gets prepended and we Clean again (to remove any trailing slash
|
||||||
|
// if the first Clean gave us just "/")
|
||||||
|
cleanP := filepath.Clean(string(filepath.Separator) + b.String() + p)
|
||||||
|
if isDriveOrRoot(cleanP) {
|
||||||
|
// never Lstat "/" itself, or drive letters on Windows
|
||||||
|
b.Reset()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fullP := filepath.Clean(root + cleanP)
|
||||||
|
|
||||||
|
fi, err := os.Lstat(fullP)
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
// if p does not exist, accept it
|
||||||
|
b.WriteString(p)
|
||||||
|
b.WriteRune(filepath.Separator)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if fi.Mode()&os.ModeSymlink == 0 {
|
||||||
|
b.WriteString(p)
|
||||||
|
b.WriteRune(filepath.Separator)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// it's a symlink, put it at the front of path
|
||||||
|
dest, err := os.Readlink(fullP)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if system.IsAbs(dest) {
|
||||||
|
b.Reset()
|
||||||
|
}
|
||||||
|
path = dest + string(filepath.Separator) + path
|
||||||
|
}
|
||||||
|
|
||||||
|
// see note above on "fullP := ..." for why this is double-cleaned and
|
||||||
|
// what's happening here
|
||||||
|
return filepath.Clean(root + filepath.Clean(string(filepath.Separator)+b.String())), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EvalSymlinks returns the path name after the evaluation of any symbolic
|
||||||
|
// links.
|
||||||
|
// If path is relative the result will be relative to the current directory,
|
||||||
|
// unless one of the components is an absolute symbolic link.
|
||||||
|
// This version has been updated to support long paths prepended with `\\?\`.
|
||||||
|
func EvalSymlinks(path string) (string, error) {
|
||||||
|
return evalSymlinks(path)
|
||||||
|
}
|
15
libnetwork/vendor/github.com/docker/docker/pkg/symlink/fs_unix.go
generated
vendored
Normal file
15
libnetwork/vendor/github.com/docker/docker/pkg/symlink/fs_unix.go
generated
vendored
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// +build !windows
|
||||||
|
|
||||||
|
package symlink // import "github.com/docker/docker/pkg/symlink"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func evalSymlinks(path string) (string, error) {
|
||||||
|
return filepath.EvalSymlinks(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDriveOrRoot(p string) bool {
|
||||||
|
return p == string(filepath.Separator)
|
||||||
|
}
|
169
libnetwork/vendor/github.com/docker/docker/pkg/symlink/fs_windows.go
generated
vendored
Normal file
169
libnetwork/vendor/github.com/docker/docker/pkg/symlink/fs_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
package symlink // import "github.com/docker/docker/pkg/symlink"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/docker/pkg/longpath"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toShort(path string) (string, error) {
|
||||||
|
p, err := windows.UTF16FromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
b := p // GetShortPathName says we can reuse buffer
|
||||||
|
n, err := windows.GetShortPathName(&p[0], &b[0], uint32(len(b)))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if n > uint32(len(b)) {
|
||||||
|
b = make([]uint16, n)
|
||||||
|
if _, err = windows.GetShortPathName(&p[0], &b[0], uint32(len(b))); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return windows.UTF16ToString(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func toLong(path string) (string, error) {
|
||||||
|
p, err := windows.UTF16FromString(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
b := p // GetLongPathName says we can reuse buffer
|
||||||
|
n, err := windows.GetLongPathName(&p[0], &b[0], uint32(len(b)))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if n > uint32(len(b)) {
|
||||||
|
b = make([]uint16, n)
|
||||||
|
n, err = windows.GetLongPathName(&p[0], &b[0], uint32(len(b)))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b = b[:n]
|
||||||
|
return windows.UTF16ToString(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func evalSymlinks(path string) (string, error) {
|
||||||
|
path, err := walkSymlinks(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
p, err := toShort(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
p, err = toLong(p)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// windows.GetLongPathName does not change the case of the drive letter,
|
||||||
|
// but the result of EvalSymlinks must be unique, so we have
|
||||||
|
// EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
|
||||||
|
// Make drive letter upper case.
|
||||||
|
if len(p) >= 2 && p[1] == ':' && 'a' <= p[0] && p[0] <= 'z' {
|
||||||
|
p = string(p[0]+'A'-'a') + p[1:]
|
||||||
|
} else if len(p) >= 6 && p[5] == ':' && 'a' <= p[4] && p[4] <= 'z' {
|
||||||
|
p = p[:3] + string(p[4]+'A'-'a') + p[5:]
|
||||||
|
}
|
||||||
|
return filepath.Clean(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const utf8RuneSelf = 0x80
|
||||||
|
|
||||||
|
func walkSymlinks(path string) (string, error) {
|
||||||
|
const maxIter = 255
|
||||||
|
originalPath := path
|
||||||
|
// consume path by taking each frontmost path element,
|
||||||
|
// expanding it if it's a symlink, and appending it to b
|
||||||
|
var b bytes.Buffer
|
||||||
|
for n := 0; path != ""; n++ {
|
||||||
|
if n > maxIter {
|
||||||
|
return "", errors.New("EvalSymlinks: too many links in " + originalPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A path beginning with `\\?\` represents the root, so automatically
|
||||||
|
// skip that part and begin processing the next segment.
|
||||||
|
if strings.HasPrefix(path, longpath.Prefix) {
|
||||||
|
b.WriteString(longpath.Prefix)
|
||||||
|
path = path[4:]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// find next path component, p
|
||||||
|
var i = -1
|
||||||
|
for j, c := range path {
|
||||||
|
if c < utf8RuneSelf && os.IsPathSeparator(uint8(c)) {
|
||||||
|
i = j
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var p string
|
||||||
|
if i == -1 {
|
||||||
|
p, path = path, ""
|
||||||
|
} else {
|
||||||
|
p, path = path[:i], path[i+1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if p == "" {
|
||||||
|
if b.Len() == 0 {
|
||||||
|
// must be absolute path
|
||||||
|
b.WriteRune(filepath.Separator)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the first segment after the long path prefix, accept the
|
||||||
|
// current segment as a volume root or UNC share and move on to the next.
|
||||||
|
if b.String() == longpath.Prefix {
|
||||||
|
b.WriteString(p)
|
||||||
|
b.WriteRune(filepath.Separator)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fi, err := os.Lstat(b.String() + p)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if fi.Mode()&os.ModeSymlink == 0 {
|
||||||
|
b.WriteString(p)
|
||||||
|
if path != "" || (b.Len() == 2 && len(p) == 2 && p[1] == ':') {
|
||||||
|
b.WriteRune(filepath.Separator)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// it's a symlink, put it at the front of path
|
||||||
|
dest, err := os.Readlink(b.String() + p)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if filepath.IsAbs(dest) || os.IsPathSeparator(dest[0]) {
|
||||||
|
b.Reset()
|
||||||
|
}
|
||||||
|
path = dest + string(filepath.Separator) + path
|
||||||
|
}
|
||||||
|
return filepath.Clean(b.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isDriveOrRoot(p string) bool {
|
||||||
|
if p == string(filepath.Separator) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
length := len(p)
|
||||||
|
if length >= 2 {
|
||||||
|
if p[length-1] == ':' && (('a' <= p[length-2] && p[length-2] <= 'z') || ('A' <= p[length-2] && p[length-2] <= 'Z')) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue