...

Source file src/pkg/path/filepath/path_windows.go

     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	// reservedNames lists reserved Windows names. Search for PRN in
    17	// https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file
    18	// for details.
    19	var reservedNames = []string{
    20		"CON", "PRN", "AUX", "NUL",
    21		"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
    22		"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
    23	}
    24	
    25	// isReservedName returns true, if path is Windows reserved name.
    26	// See reservedNames for the full list.
    27	func isReservedName(path string) bool {
    28		if len(path) == 0 {
    29			return false
    30		}
    31		for _, reserved := range reservedNames {
    32			if strings.EqualFold(path, reserved) {
    33				return true
    34			}
    35		}
    36		return false
    37	}
    38	
    39	// IsAbs reports whether the path is absolute.
    40	func IsAbs(path string) (b bool) {
    41		if isReservedName(path) {
    42			return true
    43		}
    44		l := volumeNameLen(path)
    45		if l == 0 {
    46			return false
    47		}
    48		path = path[l:]
    49		if path == "" {
    50			return false
    51		}
    52		return isSlash(path[0])
    53	}
    54	
    55	// volumeNameLen returns length of the leading volume name on Windows.
    56	// It returns 0 elsewhere.
    57	func volumeNameLen(path string) int {
    58		if len(path) < 2 {
    59			return 0
    60		}
    61		// with drive letter
    62		c := path[0]
    63		if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
    64			return 2
    65		}
    66		// is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
    67		if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
    68			!isSlash(path[2]) && path[2] != '.' {
    69			// first, leading `\\` and next shouldn't be `\`. its server name.
    70			for n := 3; n < l-1; n++ {
    71				// second, next '\' shouldn't be repeated.
    72				if isSlash(path[n]) {
    73					n++
    74					// third, following something characters. its share name.
    75					if !isSlash(path[n]) {
    76						if path[n] == '.' {
    77							break
    78						}
    79						for ; n < l; n++ {
    80							if isSlash(path[n]) {
    81								break
    82							}
    83						}
    84						return n
    85					}
    86					break
    87				}
    88			}
    89		}
    90		return 0
    91	}
    92	
    93	// HasPrefix exists for historical compatibility and should not be used.
    94	//
    95	// Deprecated: HasPrefix does not respect path boundaries and
    96	// does not ignore case when required.
    97	func HasPrefix(p, prefix string) bool {
    98		if strings.HasPrefix(p, prefix) {
    99			return true
   100		}
   101		return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix))
   102	}
   103	
   104	func splitList(path string) []string {
   105		// The same implementation is used in LookPath in os/exec;
   106		// consider changing os/exec when changing this.
   107	
   108		if path == "" {
   109			return []string{}
   110		}
   111	
   112		// Split path, respecting but preserving quotes.
   113		list := []string{}
   114		start := 0
   115		quo := false
   116		for i := 0; i < len(path); i++ {
   117			switch c := path[i]; {
   118			case c == '"':
   119				quo = !quo
   120			case c == ListSeparator && !quo:
   121				list = append(list, path[start:i])
   122				start = i + 1
   123			}
   124		}
   125		list = append(list, path[start:])
   126	
   127		// Remove quotes.
   128		for i, s := range list {
   129			list[i] = strings.ReplaceAll(s, `"`, ``)
   130		}
   131	
   132		return list
   133	}
   134	
   135	func abs(path string) (string, error) {
   136		if path == "" {
   137			// syscall.FullPath returns an error on empty path, because it's not a valid path.
   138			// To implement Abs behavior of returning working directory on empty string input,
   139			// special-case empty path by changing it to "." path. See golang.org/issue/24441.
   140			path = "."
   141		}
   142		fullPath, err := syscall.FullPath(path)
   143		if err != nil {
   144			return "", err
   145		}
   146		return Clean(fullPath), nil
   147	}
   148	
   149	func join(elem []string) string {
   150		for i, e := range elem {
   151			if e != "" {
   152				return joinNonEmpty(elem[i:])
   153			}
   154		}
   155		return ""
   156	}
   157	
   158	// joinNonEmpty is like join, but it assumes that the first element is non-empty.
   159	func joinNonEmpty(elem []string) string {
   160		if len(elem[0]) == 2 && elem[0][1] == ':' {
   161			// First element is drive letter without terminating slash.
   162			// Keep path relative to current directory on that drive.
   163			// Skip empty elements.
   164			i := 1
   165			for ; i < len(elem); i++ {
   166				if elem[i] != "" {
   167					break
   168				}
   169			}
   170			return Clean(elem[0] + strings.Join(elem[i:], string(Separator)))
   171		}
   172		// The following logic prevents Join from inadvertently creating a
   173		// UNC path on Windows. Unless the first element is a UNC path, Join
   174		// shouldn't create a UNC path. See golang.org/issue/9167.
   175		p := Clean(strings.Join(elem, string(Separator)))
   176		if !isUNC(p) {
   177			return p
   178		}
   179		// p == UNC only allowed when the first element is a UNC path.
   180		head := Clean(elem[0])
   181		if isUNC(head) {
   182			return p
   183		}
   184		// head + tail == UNC, but joining two non-UNC paths should not result
   185		// in a UNC path. Undo creation of UNC path.
   186		tail := Clean(strings.Join(elem[1:], string(Separator)))
   187		if head[len(head)-1] == Separator {
   188			return head + tail
   189		}
   190		return head + string(Separator) + tail
   191	}
   192	
   193	// isUNC reports whether path is a UNC path.
   194	func isUNC(path string) bool {
   195		return volumeNameLen(path) > 2
   196	}
   197	
   198	func sameWord(a, b string) bool {
   199		return strings.EqualFold(a, b)
   200	}
   201	

View as plain text