os: do not report ModeDir for symlinks on windows

When using Lstat against symlinks that point to a directory,
the function returns FileInfo with both ModeDir and ModeSymlink set.
Change that to never set ModeDir if ModeSymlink is set.

Fixes #10424
Fixes #17540
Fixes #17541

Change-Id: Iba280888aad108360b8c1f18180a24493fe7ad2b
Reviewed-on: https://go-review.googlesource.com/41830
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/archive/tar/tar_test.go b/src/archive/tar/tar_test.go
index 10a16dd..1cb7ec2 100644
--- a/src/archive/tar/tar_test.go
+++ b/src/archive/tar/tar_test.go
@@ -12,7 +12,6 @@
 	"path"
 	"path/filepath"
 	"reflect"
-	"runtime"
 	"strings"
 	"testing"
 	"time"
@@ -72,9 +71,6 @@
 func TestFileInfoHeaderSymlink(t *testing.T) {
 	testenv.MustHaveSymlink(t)
 
-	if runtime.GOOS == "windows" {
-		t.Skip("skipping broken test: see issue 17541")
-	}
 	tmpdir, err := ioutil.TempDir("", "TestFileInfoHeaderSymlink")
 	if err != nil {
 		t.Fatal(err)
diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go
index 3e82f69..84066de 100644
--- a/src/os/os_windows_test.go
+++ b/src/os/os_windows_test.go
@@ -153,6 +153,20 @@
 			t.Errorf("%q should point to %q", link, dir)
 			continue
 		}
+
+		fi2, err := os.Lstat(link)
+		if err != nil {
+			t.Errorf("failed to lstat link %v: %v", link, err)
+			continue
+		}
+		if m := fi2.Mode(); m&os.ModeSymlink == 0 {
+			t.Errorf("%q should be a link, but is not (mode=0x%x)", link, uint32(m))
+			continue
+		}
+		if m := fi2.Mode(); m&os.ModeDir != 0 {
+			t.Errorf("%q should be a link, not a directory (mode=0x%x)", link, uint32(m))
+			continue
+		}
 	}
 }
 
diff --git a/src/os/types_windows.go b/src/os/types_windows.go
index 772b9e5..a0d6fa4 100644
--- a/src/os/types_windows.go
+++ b/src/os/types_windows.go
@@ -32,16 +32,16 @@
 	if fs == &devNullStat {
 		return ModeDevice | ModeCharDevice | 0666
 	}
-	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
-		m |= ModeDir | 0111
-	}
 	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
 		m |= 0444
 	} else {
 		m |= 0666
 	}
 	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
-		m |= ModeSymlink
+		return m | ModeSymlink
+	}
+	if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
+		m |= ModeDir | 0111
 	}
 	switch fs.filetype {
 	case syscall.FILE_TYPE_PIPE:
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index d2a78f5..315f61e 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -1377,8 +1377,5 @@
 
 func TestWalkSymlink(t *testing.T) {
 	testenv.MustHaveSymlink(t)
-	if runtime.GOOS == "windows" {
-		t.Skip("skipping broken test: see issue 17540")
-	}
 	testWalkSymlink(t, os.Symlink)
 }
diff --git a/src/path/filepath/path_windows_test.go b/src/path/filepath/path_windows_test.go
index 0663778..d759a83 100644
--- a/src/path/filepath/path_windows_test.go
+++ b/src/path/filepath/path_windows_test.go
@@ -451,12 +451,10 @@
 
 func TestWalkDirectoryJunction(t *testing.T) {
 	testenv.MustHaveSymlink(t)
-	t.Skip("skipping broken test: see issue 10424")
 	testWalkMklink(t, "J")
 }
 
 func TestWalkDirectorySymlink(t *testing.T) {
 	testenv.MustHaveSymlink(t)
-	t.Skip("skipping broken test: see issue 17540")
 	testWalkMklink(t, "D")
 }