ソースを参照

windows: change Readlink to handle junction

Related issue golang/go#10150

Change-Id: I38e3e13238624655bb828d501bc865ff8a4312e9
Reviewed-on: https://go-review.googlesource.com/7493
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Yasuhiro Matsumoto 10 年 前
コミット
61f8ff32f5
2 ファイル変更33 行追加11 行削除
  1. 14 5
      windows/syscall_windows.go
  2. 19 6
      windows/ztypes_windows.go

+ 14 - 5
windows/syscall_windows.go

@@ -962,13 +962,22 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	}
 
 	rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
-	if uintptr(bytesReturned) < unsafe.Sizeof(*rdb) ||
-		rdb.ReparseTag != IO_REPARSE_TAG_SYMLINK {
-		// the path is not a symlink but another type of reparse point
+	var s string
+	switch rdb.ReparseTag {
+	case IO_REPARSE_TAG_SYMLINK:
+		data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
+		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
+		s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+	case IO_REPARSE_TAG_MOUNT_POINT:
+		data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
+		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
+		s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+	default:
+		// the path is not a symlink or junction but another type of reparse
+		// point
 		return -1, syscall.ENOENT
 	}
-
-	s := UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rdb.PathBuffer[0]))[:rdb.PrintNameLength/2])
 	n = copy(buf, []byte(s))
+
 	return n, nil
 }

+ 19 - 6
windows/ztypes_windows.go

@@ -1089,12 +1089,7 @@ type TCPKeepalive struct {
 	Interval uint32
 }
 
-type reparseDataBuffer struct {
-	ReparseTag        uint32
-	ReparseDataLength uint16
-	Reserved          uint16
-
-	// SymbolicLinkReparseBuffer
+type symbolicLinkReparseBuffer struct {
 	SubstituteNameOffset uint16
 	SubstituteNameLength uint16
 	PrintNameOffset      uint16
@@ -1103,9 +1098,27 @@ type reparseDataBuffer struct {
 	PathBuffer           [1]uint16
 }
 
+type mountPointReparseBuffer struct {
+	SubstituteNameOffset uint16
+	SubstituteNameLength uint16
+	PrintNameOffset      uint16
+	PrintNameLength      uint16
+	PathBuffer           [1]uint16
+}
+
+type reparseDataBuffer struct {
+	ReparseTag        uint32
+	ReparseDataLength uint16
+	Reserved          uint16
+
+	// GenericReparseBuffer
+	reparseBuffer byte
+}
+
 const (
 	FSCTL_GET_REPARSE_POINT          = 0x900A8
 	MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024
+	IO_REPARSE_TAG_MOUNT_POINT       = 0xA0000003
 	IO_REPARSE_TAG_SYMLINK           = 0xA000000C
 	SYMBOLIC_LINK_FLAG_DIRECTORY     = 0x1
 )