Source file src/pkg/path/filepath/symlink.go
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 // +build !windows
6
7 package filepath
8
9 import (
10 "bytes"
11 "errors"
12 "os"
13 "strings"
14 )
15
16 func evalSymlinks(path string) (string, error) {
17 const maxIter = 255
18 originalPath := path
19 // consume path by taking each frontmost path element,
20 // expanding it if it's a symlink, and appending it to b
21 var b bytes.Buffer
22 for n := 0; path != ""; n++ {
23 if n > maxIter {
24 return "", errors.New("EvalSymlinks: too many links in " + originalPath)
25 }
26
27 // find next path component, p
28 i := strings.IndexRune(path, Separator)
29 var p string
30 if i == -1 {
31 p, path = path, ""
32 } else {
33 p, path = path[:i], path[i+1:]
34 }
35
36 if p == "" {
37 if b.Len() == 0 {
38 // must be absolute path
39 b.WriteRune(Separator)
40 }
41 continue
42 }
43
44 fi, err := os.Lstat(b.String() + p)
45 if err != nil {
46 return "", err
47 }
48 if fi.Mode()&os.ModeSymlink == 0 {
49 b.WriteString(p)
50 if path != "" {
51 b.WriteRune(Separator)
52 }
53 continue
54 }
55
56 // it's a symlink, put it at the front of path
57 dest, err := os.Readlink(b.String() + p)
58 if err != nil {
59 return "", err
60 }
61 if IsAbs(dest) {
62 b.Reset()
63 }
64 path = dest + string(Separator) + path
65 }
66 return Clean(b.String()), nil
67 }