blob: 243352819e0d23d66cb4b80d9cd94c2fcd3e320d [file] [log] [blame]
// Copyright 2012 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 (
"strings"
"syscall"
)
// normVolumeName is like VolumeName, but makes drive letter upper case.
// result of EvalSymlinks must be unique, so we have
// EvalSymlinks(`c:\a`) == EvalSymlinks(`C:\a`).
func normVolumeName(path string) string {
volume := VolumeName(path)
if len(volume) > 2 { // isUNC
return volume
}
return strings.ToUpper(volume)
}
// normBase retruns the last element of path.
func normBase(path string) (string, error) {
p, err := syscall.UTF16PtrFromString(path)
if err != nil {
return "", err
}
var data syscall.Win32finddata
h, err := syscall.FindFirstFile(p, &data)
if err != nil {
return "", err
}
syscall.FindClose(h)
return syscall.UTF16ToString(data.FileName[:]), nil
}
func toNorm(path string, base func(string) (string, error)) (string, error) {
if path == "" {
return path, nil
}
path = Clean(path)
volume := normVolumeName(path)
path = path[len(volume):]
// skip special cases
if path == "." || path == `\` {
return volume + path, nil
}
var normPath string
for {
name, err := base(volume + path)
if err != nil {
return "", err
}
normPath = name + `\` + normPath
i := strings.LastIndexByte(path, Separator)
if i == -1 {
break
}
if i == 0 { // `\Go` or `C:\Go`
normPath = `\` + normPath
break
}
path = path[:i]
}
normPath = normPath[:len(normPath)-1] // remove trailing '\'
return volume + normPath, nil
}
func evalSymlinks(path string) (string, error) {
path, err := walkSymlinks(path)
if err != nil {
return "", err
}
return toNorm(path, normBase)
}