aboutsummaryrefslogtreecommitdiff
path: root/src/path/filepath/path_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/path/filepath/path_windows.go')
-rw-r--r--src/path/filepath/path_windows.go200
1 files changed, 3 insertions, 197 deletions
diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go
index 6adb7d4bc4..d53f87f1ac 100644
--- a/src/path/filepath/path_windows.go
+++ b/src/path/filepath/path_windows.go
@@ -1,179 +1,11 @@
-// Copyright 2010 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
package filepath
import (
- "internal/safefilepath"
"os"
"strings"
"syscall"
)
-func isSlash(c uint8) bool {
- return c == '\\' || c == '/'
-}
-
-func toUpper(c byte) byte {
- if 'a' <= c && c <= 'z' {
- return c - ('a' - 'A')
- }
- return c
-}
-
-func isLocal(path string) bool {
- if path == "" {
- return false
- }
- if isSlash(path[0]) {
- // Path rooted in the current drive.
- return false
- }
- if strings.IndexByte(path, ':') >= 0 {
- // Colons are only valid when marking a drive letter ("C:foo").
- // Rejecting any path with a colon is conservative but safe.
- return false
- }
- hasDots := false // contains . or .. path elements
- for p := path; p != ""; {
- var part string
- part, p, _ = cutPath(p)
- if part == "." || part == ".." {
- hasDots = true
- }
- if safefilepath.IsReservedName(part) {
- return false
- }
- }
- if hasDots {
- path = Clean(path)
- }
- if path == ".." || strings.HasPrefix(path, `..\`) {
- return false
- }
- return true
-}
-
-// IsAbs reports whether the path is absolute.
-func IsAbs(path string) (b bool) {
- l := volumeNameLen(path)
- if l == 0 {
- return false
- }
- // If the volume name starts with a double slash, this is an absolute path.
- if isSlash(path[0]) && isSlash(path[1]) {
- return true
- }
- path = path[l:]
- if path == "" {
- return false
- }
- return isSlash(path[0])
-}
-
-// volumeNameLen returns length of the leading volume name on Windows.
-// It returns 0 elsewhere.
-//
-// See:
-// https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats
-// https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html
-func volumeNameLen(path string) int {
- switch {
- case len(path) >= 2 && path[1] == ':':
- // Path starts with a drive letter.
- //
- // Not all Windows functions necessarily enforce the requirement that
- // drive letters be in the set A-Z, and we don't try to here.
- //
- // We don't handle the case of a path starting with a non-ASCII character,
- // in which case the "drive letter" might be multiple bytes long.
- return 2
-
- case len(path) == 0 || !isSlash(path[0]):
- // Path does not have a volume component.
- return 0
-
- case pathHasPrefixFold(path, `\\.\UNC`):
- // We're going to treat the UNC host and share as part of the volume
- // prefix for historical reasons, but this isn't really principled;
- // Windows's own GetFullPathName will happily remove the first
- // component of the path in this space, converting
- // \\.\unc\a\b\..\c into \\.\unc\a\c.
- return uncLen(path, len(`\\.\UNC\`))
-
- case pathHasPrefixFold(path, `\\.`) ||
- pathHasPrefixFold(path, `\\?`) || pathHasPrefixFold(path, `\??`):
- // Path starts with \\.\, and is a Local Device path; or
- // path starts with \\?\ or \??\ and is a Root Local Device path.
- //
- // We treat the next component after the \\.\ prefix as
- // part of the volume name, which means Clean(`\\?\c:\`)
- // won't remove the trailing \. (See #64028.)
- if len(path) == 3 {
- return 3 // exactly \\.
- }
- _, rest, ok := cutPath(path[4:])
- if !ok {
- return len(path)
- }
- return len(path) - len(rest) - 1
-
- case len(path) >= 2 && isSlash(path[1]):
- // Path starts with \\, and is a UNC path.
- return uncLen(path, 2)
- }
- return 0
-}
-
-// pathHasPrefixFold tests whether the path s begins with prefix,
-// ignoring case and treating all path separators as equivalent.
-// If s is longer than prefix, then s[len(prefix)] must be a path separator.
-func pathHasPrefixFold(s, prefix string) bool {
- if len(s) < len(prefix) {
- return false
- }
- for i := 0; i < len(prefix); i++ {
- if isSlash(prefix[i]) {
- if !isSlash(s[i]) {
- return false
- }
- } else if toUpper(prefix[i]) != toUpper(s[i]) {
- return false
- }
- }
- if len(s) > len(prefix) && !isSlash(s[len(prefix)]) {
- return false
- }
- return true
-}
-
-// uncLen returns the length of the volume prefix of a UNC path.
-// prefixLen is the prefix prior to the start of the UNC host;
-// for example, for "//host/share", the prefixLen is len("//")==2.
-func uncLen(path string, prefixLen int) int {
- count := 0
- for i := prefixLen; i < len(path); i++ {
- if isSlash(path[i]) {
- count++
- if count == 2 {
- return i
- }
- }
- }
- return len(path)
-}
-
-// cutPath slices path around the first path separator.
-func cutPath(path string) (before, after string, found bool) {
- for i := range path {
- if isSlash(path[i]) {
- return path[:i], path[i+1:], true
- }
- }
- return path, "", false
-}
-
// HasPrefix exists for historical compatibility and should not be used.
//
// Deprecated: HasPrefix does not respect path boundaries and
@@ -237,7 +69,7 @@ func join(elem []string) string {
switch {
case b.Len() == 0:
// Add the first non-empty path element unchanged.
- case isSlash(lastChar):
+ case os.IsPathSeparator(lastChar):
// If the path ends in a slash, strip any leading slashes from the next
// path element to avoid creating a UNC path (any path starting with "\\")
// from non-UNC elements.
@@ -245,13 +77,13 @@ func join(elem []string) string {
// The correct behavior for Join when the first element is an incomplete UNC
// path (for example, "\\") is underspecified. We currently join subsequent
// elements so Join("\\", "host", "share") produces "\\host\share".
- for len(e) > 0 && isSlash(e[0]) {
+ for len(e) > 0 && os.IsPathSeparator(e[0]) {
e = e[1:]
}
// If the path is \ and the next path element is ??,
// add an extra .\ to create \.\?? rather than \??\
// (a Root Local Device path).
- if b.Len() == 1 && pathHasPrefixFold(e, "??") {
+ if b.Len() == 1 && strings.HasPrefix(e, "??") && (len(e) == len("??") || os.IsPathSeparator(e[2])) {
b.WriteString(`.\`)
}
case lastChar == ':':
@@ -280,29 +112,3 @@ func join(elem []string) string {
func sameWord(a, b string) bool {
return strings.EqualFold(a, b)
}
-
-// postClean adjusts the results of Clean to avoid turning a relative path
-// into an absolute or rooted one.
-func postClean(out *lazybuf) {
- if out.volLen != 0 || out.buf == nil {
- return
- }
- // If a ':' appears in the path element at the start of a path,
- // insert a .\ at the beginning to avoid converting relative paths
- // like a/../c: into c:.
- for _, c := range out.buf {
- if os.IsPathSeparator(c) {
- break
- }
- if c == ':' {
- out.prepend('.', Separator)
- return
- }
- }
- // If a path begins with \??\, insert a \. at the beginning
- // to avoid converting paths like \a\..\??\c:\x into \??\c:\x
- // (equivalent to c:\x).
- if len(out.buf) >= 3 && os.IsPathSeparator(out.buf[0]) && out.buf[1] == '?' && out.buf[2] == '?' {
- out.prepend(Separator, '.')
- }
-}