From 06ba6a9519f7b7e386f989c3cede3f2eb85a0a68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Sat, 2 Feb 2019 17:28:14 +0000 Subject: [PATCH] interp: support lowercase volume names in $PATH On Windows, "C:" is a valid volume name, just like "c:". We were incorrectly assuming that the letter had to be uppercase. Add a simple regression test for Windows, which sets up a PATH with a script in a directory, then tries to execute it via such a PATH with a lowercase volume name. Fixes #355. --- interp/interp.go | 7 +++++-- interp/interp_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/interp/interp.go b/interp/interp.go index 256e8ac78..d6ec81893 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -1209,6 +1209,10 @@ func (r *Runner) findExecutable(file string, exts []string) string { return "" } +func driveLetter(c byte) bool { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') +} + // splitList is like filepath.SplitList, but always using the unix path // list separator ':'. On Windows, it also makes sure not to split // [A-Z]:[/\]. @@ -1225,8 +1229,7 @@ func splitList(path string) []string { for i := 0; i < len(list); i++ { s := list[i] switch { - case len(s) != 1, s[0] < 'A', s[0] > 'Z': - // not a disk name + case len(s) != 1, !driveLetter(s[0]): case i+1 >= len(list): // last element case strings.IndexAny(list[i+1], `/\`) != 0: diff --git a/interp/interp_test.go b/interp/interp_test.go index 84972ef46..2d52e0316 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -2728,3 +2728,35 @@ func TestRunnerEnvNoModify(t *testing.T) { t.Fatalf("\nwant: %q\ngot: %q", want, got) } } + +func TestMalformedPathOnWindows(t *testing.T) { + if runtime.GOOS != "windows" { + t.Skip("Skipping windows test on non-windows GOOS") + } + dir, err := ioutil.TempDir("", "interp-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + path := filepath.Join(dir, "test.cmd") + script := []byte("@echo foo") + if err := ioutil.WriteFile(path, script, 0777); err != nil { + t.Fatal(err) + } + + // set PATH to c:\tmp\dir instead of C:\tmp\dir + volume := filepath.VolumeName(dir) + pathList := strings.ToLower(volume) + dir[len(volume):] + + file, _ := syntax.NewParser().Parse(strings.NewReader("test.cmd"), "") + var cb concBuffer + r, _ := New(Env(expand.ListEnviron("PATH="+pathList)), StdIO(nil, &cb, &cb)) + if err := r.Run(context.Background(), file); err != nil { + t.Fatal(err) + } + want := "foo\r\n" + if got := cb.String(); got != want { + t.Fatalf("wrong output:\nwant: %q\ngot: %q", want, got) + } +}