From 61f8ff32f5e9372236621fb57c9e280095ce0a58 Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Fri, 13 Mar 2015 12:23:52 +0900 Subject: [PATCH] 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 --- windows/syscall_windows.go | 19 ++++++++++++++----- windows/ztypes_windows.go | 25 +++++++++++++++++++------ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/windows/syscall_windows.go b/windows/syscall_windows.go index 0b512dfd..4256f453 100644 --- a/windows/syscall_windows.go +++ b/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 } diff --git a/windows/ztypes_windows.go b/windows/ztypes_windows.go index 5d61194c..ee669ab9 100644 --- a/windows/ztypes_windows.go +++ b/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 )