2012-03-30 23:27:11 +02:00
|
|
|
// 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 file.
|
|
|
|
|
|
|
|
package filepath
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"os"
|
2016-02-03 22:58:02 +01:00
|
|
|
"runtime"
|
2012-03-30 23:27:11 +02:00
|
|
|
)
|
|
|
|
|
2016-02-03 22:58:02 +01:00
|
|
|
// isRoot returns true if path is root of file system
|
|
|
|
// (`/` on unix and `/`, `\`, `c:\` or `c:/` on windows).
|
|
|
|
func isRoot(path string) bool {
|
|
|
|
if runtime.GOOS != "windows" {
|
|
|
|
return path == "/"
|
|
|
|
}
|
|
|
|
switch len(path) {
|
|
|
|
case 1:
|
|
|
|
return os.IsPathSeparator(path[0])
|
|
|
|
case 3:
|
|
|
|
return path[1] == ':' && os.IsPathSeparator(path[2])
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2015-01-15 01:27:56 +01:00
|
|
|
|
2016-02-03 22:58:02 +01:00
|
|
|
// isDriveLetter returns true if path is Windows drive letter (like "c:").
|
|
|
|
func isDriveLetter(path string) bool {
|
|
|
|
if runtime.GOOS != "windows" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return len(path) == 2 && path[1] == ':'
|
|
|
|
}
|
2012-03-30 23:27:11 +02:00
|
|
|
|
2016-02-03 22:58:02 +01:00
|
|
|
func walkLink(path string, linksWalked *int) (newpath string, islink bool, err error) {
|
|
|
|
if *linksWalked > 255 {
|
|
|
|
return "", false, errors.New("EvalSymlinks: too many links")
|
|
|
|
}
|
|
|
|
fi, err := os.Lstat(path)
|
|
|
|
if err != nil {
|
|
|
|
return "", false, err
|
|
|
|
}
|
|
|
|
if fi.Mode()&os.ModeSymlink == 0 {
|
|
|
|
return path, false, nil
|
|
|
|
}
|
|
|
|
newpath, err = os.Readlink(path)
|
|
|
|
if err != nil {
|
|
|
|
return "", false, err
|
|
|
|
}
|
|
|
|
*linksWalked++
|
|
|
|
return newpath, true, nil
|
|
|
|
}
|
2012-03-30 23:27:11 +02:00
|
|
|
|
2016-02-03 22:58:02 +01:00
|
|
|
func walkLinks(path string, linksWalked *int) (string, error) {
|
|
|
|
switch dir, file := Split(path); {
|
|
|
|
case dir == "":
|
|
|
|
newpath, _, err := walkLink(file, linksWalked)
|
|
|
|
return newpath, err
|
|
|
|
case file == "":
|
|
|
|
if isDriveLetter(dir) {
|
|
|
|
return dir, nil
|
|
|
|
}
|
|
|
|
if os.IsPathSeparator(dir[len(dir)-1]) {
|
|
|
|
if isRoot(dir) {
|
|
|
|
return dir, nil
|
2012-03-30 23:27:11 +02:00
|
|
|
}
|
2016-02-03 22:58:02 +01:00
|
|
|
return walkLinks(dir[:len(dir)-1], linksWalked)
|
2012-03-30 23:27:11 +02:00
|
|
|
}
|
2016-02-03 22:58:02 +01:00
|
|
|
newpath, _, err := walkLink(dir, linksWalked)
|
|
|
|
return newpath, err
|
|
|
|
default:
|
|
|
|
newdir, err := walkLinks(dir, linksWalked)
|
2012-03-30 23:27:11 +02:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2016-02-03 22:58:02 +01:00
|
|
|
newpath, islink, err := walkLink(Join(newdir, file), linksWalked)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if !islink {
|
|
|
|
return newpath, nil
|
2012-03-30 23:27:11 +02:00
|
|
|
}
|
2016-02-03 22:58:02 +01:00
|
|
|
if IsAbs(newpath) || os.IsPathSeparator(newpath[0]) {
|
|
|
|
return newpath, nil
|
|
|
|
}
|
|
|
|
return Join(newdir, newpath), nil
|
|
|
|
}
|
|
|
|
}
|
2012-03-30 23:27:11 +02:00
|
|
|
|
2016-02-03 22:58:02 +01:00
|
|
|
func walkSymlinks(path string) (string, error) {
|
|
|
|
if path == "" {
|
|
|
|
return path, nil
|
|
|
|
}
|
|
|
|
var linksWalked int // to protect against cycles
|
|
|
|
for {
|
|
|
|
i := linksWalked
|
|
|
|
newpath, err := walkLinks(path, &linksWalked)
|
2012-03-30 23:27:11 +02:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2016-02-03 22:58:02 +01:00
|
|
|
if runtime.GOOS == "windows" {
|
|
|
|
// walkLinks(".", ...) always retuns "." on unix.
|
|
|
|
// But on windows it returns symlink target, if current
|
|
|
|
// directory is a symlink. Stop the walk, if symlink
|
|
|
|
// target is not absolute path, and return "."
|
|
|
|
// to the caller (just like unix does).
|
|
|
|
if path == "." && !IsAbs(newpath) {
|
|
|
|
return ".", nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if i == linksWalked {
|
|
|
|
return Clean(newpath), nil
|
2012-03-30 23:27:11 +02:00
|
|
|
}
|
2016-02-03 22:58:02 +01:00
|
|
|
path = newpath
|
2012-03-30 23:27:11 +02:00
|
|
|
}
|
|
|
|
}
|