syscall: ensure Mkdir(path) on Plan 9 fails if path exists

On Plan 9, the underlying create() syscall with DMDIR flag, which is
used to implement Mkdir, will fail silently if the path exists and
is not a directory.  Work around this by checking for existence
first and rejecting Mkdir with error EEXIST if the path is found.

Fixes #23918

Change-Id: I439115662307923c9f498d3e7b1f32c6d205e1ad
Reviewed-on: https://go-review.googlesource.com/94777
Reviewed-by: David du Colombier <0intro@gmail.com>
diff --git a/src/os/stat_plan9.go b/src/os/stat_plan9.go
index 8057fd4..15999c0 100644
--- a/src/os/stat_plan9.go
+++ b/src/os/stat_plan9.go
@@ -9,7 +9,7 @@
 	"time"
 )
 
-const _BIT16SZ = 2
+const bitSize16 = 2
 
 func fileInfoFromStat(d *syscall.Dir) FileInfo {
 	fs := &fileStat{
@@ -46,7 +46,7 @@
 	size := syscall.STATFIXLEN + 16*4
 
 	for i := 0; i < 2; i++ {
-		buf := make([]byte, _BIT16SZ+size)
+		buf := make([]byte, bitSize16+size)
 
 		var n int
 		switch a := arg.(type) {
@@ -60,7 +60,7 @@
 			panic("phase error in dirstat")
 		}
 
-		if n < _BIT16SZ {
+		if n < bitSize16 {
 			return nil, &PathError{"stat", name, err}
 		}
 
diff --git a/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go
index 12b61ee..7595126 100644
--- a/src/syscall/syscall_plan9.go
+++ b/src/syscall/syscall_plan9.go
@@ -14,6 +14,7 @@
 import "unsafe"
 
 const ImplementsGetwd = true
+const bitSize16 = 2
 
 // ErrorString implements Error's String method by returning itself.
 type ErrorString string
@@ -164,6 +165,20 @@
 }
 
 func Mkdir(path string, mode uint32) (err error) {
+	// If path exists and is not a directory, Create will fail silently.
+	// Work around this by rejecting Mkdir if path exists.
+	statbuf := make([]byte, bitSize16)
+	// Remove any trailing slashes from path, otherwise the Stat will
+	// fail with ENOTDIR.
+	n := len(path)
+	for n > 1 && path[n-1] == '/' {
+		n--
+	}
+	_, err = Stat(path[0:n], statbuf)
+	if err == nil {
+		return EEXIST
+	}
+
 	fd, err := Create(path, O_RDONLY, DMDIR|mode)
 
 	if fd != -1 {