1
2
3
4
5 package filepath
6
7 import (
8 "errors"
9 "os"
10 "runtime"
11 )
12
13
14
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
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 func walkSymlinks(path string) (string, error) {
92 if path == "" {
93 return path, nil
94 }
95 var linksWalked int
96 for {
97 i := linksWalked
98 newpath, err := walkLinks(path, &linksWalked)
99 if err != nil {
100 return "", err
101 }
102 if runtime.GOOS == "windows" {
103
104
105
106
107
108
109 if path[volumeNameLen(path):] == "." && !IsAbs(newpath) {
110 return path, nil
111 }
112 }
113 if i == linksWalked {
114 return Clean(newpath), nil
115 }
116 path = newpath
117 }
118 }
119
View as plain text