mirror of
https://github.com/golang/go
synced 2024-11-18 15:04:44 -07:00
82bb89366a
On case-insensitive file systems, the editor may send us a path that works but doesn't match the actual file's case. Then when we run go list, we'll get mismatching paths and everything will break. We can't reliably fix this problem: tracking what case the editor expects is too difficult to be worth it. Instead, check the workspace path and bail if it's mismatched. Possibly we should also check files on DidOpen or such, but we can start with this. Updates golang/go#36904. Change-Id: I7635c8136bf9400db4143a0f2fde25c39b5abc44 Reviewed-on: https://go-review.googlesource.com/c/tools/+/225239 Reviewed-by: Ian Cottrell <iancottrell@google.com>
56 lines
1.6 KiB
Go
56 lines
1.6 KiB
Go
// Copyright 2020 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 cache
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
"syscall"
|
|
)
|
|
|
|
func init() {
|
|
checkPathCase = windowsCheckPathCase
|
|
}
|
|
|
|
func windowsCheckPathCase(path string) error {
|
|
// Back in the day, Windows used to have short and long filenames, and
|
|
// it still supports those APIs. GetLongPathName gets the real case for a
|
|
// path, so we can use it here. Inspired by
|
|
// http://stackoverflow.com/q/2113822.
|
|
|
|
// Short paths can be longer than long paths, and unicode, so be generous.
|
|
buflen := 4 * len(path)
|
|
namep, err := syscall.UTF16PtrFromString(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
short := make([]uint16, buflen)
|
|
n, err := syscall.GetShortPathName(namep, &short[0], uint32(len(short)*2)) // buflen is in bytes.
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if int(n) > len(short)*2 {
|
|
return fmt.Errorf("short buffer too short: %v vs %v*2", n, len(short))
|
|
}
|
|
long := make([]uint16, buflen)
|
|
n, err = syscall.GetLongPathName(&short[0], &long[0], uint32(len(long)*2))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if int(n) > len(long)*2 {
|
|
return fmt.Errorf("long buffer too short: %v vs %v*2", n, len(long))
|
|
}
|
|
longstr := syscall.UTF16ToString(long)
|
|
|
|
isRoot := func(p string) bool {
|
|
return p[len(p)-1] == filepath.Separator
|
|
}
|
|
for got, want := path, longstr; !isRoot(got) && !isRoot(want); got, want = filepath.Dir(got), filepath.Dir(want) {
|
|
if g, w := filepath.Base(got), filepath.Base(want); g != w {
|
|
return fmt.Errorf("case mismatch in path %q: component %q should be %q", path, g, w)
|
|
}
|
|
}
|
|
return nil
|
|
}
|