/
conversion.go
156 lines (135 loc) · 5.13 KB
/
conversion.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package internal
// This file contains helpers to convert from public-facing to internal structs.
import (
"golang.org/x/sys/windows"
"github.com/pkg/errors"
iscsidsc "github.com/wk8/go-win-iscsidsc"
)
// CheckAndConvertLoginOptions translates the user-facing `LoginOptions` struct
// into the internal `LoginOptions` struct that the syscalls expect.
// Note that this latter struct contains two `uintptr`s that map to `PUCHAR`s on the
// C++ side, which means they need to be converted to unsafe pointers in a safe way;
// we achieve that by taking advantage of converting them to unsafe pointers as part
// of a function call's argument lists.
// See https://golang.org/pkg/unsafe/#Pointer (point 4) for more info.
func CheckAndConvertLoginOptions(optsIn *iscsidsc.LoginOptions) (opts *LoginOptions, userNamePtr, passwordPtr *byte, err error) {
if optsIn == nil {
optsIn = &iscsidsc.LoginOptions{}
}
opts = &LoginOptions{
// that one must always be the same as per Windows' doc
Version: LoginOptionsVersion,
LoginFlags: optsIn.LoginFlags,
}
if optsIn.AuthType != nil {
opts.AuthType = *optsIn.AuthType
opts.InformationSpecified |= InformationSpecifiedAuthType
}
if optsIn.HeaderDigest != nil {
opts.HeaderDigest = *optsIn.HeaderDigest
opts.InformationSpecified |= InformationSpecifiedHeaderDigest
}
if optsIn.DataDigest != nil {
opts.DataDigest = *optsIn.DataDigest
opts.InformationSpecified |= InformationSpecifiedDataDigest
}
if optsIn.MaximumConnections != nil {
opts.MaximumConnections = *optsIn.MaximumConnections
opts.InformationSpecified |= InformationSpecifiedMaximumConnections
}
if optsIn.DefaultTime2Wait != nil {
opts.DefaultTime2Wait = *optsIn.DefaultTime2Wait
opts.InformationSpecified |= InformationSpecifiedDefaultTime2Wait
}
if optsIn.DefaultTime2Retain != nil {
opts.DefaultTime2Retain = *optsIn.DefaultTime2Retain
opts.InformationSpecified |= InformationSpecifiedDefaultTime2Retain
}
if optsIn.Username != nil {
userNamePtr, err = windows.BytePtrFromString(*optsIn.Username)
if err != nil {
err = errors.Wrapf(err, "invalid username: %q", *optsIn.Username)
return
}
opts.UsernameLength = uint32(len(*optsIn.Username))
opts.InformationSpecified |= InformationSpecifiedUsername
}
if optsIn.Password != nil {
passwordPtr, err = windows.BytePtrFromString(*optsIn.Password)
if err != nil {
err = errors.Wrapf(err, "invalid password: %q", *optsIn.Username)
return
}
opts.PasswordLength = uint32(len(*optsIn.Password))
opts.InformationSpecified |= InformationSpecifiedPassword
}
return
}
// CheckAndConvertPortal translates the user-facing `Portal` struct
// into the internal `Portal` struct that the syscalls expect.
func CheckAndConvertPortal(ptlIn *iscsidsc.Portal) (*Portal, error) {
if ptlIn == nil {
return nil, nil
}
ptl := &Portal{}
symbolicNameRunes, err := windows.UTF16FromString(ptlIn.SymbolicName)
if err != nil {
return nil, errors.Wrapf(err, "invalid portal name: %q", ptlIn.SymbolicName)
}
var symbolicName [MaxIscsiPortalNameLen]uint16
if n := copy(symbolicName[:], symbolicNameRunes); n == MaxIscsiPortalNameLen {
return nil, errors.Errorf("portal name too long, cannot be more than %d characters", MaxIscsiPortalNameLen)
}
ptl.SymbolicName = symbolicName
addressRunes, err := windows.UTF16FromString(ptlIn.Address)
if err != nil {
return nil, errors.Wrapf(err, "invalid portal address: %q", ptlIn.Address)
}
var address [MaxIscsiPortalAddressLen]uint16
if n := copy(address[:], addressRunes); n == MaxIscsiPortalAddressLen {
return nil, errors.Errorf("portal address too long, cannot be more than %d characters", MaxIscsiPortalAddressLen)
}
ptl.Address = address
if ptlIn.Socket == nil {
ptl.Socket = DefaultPortalPortNumber
} else {
ptl.Socket = *ptlIn.Socket
}
return ptl, nil
}
// ConvertInitiatorArgs converts user-facing initiator arguments to internal
// types compatible with Windows' API.
func ConvertInitiatorArgs(initiatorInstance *string, initiatorPortNumber *uint32) (*uint16, uint32, error) {
var (
initiatorInstancePtr *uint16
err error
)
if initiatorInstance != nil {
initiatorInstancePtr, err = windows.UTF16PtrFromString(*initiatorInstance)
if err != nil {
return nil, 0, errors.Wrapf(err, "invalid initiatorInstance argument: %q", *initiatorInstance)
}
}
return initiatorInstancePtr, ConvertInitiatorPortNumber(initiatorPortNumber), nil
}
// ConvertInitiatorPortNumber converts the user-facing initiatorPortNumber
// to an internal type compatible with Windows' API.
func ConvertInitiatorPortNumber(initiatorPortNumber *uint32) uint32 {
initiatorPortNumberValue := AllInititatorPorts
if initiatorPortNumber != nil {
initiatorPortNumberValue = *initiatorPortNumber
}
return initiatorPortNumberValue
}
// CheckAndConvertKey converts the user-facing key argument, common to several
// procs, into internal types compatible with Windows' API.
func CheckAndConvertKey(key *string) (keyPtr *byte, keySize uint32, err error) {
if key != nil {
if keyPtr, err = windows.BytePtrFromString(*key); err != nil {
err = errors.Wrapf(err, "invalid key: %q", *key)
return
}
keySize = uint32(len(*key))
}
return
}