...
Source file src/pkg/path/filepath/symlink.go
1
2
3
4
5 package filepath
6
7 import (
8 "errors"
9 "os"
10 "runtime"
11 "syscall"
12 )
13
14 func walkSymlinks(path string) (string, error) {
15 volLen := volumeNameLen(path)
16 pathSeparator := string(os.PathSeparator)
17
18 if volLen < len(path) && os.IsPathSeparator(path[volLen]) {
19 volLen++
20 }
21 vol := path[:volLen]
22 dest := vol
23 linksWalked := 0
24 for start, end := volLen, volLen; start < len(path); start = end {
25 for start < len(path) && os.IsPathSeparator(path[start]) {
26 start++
27 }
28 end = start
29 for end < len(path) && !os.IsPathSeparator(path[end]) {
30 end++
31 }
32
33
34
35
36 isWindowsDot := runtime.GOOS == "windows" && path[volumeNameLen(path):] == "."
37
38
39 if end == start {
40
41 break
42 } else if path[start:end] == "." && !isWindowsDot {
43
44 continue
45 } else if path[start:end] == ".." {
46
47
48
49
50
51 var r int
52 for r = len(dest) - 1; r >= volLen; r-- {
53 if os.IsPathSeparator(dest[r]) {
54 break
55 }
56 }
57 if r < volLen || dest[r+1:] == ".." {
58
59
60
61
62 if len(dest) > volLen {
63 dest += pathSeparator
64 }
65 dest += ".."
66 } else {
67
68 dest = dest[:r]
69 }
70 continue
71 }
72
73
74
75 if len(dest) > volumeNameLen(dest) && !os.IsPathSeparator(dest[len(dest)-1]) {
76 dest += pathSeparator
77 }
78
79 dest += path[start:end]
80
81
82
83 fi, err := os.Lstat(dest)
84 if err != nil {
85 return "", err
86 }
87
88 if fi.Mode()&os.ModeSymlink == 0 {
89 if !fi.Mode().IsDir() && end < len(path) {
90 return "", syscall.ENOTDIR
91 }
92 continue
93 }
94
95
96
97 linksWalked++
98 if linksWalked > 255 {
99 return "", errors.New("EvalSymlinks: too many links")
100 }
101
102 link, err := os.Readlink(dest)
103 if err != nil {
104 return "", err
105 }
106
107 if isWindowsDot && !IsAbs(link) {
108
109
110 break
111 }
112
113 path = link + path[end:]
114
115 v := volumeNameLen(link)
116 if v > 0 {
117
118 if v < len(link) && os.IsPathSeparator(link[v]) {
119 v++
120 }
121 vol = link[:v]
122 dest = vol
123 end = len(vol)
124 } else if len(link) > 0 && os.IsPathSeparator(link[0]) {
125
126 dest = link[:1]
127 end = 1
128 } else {
129
130
131 var r int
132 for r = len(dest) - 1; r >= volLen; r-- {
133 if os.IsPathSeparator(dest[r]) {
134 break
135 }
136 }
137 if r < volLen {
138 dest = vol
139 } else {
140 dest = dest[:r]
141 }
142 end = 0
143 }
144 }
145 return Clean(dest), nil
146 }
147
View as plain text