From e65bce7144dbced232df8842ef6825d7e45f094e Mon Sep 17 00:00:00 2001 From: Hiroshi Ioka Date: Sun, 16 Oct 2016 13:25:53 +0900 Subject: os, syscall: fix incorrect offset calculation in Readlink on windows Current implementation of syscall.Readlink mistakenly calculates the end offset of the PrintName field. Also, there are some cases that the PrintName field is empty. Instead, the CL uses SubstituteName with correct calculation. Fixes #15978 Fixes #16145 Change-Id: If3257137141129ac1c552d003726d5b9c08bb754 Reviewed-on: https://go-review.googlesource.com/31118 Reviewed-by: Alex Brainman Run-TryBot: Alex Brainman TryBot-Result: Gobot Gobot --- src/syscall/syscall_windows.go | 24 ++++++++++++++++++++++-- src/syscall/ztypes_windows.go | 1 + 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'src/syscall') diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index e13d6e2dd5..f4f8f3ad09 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -1024,11 +1024,31 @@ func Readlink(path string, buf []byte) (n int, err error) { 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]) + s = UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) + if data.Flags&_SYMLINK_FLAG_RELATIVE == 0 { + if len(s) >= 4 && s[:4] == `\??\` { + s = s[4:] + switch { + case len(s) >= 2 && s[1] == ':': // \??\C:\foo\bar + // do nothing + case len(s) >= 4 && s[:4] == `UNC\`: // \??\UNC\foo\bar + s = `\\` + s[4:] + default: + // unexpected; do nothing + } + } else { + // unexpected; do nothing + } + } 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]) + s = UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2]) + if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar + s = s[4:] + } else { + // unexpected; do nothing + } default: // the path is not a symlink or junction but another type of reparse // point diff --git a/src/syscall/ztypes_windows.go b/src/syscall/ztypes_windows.go index 8c2e19653a..1fb6f5c29f 100644 --- a/src/syscall/ztypes_windows.go +++ b/src/syscall/ztypes_windows.go @@ -1116,4 +1116,5 @@ const ( _IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003 IO_REPARSE_TAG_SYMLINK = 0xA000000C SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1 + _SYMLINK_FLAG_RELATIVE = 1 ) -- cgit v1.3