github.com/fjballest/golang@v0.0.0-20151209143359-e4c5fe594ca8/src/path/filepath/symlink.go (about) 1 // Copyright 2012 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package filepath 6 7 import ( 8 "errors" 9 "os" 10 "runtime" 11 ) 12 13 // isRoot returns true if path is root of file system 14 // (`/` on unix and `/`, `\`, `c:\` or `c:/` on windows). 15 func isRoot(path string) bool { 16 if runtime.GOOS != "windows" { 17 return path == "/" 18 } 19 switch len(path) { 20 case 1: 21 return os.IsPathSeparator(path[0]) 22 case 3: 23 return path[1] == ':' && os.IsPathSeparator(path[2]) 24 } 25 return false 26 } 27 28 // isDriveLetter returns true if path is Windows drive letter (like "c:"). 29 func isDriveLetter(path string) bool { 30 if runtime.GOOS != "windows" { 31 return false 32 } 33 return len(path) == 2 && path[1] == ':' 34 } 35 36 func walkLink(path string, linksWalked *int) (newpath string, islink bool, err error) { 37 if *linksWalked > 255 { 38 return "", false, errors.New("EvalSymlinks: too many links") 39 } 40 fi, err := os.Lstat(path) 41 if err != nil { 42 return "", false, err 43 } 44 if fi.Mode()&os.ModeSymlink == 0 { 45 return path, false, nil 46 } 47 newpath, err = os.Readlink(path) 48 if err != nil { 49 return "", false, err 50 } 51 *linksWalked++ 52 return newpath, true, nil 53 } 54 55 func walkLinks(path string, linksWalked *int) (string, error) { 56 switch dir, file := Split(path); { 57 case dir == "": 58 newpath, _, err := walkLink(file, linksWalked) 59 return newpath, err 60 case file == "": 61 if isDriveLetter(dir) { 62 return dir, nil 63 } 64 if os.IsPathSeparator(dir[len(dir)-1]) { 65 if isRoot(dir) { 66 return dir, nil 67 } 68 return walkLinks(dir[:len(dir)-1], linksWalked) 69 } 70 newpath, _, err := walkLink(dir, linksWalked) 71 return newpath, err 72 default: 73 newdir, err := walkLinks(dir, linksWalked) 74 if err != nil { 75 return "", err 76 } 77 newpath, islink, err := walkLink(Join(newdir, file), linksWalked) 78 if err != nil { 79 return "", err 80 } 81 if !islink { 82 return newpath, nil 83 } 84 if IsAbs(newpath) || os.IsPathSeparator(newpath[0]) { 85 return newpath, nil 86 } 87 return Join(newdir, newpath), nil 88 89 } 90 } 91 92 func walkSymlinks(path string) (string, error) { 93 if path == "" { 94 return path, nil 95 } 96 var linksWalked int // to protect against cycles 97 newpath, err := walkLinks(path, &linksWalked) 98 if err != nil { 99 return "", err 100 } 101 return Clean(newpath), nil 102 }