Home | History | Annotate | Download | only in filepath
      1 // Copyright 2010 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 	"strings"
      9 	"syscall"
     10 )
     11 
     12 func isSlash(c uint8) bool {
     13 	return c == '\\' || c == '/'
     14 }
     15 
     16 // IsAbs reports whether the path is absolute.
     17 func IsAbs(path string) (b bool) {
     18 	l := volumeNameLen(path)
     19 	if l == 0 {
     20 		return false
     21 	}
     22 	path = path[l:]
     23 	if path == "" {
     24 		return false
     25 	}
     26 	return isSlash(path[0])
     27 }
     28 
     29 // volumeNameLen returns length of the leading volume name on Windows.
     30 // It returns 0 elsewhere.
     31 func volumeNameLen(path string) int {
     32 	if len(path) < 2 {
     33 		return 0
     34 	}
     35 	// with drive letter
     36 	c := path[0]
     37 	if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
     38 		return 2
     39 	}
     40 	// is it UNC
     41 	if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
     42 		!isSlash(path[2]) && path[2] != '.' {
     43 		// first, leading `\\` and next shouldn't be `\`. its server name.
     44 		for n := 3; n < l-1; n++ {
     45 			// second, next '\' shouldn't be repeated.
     46 			if isSlash(path[n]) {
     47 				n++
     48 				// third, following something characters. its share name.
     49 				if !isSlash(path[n]) {
     50 					if path[n] == '.' {
     51 						break
     52 					}
     53 					for ; n < l; n++ {
     54 						if isSlash(path[n]) {
     55 							break
     56 						}
     57 					}
     58 					return n
     59 				}
     60 				break
     61 			}
     62 		}
     63 	}
     64 	return 0
     65 }
     66 
     67 // HasPrefix exists for historical compatibility and should not be used.
     68 func HasPrefix(p, prefix string) bool {
     69 	if strings.HasPrefix(p, prefix) {
     70 		return true
     71 	}
     72 	return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix))
     73 }
     74 
     75 func splitList(path string) []string {
     76 	// The same implementation is used in LookPath in os/exec;
     77 	// consider changing os/exec when changing this.
     78 
     79 	if path == "" {
     80 		return []string{}
     81 	}
     82 
     83 	// Split path, respecting but preserving quotes.
     84 	list := []string{}
     85 	start := 0
     86 	quo := false
     87 	for i := 0; i < len(path); i++ {
     88 		switch c := path[i]; {
     89 		case c == '"':
     90 			quo = !quo
     91 		case c == ListSeparator && !quo:
     92 			list = append(list, path[start:i])
     93 			start = i + 1
     94 		}
     95 	}
     96 	list = append(list, path[start:])
     97 
     98 	// Remove quotes.
     99 	for i, s := range list {
    100 		if strings.Contains(s, `"`) {
    101 			list[i] = strings.Replace(s, `"`, ``, -1)
    102 		}
    103 	}
    104 
    105 	return list
    106 }
    107 
    108 func abs(path string) (string, error) {
    109 	return syscall.FullPath(path)
    110 }
    111 
    112 func join(elem []string) string {
    113 	for i, e := range elem {
    114 		if e != "" {
    115 			return joinNonEmpty(elem[i:])
    116 		}
    117 	}
    118 	return ""
    119 }
    120 
    121 // joinNonEmpty is like join, but it assumes that the first element is non-empty.
    122 func joinNonEmpty(elem []string) string {
    123 	// The following logic prevents Join from inadvertently creating a
    124 	// UNC path on Windows. Unless the first element is a UNC path, Join
    125 	// shouldn't create a UNC path. See golang.org/issue/9167.
    126 	p := Clean(strings.Join(elem, string(Separator)))
    127 	if !isUNC(p) {
    128 		return p
    129 	}
    130 	// p == UNC only allowed when the first element is a UNC path.
    131 	head := Clean(elem[0])
    132 	if isUNC(head) {
    133 		return p
    134 	}
    135 	// head + tail == UNC, but joining two non-UNC paths should not result
    136 	// in a UNC path. Undo creation of UNC path.
    137 	tail := Clean(strings.Join(elem[1:], string(Separator)))
    138 	if head[len(head)-1] == Separator {
    139 		return head + tail
    140 	}
    141 	return head + string(Separator) + tail
    142 }
    143 
    144 // isUNC reports whether path is a UNC path.
    145 func isUNC(path string) bool {
    146 	return volumeNameLen(path) > 2
    147 }
    148