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