mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-31 16:13:45 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			113 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			113 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
|    Copyright The containerd Authors.
 | |
| 
 | |
|    Licensed under the Apache License, Version 2.0 (the "License");
 | |
|    you may not use this file except in compliance with the License.
 | |
|    You may obtain a copy of the License at
 | |
| 
 | |
|        http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
|    Unless required by applicable law or agreed to in writing, software
 | |
|    distributed under the License is distributed on an "AS IS" BASIS,
 | |
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|    See the License for the specific language governing permissions and
 | |
|    limitations under the License.
 | |
| */
 | |
| 
 | |
| package syscallx
 | |
| 
 | |
| import (
 | |
| 	"syscall"
 | |
| 	"unsafe"
 | |
| )
 | |
| 
 | |
| type reparseDataBuffer struct {
 | |
| 	ReparseTag        uint32
 | |
| 	ReparseDataLength uint16
 | |
| 	Reserved          uint16
 | |
| 
 | |
| 	// GenericReparseBuffer
 | |
| 	reparseBuffer byte
 | |
| }
 | |
| 
 | |
| type mountPointReparseBuffer struct {
 | |
| 	SubstituteNameOffset uint16
 | |
| 	SubstituteNameLength uint16
 | |
| 	PrintNameOffset      uint16
 | |
| 	PrintNameLength      uint16
 | |
| 	PathBuffer           [1]uint16
 | |
| }
 | |
| 
 | |
| type symbolicLinkReparseBuffer struct {
 | |
| 	SubstituteNameOffset uint16
 | |
| 	SubstituteNameLength uint16
 | |
| 	PrintNameOffset      uint16
 | |
| 	PrintNameLength      uint16
 | |
| 	Flags                uint32
 | |
| 	PathBuffer           [1]uint16
 | |
| }
 | |
| 
 | |
| const (
 | |
| 	_IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
 | |
| 	_SYMLINK_FLAG_RELATIVE      = 1
 | |
| )
 | |
| 
 | |
| // Readlink returns the destination of the named symbolic link.
 | |
| func Readlink(path string, buf []byte) (n int, err error) {
 | |
| 	fd, err := syscall.CreateFile(syscall.StringToUTF16Ptr(path), syscall.GENERIC_READ, 0, nil, syscall.OPEN_EXISTING,
 | |
| 		syscall.FILE_FLAG_OPEN_REPARSE_POINT|syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
 | |
| 	if err != nil {
 | |
| 		return -1, err
 | |
| 	}
 | |
| 	defer syscall.CloseHandle(fd)
 | |
| 
 | |
| 	rdbbuf := make([]byte, syscall.MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
 | |
| 	var bytesReturned uint32
 | |
| 	err = syscall.DeviceIoControl(fd, syscall.FSCTL_GET_REPARSE_POINT, nil, 0, &rdbbuf[0], uint32(len(rdbbuf)), &bytesReturned, nil)
 | |
| 	if err != nil {
 | |
| 		return -1, err
 | |
| 	}
 | |
| 
 | |
| 	rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
 | |
| 	var s string
 | |
| 	switch rdb.ReparseTag {
 | |
| 	case syscall.IO_REPARSE_TAG_SYMLINK:
 | |
| 		data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
 | |
| 		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
 | |
| 		s = syscall.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 = syscall.UTF16ToString(p[data.SubstituteNameOffset/2 : (data.SubstituteNameOffset+data.SubstituteNameLength)/2])
 | |
| 		if len(s) >= 4 && s[:4] == `\??\` { // \??\C:\foo\bar
 | |
| 			if len(s) < 48 || s[:11] != `\??\Volume{` {
 | |
| 				s = s[4:]
 | |
| 			}
 | |
| 		} else {
 | |
| 			// unexpected; do nothing
 | |
| 		}
 | |
| 	default:
 | |
| 		// the path is not a symlink or junction but another type of reparse
 | |
| 		// point
 | |
| 		return -1, syscall.ENOENT
 | |
| 	}
 | |
| 	n = copy(buf, []byte(s))
 | |
| 
 | |
| 	return n, nil
 | |
| }
 | 
