From ac5f45cfb230d99bf92d640836d5b1a01f612ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20F=20Bj=C3=B6rklund?= Date: Tue, 12 Jul 2022 22:19:33 +0200 Subject: [PATCH] Use short path for LIMA_HOME on windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Other commands such as qemu-system-x86_64.exe don't work with C:\Users\AndersBjörklund, they need to use C:\Users\ANDERS~1 In theory they could have supported using UNC paths such as \\?\C:\Users\AndersBjörklund, but in practice they do not... Signed-off-by: Anders F Björklund --- pkg/store/dirnames/dirnames.go | 16 +++++++++++ pkg/store/dirnames/shortname_others.go | 9 ++++++ pkg/store/dirnames/shortname_test.go | 37 +++++++++++++++++++++++++ pkg/store/dirnames/shortname_windows.go | 23 +++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 pkg/store/dirnames/shortname_others.go create mode 100644 pkg/store/dirnames/shortname_test.go create mode 100644 pkg/store/dirnames/shortname_windows.go diff --git a/pkg/store/dirnames/dirnames.go b/pkg/store/dirnames/dirnames.go index bc7f814d71c..a03e0ad0774 100644 --- a/pkg/store/dirnames/dirnames.go +++ b/pkg/store/dirnames/dirnames.go @@ -5,6 +5,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "github.com/lima-vm/lima/pkg/store/filenames" ) @@ -17,6 +18,10 @@ const DotLima = ".lima" // NOTE: We do not use `~/Library/Application Support/Lima` on macOS. // We use `~/.lima` so that we can have enough space for the length of the socket path, // which can be only 104 characters on macOS. +// +// NOTE: There are some issues when using "long names" on Windows. +// We use "short names" here, so that it works with user names containing unicode etc. +// They normally have 8+3 characters, with suffix. func LimaDir() (string, error) { dir := os.Getenv("LIMA_HOME") if dir == "" { @@ -24,11 +29,22 @@ func LimaDir() (string, error) { if err != nil { return "", err } + // on windows, 8.3 paths are needed by some tools like QEMU + if runtime.GOOS == "windows" { + homeDir, err = ShortPathName(homeDir) + if err != nil { + return "", err + } + } dir = filepath.Join(homeDir, DotLima) } if _, err := os.Stat(dir); errors.Is(err, os.ErrNotExist) { return dir, nil } + // on windows, EvalSymlinks translates short paths back to long again + if runtime.GOOS == "windows" { + return dir, nil + } realdir, err := filepath.EvalSymlinks(dir) if err != nil { return "", fmt.Errorf("cannot evaluate symlinks in %q: %w", dir, err) diff --git a/pkg/store/dirnames/shortname_others.go b/pkg/store/dirnames/shortname_others.go new file mode 100644 index 00000000000..60750fd88be --- /dev/null +++ b/pkg/store/dirnames/shortname_others.go @@ -0,0 +1,9 @@ +//go:build !windows +// +build !windows + +package dirnames + +// ShortPathName just returns the provided path. +func ShortPathName(path string) (string, error) { + return path, nil +} diff --git a/pkg/store/dirnames/shortname_test.go b/pkg/store/dirnames/shortname_test.go new file mode 100644 index 00000000000..31284cb3eb1 --- /dev/null +++ b/pkg/store/dirnames/shortname_test.go @@ -0,0 +1,37 @@ +package dirnames + +import ( + "os" + "path/filepath" + "testing" + + "gotest.tools/v3/assert" +) + +// Note: can't use t.TempDir(), because it is _always_ long... +// instead use os.TempDir(), something like `C:\users\anders\Temp` + +func TestShortPathNameShort(t *testing.T) { + d := os.TempDir() + l := filepath.Join(d, "foo") + err := os.Mkdir(l, 0755) + assert.NilError(t, err) + s, err := ShortPathName(l) + assert.NilError(t, err) + t.Logf("%s => %s", l, s) + os.RemoveAll(l) +} + +func TestShortPathNameLong(t *testing.T) { + d := os.TempDir() + l := filepath.Join(d, "baaaaaaaaaar") + err := os.Mkdir(l, 0755) + assert.NilError(t, err) + s, err := ShortPathName(l) + assert.NilError(t, err) + t.Logf("%s => %s", l, s) + fi, err := os.Stat(s) + assert.NilError(t, err) + assert.Assert(t, fi.Mode().IsDir()) + os.RemoveAll(l) +} diff --git a/pkg/store/dirnames/shortname_windows.go b/pkg/store/dirnames/shortname_windows.go new file mode 100644 index 00000000000..f83d3dc75d2 --- /dev/null +++ b/pkg/store/dirnames/shortname_windows.go @@ -0,0 +1,23 @@ +package dirnames + +import ( + "syscall" +) + +// ShortPathName return the short path name, when given a long path. +func ShortPathName(path string) (string, error) { + p := syscall.StringToUTF16(path) + b := p // GetShortPathName says we can reuse buffer + n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + if n > uint32(len(b)) { + b = make([]uint16, n) + n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + } + return syscall.UTF16ToString(b), nil +}