github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/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 // appending "." to avoid bug in Join (see issue 11551) 63 return dir + ".", nil 64 } 65 if os.IsPathSeparator(dir[len(dir)-1]) { 66 if isRoot(dir) { 67 return dir, nil 68 } 69 return walkLinks(dir[:len(dir)-1], linksWalked) 70 } 71 newpath, _, err := walkLink(dir, linksWalked) 72 return newpath, err 73 default: 74 newdir, err := walkLinks(dir, linksWalked) 75 if err != nil { 76 return "", err 77 } 78 newpath, islink, err := walkLink(Join(newdir, file), linksWalked) 79 if err != nil { 80 return "", err 81 } 82 if !islink { 83 return newpath, nil 84 } 85 if IsAbs(newpath) || os.IsPathSeparator(newpath[0]) { 86 return newpath, nil 87 } 88 return Join(newdir, newpath), nil 89 90 } 91 } 92 93 func walkSymlinks(path string) (string, error) { 94 if path == "" { 95 return path, nil 96 } 97 var linksWalked int // to protect against cycles 98 newpath, err := walkLinks(path, &linksWalked) 99 if err != nil { 100 return "", err 101 } 102 return Clean(newpath), nil 103 }