1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package windows
6
7import (
8	"syscall"
9	"unsafe"
10)
11
12// Reparse tag values are taken from
13// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/c8e77b37-3909-4fe6-a4ea-2b9d423b1ee4
14const (
15	FSCTL_SET_REPARSE_POINT    = 0x000900A4
16	IO_REPARSE_TAG_MOUNT_POINT = 0xA0000003
17	IO_REPARSE_TAG_DEDUP       = 0x80000013
18	IO_REPARSE_TAG_AF_UNIX     = 0x80000023
19
20	SYMLINK_FLAG_RELATIVE = 1
21)
22
23// These structures are described
24// in https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ca069dad-ed16-42aa-b057-b6b207f447cc
25// and https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/b41f1cbf-10df-4a47-98d4-1c52a833d913.
26
27type REPARSE_DATA_BUFFER struct {
28	ReparseTag        uint32
29	ReparseDataLength uint16
30	Reserved          uint16
31	DUMMYUNIONNAME    byte
32}
33
34// REPARSE_DATA_BUFFER_HEADER is a common part of REPARSE_DATA_BUFFER structure.
35type REPARSE_DATA_BUFFER_HEADER struct {
36	ReparseTag uint32
37	// The size, in bytes, of the reparse data that follows
38	// the common portion of the REPARSE_DATA_BUFFER element.
39	// This value is the length of the data starting at the
40	// SubstituteNameOffset field.
41	ReparseDataLength uint16
42	Reserved          uint16
43}
44
45type SymbolicLinkReparseBuffer struct {
46	// The integer that contains the offset, in bytes,
47	// of the substitute name string in the PathBuffer array,
48	// computed as an offset from byte 0 of PathBuffer. Note that
49	// this offset must be divided by 2 to get the array index.
50	SubstituteNameOffset uint16
51	// The integer that contains the length, in bytes, of the
52	// substitute name string. If this string is null-terminated,
53	// SubstituteNameLength does not include the Unicode null character.
54	SubstituteNameLength uint16
55	// PrintNameOffset is similar to SubstituteNameOffset.
56	PrintNameOffset uint16
57	// PrintNameLength is similar to SubstituteNameLength.
58	PrintNameLength uint16
59	// Flags specifies whether the substitute name is a full path name or
60	// a path name relative to the directory containing the symbolic link.
61	Flags      uint32
62	PathBuffer [1]uint16
63}
64
65// Path returns path stored in rb.
66func (rb *SymbolicLinkReparseBuffer) Path() string {
67	n1 := rb.SubstituteNameOffset / 2
68	n2 := (rb.SubstituteNameOffset + rb.SubstituteNameLength) / 2
69	return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rb.PathBuffer[0]))[n1:n2:n2])
70}
71
72type MountPointReparseBuffer struct {
73	// The integer that contains the offset, in bytes,
74	// of the substitute name string in the PathBuffer array,
75	// computed as an offset from byte 0 of PathBuffer. Note that
76	// this offset must be divided by 2 to get the array index.
77	SubstituteNameOffset uint16
78	// The integer that contains the length, in bytes, of the
79	// substitute name string. If this string is null-terminated,
80	// SubstituteNameLength does not include the Unicode null character.
81	SubstituteNameLength uint16
82	// PrintNameOffset is similar to SubstituteNameOffset.
83	PrintNameOffset uint16
84	// PrintNameLength is similar to SubstituteNameLength.
85	PrintNameLength uint16
86	PathBuffer      [1]uint16
87}
88
89// Path returns path stored in rb.
90func (rb *MountPointReparseBuffer) Path() string {
91	n1 := rb.SubstituteNameOffset / 2
92	n2 := (rb.SubstituteNameOffset + rb.SubstituteNameLength) / 2
93	return syscall.UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rb.PathBuffer[0]))[n1:n2:n2])
94}
95