فهرست منبع

Bump docker commit

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit aae1b0e116d0c4ee0e46494864d1540fec22ced3)
Signed-off-by: selansen <elango.siva@docker.com>
Brian Goff 7 سال پیش
والد
کامیت
e07681c8ca

+ 4 - 3
libnetwork/libnetwork_test.go

@@ -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

+ 1 - 1
libnetwork/vendor.conf

@@ -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 - 0
libnetwork/vendor/github.com/docker/docker/errdefs/defs.go

@@ -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 - 0
libnetwork/vendor/github.com/docker/docker/errdefs/doc.go

@@ -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 - 0
libnetwork/vendor/github.com/docker/docker/errdefs/helpers.go

@@ -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 - 0
libnetwork/vendor/github.com/docker/docker/errdefs/is.go

@@ -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 - 0
libnetwork/vendor/github.com/docker/docker/pkg/symlink/fs.go

@@ -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 - 0
libnetwork/vendor/github.com/docker/docker/pkg/symlink/fs_unix.go

@@ -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 - 0
libnetwork/vendor/github.com/docker/docker/pkg/symlink/fs_windows.go

@@ -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
+}