Skip to content

Commit

Permalink
interp: support lowercase volume names in $PATH
Browse files Browse the repository at this point in the history
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 mvdan#355.
  • Loading branch information
mvdan committed Feb 2, 2019
1 parent ecd349c commit 06ba6a9
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
7 changes: 5 additions & 2 deletions interp/interp.go
Original file line number Diff line number Diff line change
Expand Up @@ -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]:[/\].
Expand All @@ -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:
Expand Down
32 changes: 32 additions & 0 deletions interp/interp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

0 comments on commit 06ba6a9

Please sign in to comment.