github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/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  	"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  }