...
Run Format

Source file src/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	package filepath
     6	
     7	import (
     8		"errors"
     9		"os"
    10		"runtime"
    11	)
    12	
    13	// isRoot returns true if path is root of file system
    14	// (`/` on unix and `/`, `\`, `c:\` or `c:/` on windows).
    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	// isDriveLetter returns true if path is Windows drive letter (like "c:").
    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 // to protect against cycles
    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				// walkLinks(".", ...) always retuns "." on unix.
   104				// But on windows it returns symlink target, if current
   105				// directory is a symlink. Stop the walk, if symlink
   106				// target is not absolute path, and return "."
   107				// to the caller (just like unix does).
   108				if path == "." && !IsAbs(newpath) {
   109					return ".", nil
   110				}
   111			}
   112			if i == linksWalked {
   113				return Clean(newpath), nil
   114			}
   115			path = newpath
   116		}
   117	}
   118	

View as plain text