Blame


1 e342de7d 2015-11-11 adrien package p9p
2 e342de7d 2015-11-11 adrien
3 e342de7d 2015-11-11 adrien import (
4 e342de7d 2015-11-11 adrien "bytes"
5 e342de7d 2015-11-11 adrien "encoding/binary"
6 e342de7d 2015-11-11 adrien "fmt"
7 e342de7d 2015-11-11 adrien "io"
8 e342de7d 2015-11-11 adrien "log"
9 e342de7d 2015-11-11 adrien "reflect"
10 e342de7d 2015-11-11 adrien "strings"
11 e342de7d 2015-11-11 adrien "time"
12 e342de7d 2015-11-11 adrien )
13 e342de7d 2015-11-11 adrien
14 e342de7d 2015-11-11 adrien // Codec defines the interface for encoding and decoding of 9p types.
15 e342de7d 2015-11-11 adrien // Unsupported types will throw an error.
16 e342de7d 2015-11-11 adrien type Codec interface {
17 e342de7d 2015-11-11 adrien // Unmarshal from data into the value pointed to by v.
18 e342de7d 2015-11-11 adrien Unmarshal(data []byte, v interface{}) error
19 e342de7d 2015-11-11 adrien
20 e342de7d 2015-11-11 adrien // Marshal the value v into a byte slice.
21 e342de7d 2015-11-11 adrien Marshal(v interface{}) ([]byte, error)
22 e342de7d 2015-11-11 adrien
23 e342de7d 2015-11-11 adrien // Size returns the encoded size for the target of v.
24 e342de7d 2015-11-11 adrien Size(v interface{}) int
25 e342de7d 2015-11-11 adrien }
26 e342de7d 2015-11-11 adrien
27 e342de7d 2015-11-11 adrien func NewCodec() Codec {
28 e342de7d 2015-11-11 adrien return codec9p{}
29 e342de7d 2015-11-11 adrien }
30 e342de7d 2015-11-11 adrien
31 e342de7d 2015-11-11 adrien type codec9p struct{}
32 e342de7d 2015-11-11 adrien
33 e342de7d 2015-11-11 adrien func (c codec9p) Unmarshal(data []byte, v interface{}) error {
34 e342de7d 2015-11-11 adrien dec := &decoder{bytes.NewReader(data)}
35 e342de7d 2015-11-11 adrien return dec.decode(v)
36 e342de7d 2015-11-11 adrien }
37 e342de7d 2015-11-11 adrien
38 e342de7d 2015-11-11 adrien func (c codec9p) Marshal(v interface{}) ([]byte, error) {
39 e342de7d 2015-11-11 adrien var b bytes.Buffer
40 e342de7d 2015-11-11 adrien enc := &encoder{&b}
41 e342de7d 2015-11-11 adrien
42 e342de7d 2015-11-11 adrien if err := enc.encode(v); err != nil {
43 e342de7d 2015-11-11 adrien return nil, err
44 e342de7d 2015-11-11 adrien }
45 e342de7d 2015-11-11 adrien
46 e342de7d 2015-11-11 adrien return b.Bytes(), nil
47 e342de7d 2015-11-11 adrien }
48 e342de7d 2015-11-11 adrien
49 e342de7d 2015-11-11 adrien func (c codec9p) Size(v interface{}) int {
50 e342de7d 2015-11-11 adrien return int(size9p(v))
51 e342de7d 2015-11-11 adrien }
52 e342de7d 2015-11-11 adrien
53 e342de7d 2015-11-11 adrien // DecodeDir decodes a directory entry from rd using the provided codec.
54 e342de7d 2015-11-11 adrien func DecodeDir(codec Codec, rd io.Reader, d *Dir) error {
55 e342de7d 2015-11-11 adrien var ll uint16
56 e342de7d 2015-11-11 adrien
57 e342de7d 2015-11-11 adrien // pull the size off the wire
58 e342de7d 2015-11-11 adrien if err := binary.Read(rd, binary.LittleEndian, &ll); err != nil {
59 e342de7d 2015-11-11 adrien return err
60 e342de7d 2015-11-11 adrien }
61 e342de7d 2015-11-11 adrien
62 e342de7d 2015-11-11 adrien p := make([]byte, ll+2)
63 e342de7d 2015-11-11 adrien binary.LittleEndian.PutUint16(p, ll) // must have size at start
64 e342de7d 2015-11-11 adrien
65 e342de7d 2015-11-11 adrien // read out the rest of the record
66 e342de7d 2015-11-11 adrien if _, err := io.ReadFull(rd, p[2:]); err != nil {
67 e342de7d 2015-11-11 adrien return err
68 e342de7d 2015-11-11 adrien }
69 e342de7d 2015-11-11 adrien
70 e342de7d 2015-11-11 adrien return codec.Unmarshal(p, d)
71 e342de7d 2015-11-11 adrien }
72 e342de7d 2015-11-11 adrien
73 e342de7d 2015-11-11 adrien // EncodeDir writes the directory to wr.
74 e342de7d 2015-11-11 adrien func EncodeDir(codec Codec, wr io.Writer, d *Dir) error {
75 e342de7d 2015-11-11 adrien p, err := codec.Marshal(d)
76 e342de7d 2015-11-11 adrien if err != nil {
77 e342de7d 2015-11-11 adrien return err
78 e342de7d 2015-11-11 adrien }
79 e342de7d 2015-11-11 adrien
80 e342de7d 2015-11-11 adrien _, err = wr.Write(p)
81 e342de7d 2015-11-11 adrien return err
82 e342de7d 2015-11-11 adrien }
83 e342de7d 2015-11-11 adrien
84 e342de7d 2015-11-11 adrien type encoder struct {
85 e342de7d 2015-11-11 adrien wr io.Writer
86 e342de7d 2015-11-11 adrien }
87 e342de7d 2015-11-11 adrien
88 e342de7d 2015-11-11 adrien func (e *encoder) encode(vs ...interface{}) error {
89 e342de7d 2015-11-11 adrien for _, v := range vs {
90 e342de7d 2015-11-11 adrien switch v := v.(type) {
91 e342de7d 2015-11-11 adrien case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
92 e342de7d 2015-11-11 adrien *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
93 e342de7d 2015-11-11 adrien if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
94 e342de7d 2015-11-11 adrien return err
95 e342de7d 2015-11-11 adrien }
96 e342de7d 2015-11-11 adrien case []byte:
97 e342de7d 2015-11-11 adrien if err := e.encode(uint32(len(v))); err != nil {
98 e342de7d 2015-11-11 adrien return err
99 e342de7d 2015-11-11 adrien }
100 e342de7d 2015-11-11 adrien
101 e342de7d 2015-11-11 adrien if err := binary.Write(e.wr, binary.LittleEndian, v); err != nil {
102 e342de7d 2015-11-11 adrien return err
103 e342de7d 2015-11-11 adrien }
104 e342de7d 2015-11-11 adrien
105 e342de7d 2015-11-11 adrien case *[]byte:
106 e342de7d 2015-11-11 adrien if err := e.encode(*v); err != nil {
107 e342de7d 2015-11-11 adrien return err
108 e342de7d 2015-11-11 adrien }
109 e342de7d 2015-11-11 adrien case string:
110 e342de7d 2015-11-11 adrien if err := binary.Write(e.wr, binary.LittleEndian, uint16(len(v))); err != nil {
111 e342de7d 2015-11-11 adrien return err
112 e342de7d 2015-11-11 adrien }
113 e342de7d 2015-11-11 adrien
114 e342de7d 2015-11-11 adrien _, err := io.WriteString(e.wr, v)
115 e342de7d 2015-11-11 adrien if err != nil {
116 e342de7d 2015-11-11 adrien return err
117 e342de7d 2015-11-11 adrien }
118 e342de7d 2015-11-11 adrien case *string:
119 e342de7d 2015-11-11 adrien if err := e.encode(*v); err != nil {
120 e342de7d 2015-11-11 adrien return err
121 e342de7d 2015-11-11 adrien }
122 e342de7d 2015-11-11 adrien
123 e342de7d 2015-11-11 adrien case []string:
124 e342de7d 2015-11-11 adrien if err := e.encode(uint16(len(v))); err != nil {
125 e342de7d 2015-11-11 adrien return err
126 e342de7d 2015-11-11 adrien }
127 e342de7d 2015-11-11 adrien
128 e342de7d 2015-11-11 adrien for _, m := range v {
129 e342de7d 2015-11-11 adrien if err := e.encode(m); err != nil {
130 e342de7d 2015-11-11 adrien return err
131 e342de7d 2015-11-11 adrien }
132 e342de7d 2015-11-11 adrien }
133 e342de7d 2015-11-11 adrien case *[]string:
134 e342de7d 2015-11-11 adrien if err := e.encode(*v); err != nil {
135 e342de7d 2015-11-11 adrien return err
136 e342de7d 2015-11-11 adrien }
137 e342de7d 2015-11-11 adrien case time.Time:
138 e342de7d 2015-11-11 adrien if err := e.encode(uint32(v.Unix())); err != nil {
139 e342de7d 2015-11-11 adrien return err
140 e342de7d 2015-11-11 adrien }
141 e342de7d 2015-11-11 adrien case *time.Time:
142 e342de7d 2015-11-11 adrien if err := e.encode(*v); err != nil {
143 e342de7d 2015-11-11 adrien return err
144 e342de7d 2015-11-11 adrien }
145 e342de7d 2015-11-11 adrien case Qid:
146 e342de7d 2015-11-11 adrien if err := e.encode(v.Type, v.Version, v.Path); err != nil {
147 e342de7d 2015-11-11 adrien return err
148 e342de7d 2015-11-11 adrien }
149 e342de7d 2015-11-11 adrien case *Qid:
150 e342de7d 2015-11-11 adrien if err := e.encode(*v); err != nil {
151 e342de7d 2015-11-11 adrien return err
152 e342de7d 2015-11-11 adrien }
153 e342de7d 2015-11-11 adrien case []Qid:
154 e342de7d 2015-11-11 adrien if err := e.encode(uint16(len(v))); err != nil {
155 e342de7d 2015-11-11 adrien return err
156 e342de7d 2015-11-11 adrien }
157 e342de7d 2015-11-11 adrien
158 e342de7d 2015-11-11 adrien elements := make([]interface{}, len(v))
159 e342de7d 2015-11-11 adrien for i := range v {
160 e342de7d 2015-11-11 adrien elements[i] = &v[i]
161 e342de7d 2015-11-11 adrien }
162 e342de7d 2015-11-11 adrien
163 e342de7d 2015-11-11 adrien if err := e.encode(elements...); err != nil {
164 e342de7d 2015-11-11 adrien return err
165 e342de7d 2015-11-11 adrien }
166 e342de7d 2015-11-11 adrien case *[]Qid:
167 e342de7d 2015-11-11 adrien if err := e.encode(*v); err != nil {
168 e342de7d 2015-11-11 adrien return err
169 e342de7d 2015-11-11 adrien }
170 e342de7d 2015-11-11 adrien case Dir:
171 e342de7d 2015-11-11 adrien elements, err := fields9p(v)
172 e342de7d 2015-11-11 adrien if err != nil {
173 e342de7d 2015-11-11 adrien return err
174 e342de7d 2015-11-11 adrien }
175 e342de7d 2015-11-11 adrien
176 e342de7d 2015-11-11 adrien if err := e.encode(uint16(size9p(elements...))); err != nil {
177 e342de7d 2015-11-11 adrien return err
178 e342de7d 2015-11-11 adrien }
179 e342de7d 2015-11-11 adrien
180 e342de7d 2015-11-11 adrien if err := e.encode(elements...); err != nil {
181 e342de7d 2015-11-11 adrien return err
182 e342de7d 2015-11-11 adrien }
183 e342de7d 2015-11-11 adrien case *Dir:
184 e342de7d 2015-11-11 adrien if err := e.encode(*v); err != nil {
185 e342de7d 2015-11-11 adrien return err
186 e342de7d 2015-11-11 adrien }
187 e342de7d 2015-11-11 adrien case Fcall:
188 e342de7d 2015-11-11 adrien if err := e.encode(v.Type, v.Tag, v.Message); err != nil {
189 e342de7d 2015-11-11 adrien return err
190 e342de7d 2015-11-11 adrien }
191 e342de7d 2015-11-11 adrien case *Fcall:
192 e342de7d 2015-11-11 adrien if err := e.encode(*v); err != nil {
193 e342de7d 2015-11-11 adrien return err
194 e342de7d 2015-11-11 adrien }
195 e342de7d 2015-11-11 adrien case Message:
196 e342de7d 2015-11-11 adrien elements, err := fields9p(v)
197 e342de7d 2015-11-11 adrien if err != nil {
198 e342de7d 2015-11-11 adrien return err
199 e342de7d 2015-11-11 adrien }
200 e342de7d 2015-11-11 adrien
201 e342de7d 2015-11-11 adrien switch v.(type) {
202 e342de7d 2015-11-11 adrien case MessageRstat, *MessageRstat:
203 e342de7d 2015-11-11 adrien // NOTE(stevvooe): Prepend size preceeding Dir. See bugs in
204 e342de7d 2015-11-11 adrien // http://man.cat-v.org/plan_9/5/stat to make sense of this.
205 e342de7d 2015-11-11 adrien // The field has been included here but we need to make sure
206 e342de7d 2015-11-11 adrien // to double emit it for Rstat.
207 e342de7d 2015-11-11 adrien if err := e.encode(uint16(size9p(elements...))); err != nil {
208 e342de7d 2015-11-11 adrien return err
209 e342de7d 2015-11-11 adrien }
210 e342de7d 2015-11-11 adrien }
211 e342de7d 2015-11-11 adrien
212 e342de7d 2015-11-11 adrien if err := e.encode(elements...); err != nil {
213 e342de7d 2015-11-11 adrien return err
214 e342de7d 2015-11-11 adrien }
215 e342de7d 2015-11-11 adrien }
216 e342de7d 2015-11-11 adrien }
217 e342de7d 2015-11-11 adrien
218 e342de7d 2015-11-11 adrien return nil
219 e342de7d 2015-11-11 adrien }
220 e342de7d 2015-11-11 adrien
221 e342de7d 2015-11-11 adrien type decoder struct {
222 e342de7d 2015-11-11 adrien rd io.Reader
223 e342de7d 2015-11-11 adrien }
224 e342de7d 2015-11-11 adrien
225 e342de7d 2015-11-11 adrien // read9p extracts values from rd and unmarshals them to the targets of vs.
226 e342de7d 2015-11-11 adrien func (d *decoder) decode(vs ...interface{}) error {
227 e342de7d 2015-11-11 adrien for _, v := range vs {
228 e342de7d 2015-11-11 adrien switch v := v.(type) {
229 e342de7d 2015-11-11 adrien case *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
230 e342de7d 2015-11-11 adrien if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
231 e342de7d 2015-11-11 adrien return err
232 e342de7d 2015-11-11 adrien }
233 e342de7d 2015-11-11 adrien case *[]byte:
234 e342de7d 2015-11-11 adrien var ll uint32
235 e342de7d 2015-11-11 adrien
236 e342de7d 2015-11-11 adrien if err := d.decode(&ll); err != nil {
237 e342de7d 2015-11-11 adrien return err
238 e342de7d 2015-11-11 adrien }
239 e342de7d 2015-11-11 adrien
240 e342de7d 2015-11-11 adrien *v = make([]byte, int(ll))
241 e342de7d 2015-11-11 adrien
242 e342de7d 2015-11-11 adrien if err := binary.Read(d.rd, binary.LittleEndian, v); err != nil {
243 e342de7d 2015-11-11 adrien return err
244 e342de7d 2015-11-11 adrien }
245 e342de7d 2015-11-11 adrien case *string:
246 e342de7d 2015-11-11 adrien var ll uint16
247 e342de7d 2015-11-11 adrien
248 e342de7d 2015-11-11 adrien // implement string[s] encoding
249 e342de7d 2015-11-11 adrien if err := d.decode(&ll); err != nil {
250 e342de7d 2015-11-11 adrien return err
251 e342de7d 2015-11-11 adrien }
252 e342de7d 2015-11-11 adrien
253 e342de7d 2015-11-11 adrien b := make([]byte, ll)
254 e342de7d 2015-11-11 adrien
255 e342de7d 2015-11-11 adrien n, err := io.ReadFull(d.rd, b)
256 e342de7d 2015-11-11 adrien if err != nil {
257 e342de7d 2015-11-11 adrien return err
258 e342de7d 2015-11-11 adrien }
259 e342de7d 2015-11-11 adrien
260 e342de7d 2015-11-11 adrien if n != int(ll) {
261 e342de7d 2015-11-11 adrien return fmt.Errorf("unexpected string length")
262 e342de7d 2015-11-11 adrien }
263 e342de7d 2015-11-11 adrien
264 e342de7d 2015-11-11 adrien *v = string(b)
265 e342de7d 2015-11-11 adrien case *[]string:
266 e342de7d 2015-11-11 adrien var ll uint16
267 e342de7d 2015-11-11 adrien
268 e342de7d 2015-11-11 adrien if err := d.decode(&ll); err != nil {
269 e342de7d 2015-11-11 adrien return err
270 e342de7d 2015-11-11 adrien }
271 e342de7d 2015-11-11 adrien
272 e342de7d 2015-11-11 adrien elements := make([]interface{}, int(ll))
273 e342de7d 2015-11-11 adrien *v = make([]string, int(ll))
274 e342de7d 2015-11-11 adrien for i := range elements {
275 e342de7d 2015-11-11 adrien elements[i] = &(*v)[i]
276 e342de7d 2015-11-11 adrien }
277 e342de7d 2015-11-11 adrien
278 e342de7d 2015-11-11 adrien if err := d.decode(elements...); err != nil {
279 e342de7d 2015-11-11 adrien return err
280 e342de7d 2015-11-11 adrien }
281 e342de7d 2015-11-11 adrien case *time.Time:
282 e342de7d 2015-11-11 adrien var epoch uint32
283 e342de7d 2015-11-11 adrien if err := d.decode(&epoch); err != nil {
284 e342de7d 2015-11-11 adrien return err
285 e342de7d 2015-11-11 adrien }
286 e342de7d 2015-11-11 adrien
287 e342de7d 2015-11-11 adrien *v = time.Unix(int64(epoch), 0).UTC()
288 e342de7d 2015-11-11 adrien case *Qid:
289 e342de7d 2015-11-11 adrien if err := d.decode(&v.Type, &v.Version, &v.Path); err != nil {
290 e342de7d 2015-11-11 adrien return err
291 e342de7d 2015-11-11 adrien }
292 e342de7d 2015-11-11 adrien case *[]Qid:
293 e342de7d 2015-11-11 adrien var ll uint16
294 e342de7d 2015-11-11 adrien
295 e342de7d 2015-11-11 adrien if err := d.decode(&ll); err != nil {
296 e342de7d 2015-11-11 adrien return err
297 e342de7d 2015-11-11 adrien }
298 e342de7d 2015-11-11 adrien
299 e342de7d 2015-11-11 adrien elements := make([]interface{}, int(ll))
300 e342de7d 2015-11-11 adrien *v = make([]Qid, int(ll))
301 e342de7d 2015-11-11 adrien for i := range elements {
302 e342de7d 2015-11-11 adrien elements[i] = &(*v)[i]
303 e342de7d 2015-11-11 adrien }
304 e342de7d 2015-11-11 adrien
305 e342de7d 2015-11-11 adrien if err := d.decode(elements...); err != nil {
306 e342de7d 2015-11-11 adrien return err
307 e342de7d 2015-11-11 adrien }
308 e342de7d 2015-11-11 adrien case *Dir:
309 e342de7d 2015-11-11 adrien var ll uint16
310 e342de7d 2015-11-11 adrien
311 e342de7d 2015-11-11 adrien if err := d.decode(&ll); err != nil {
312 e342de7d 2015-11-11 adrien return err
313 e342de7d 2015-11-11 adrien }
314 e342de7d 2015-11-11 adrien
315 e342de7d 2015-11-11 adrien b := make([]byte, ll)
316 e342de7d 2015-11-11 adrien // must consume entire dir entry.
317 e342de7d 2015-11-11 adrien n, err := io.ReadFull(d.rd, b)
318 e342de7d 2015-11-11 adrien if err != nil {
319 e342de7d 2015-11-11 adrien log.Println("dir readfull failed:", err, ll, n)
320 e342de7d 2015-11-11 adrien return err
321 e342de7d 2015-11-11 adrien }
322 e342de7d 2015-11-11 adrien
323 e342de7d 2015-11-11 adrien elements, err := fields9p(v)
324 e342de7d 2015-11-11 adrien if err != nil {
325 e342de7d 2015-11-11 adrien return err
326 e342de7d 2015-11-11 adrien }
327 e342de7d 2015-11-11 adrien
328 e342de7d 2015-11-11 adrien dec := &decoder{bytes.NewReader(b)}
329 e342de7d 2015-11-11 adrien
330 e342de7d 2015-11-11 adrien if err := dec.decode(elements...); err != nil {
331 e342de7d 2015-11-11 adrien return err
332 e342de7d 2015-11-11 adrien }
333 e342de7d 2015-11-11 adrien case *Fcall:
334 e342de7d 2015-11-11 adrien if err := d.decode(&v.Type, &v.Tag); err != nil {
335 e342de7d 2015-11-11 adrien return err
336 e342de7d 2015-11-11 adrien }
337 e342de7d 2015-11-11 adrien
338 e342de7d 2015-11-11 adrien message, err := newMessage(v.Type)
339 e342de7d 2015-11-11 adrien if err != nil {
340 e342de7d 2015-11-11 adrien return err
341 e342de7d 2015-11-11 adrien }
342 e342de7d 2015-11-11 adrien
343 e342de7d 2015-11-11 adrien // NOTE(stevvooe): We do a little pointer dance to allocate the
344 e342de7d 2015-11-11 adrien // new type, write to it, then assign it back to the interface as
345 e342de7d 2015-11-11 adrien // a concrete type, avoiding a pointer (the interface) to a
346 e342de7d 2015-11-11 adrien // pointer.
347 e342de7d 2015-11-11 adrien rv := reflect.New(reflect.TypeOf(message))
348 e342de7d 2015-11-11 adrien if err := d.decode(rv.Interface()); err != nil {
349 e342de7d 2015-11-11 adrien return err
350 e342de7d 2015-11-11 adrien }
351 e342de7d 2015-11-11 adrien
352 e342de7d 2015-11-11 adrien v.Message = rv.Elem().Interface().(Message)
353 e342de7d 2015-11-11 adrien case Message:
354 e342de7d 2015-11-11 adrien elements, err := fields9p(v)
355 e342de7d 2015-11-11 adrien if err != nil {
356 e342de7d 2015-11-11 adrien return err
357 e342de7d 2015-11-11 adrien }
358 e342de7d 2015-11-11 adrien
359 e342de7d 2015-11-11 adrien switch v.(type) {
360 e342de7d 2015-11-11 adrien case *MessageRstat, MessageRstat:
361 e342de7d 2015-11-11 adrien // NOTE(stevvooe): Consume extra size preceeding Dir. See bugs
362 e342de7d 2015-11-11 adrien // in http://man.cat-v.org/plan_9/5/stat to make sense of
363 e342de7d 2015-11-11 adrien // this. The field has been included here but we need to make
364 e342de7d 2015-11-11 adrien // sure to double emit it for Rstat. decode extra size header
365 e342de7d 2015-11-11 adrien // for stat structure.
366 e342de7d 2015-11-11 adrien var ll uint16
367 e342de7d 2015-11-11 adrien if err := d.decode(&ll); err != nil {
368 e342de7d 2015-11-11 adrien return err
369 e342de7d 2015-11-11 adrien }
370 e342de7d 2015-11-11 adrien }
371 e342de7d 2015-11-11 adrien
372 e342de7d 2015-11-11 adrien if err := d.decode(elements...); err != nil {
373 e342de7d 2015-11-11 adrien return err
374 e342de7d 2015-11-11 adrien }
375 e342de7d 2015-11-11 adrien }
376 e342de7d 2015-11-11 adrien }
377 e342de7d 2015-11-11 adrien
378 e342de7d 2015-11-11 adrien return nil
379 e342de7d 2015-11-11 adrien }
380 e342de7d 2015-11-11 adrien
381 e342de7d 2015-11-11 adrien // size9p calculates the projected size of the values in vs when encoded into
382 e342de7d 2015-11-11 adrien // 9p binary protocol. If an element or elements are not valid for 9p encoded,
383 e342de7d 2015-11-11 adrien // the value 0 will be used for the size. The error will be detected when
384 e342de7d 2015-11-11 adrien // encoding.
385 e342de7d 2015-11-11 adrien func size9p(vs ...interface{}) uint32 {
386 e342de7d 2015-11-11 adrien var s uint32
387 e342de7d 2015-11-11 adrien for _, v := range vs {
388 e342de7d 2015-11-11 adrien if v == nil {
389 e342de7d 2015-11-11 adrien continue
390 e342de7d 2015-11-11 adrien }
391 e342de7d 2015-11-11 adrien
392 e342de7d 2015-11-11 adrien switch v := v.(type) {
393 e342de7d 2015-11-11 adrien case uint8, uint16, uint32, uint64, FcallType, Tag, QType, Fid, Flag,
394 e342de7d 2015-11-11 adrien *uint8, *uint16, *uint32, *uint64, *FcallType, *Tag, *QType, *Fid, *Flag:
395 e342de7d 2015-11-11 adrien s += uint32(binary.Size(v))
396 e342de7d 2015-11-11 adrien case []byte:
397 e342de7d 2015-11-11 adrien s += uint32(binary.Size(uint32(0)) + len(v))
398 e342de7d 2015-11-11 adrien case *[]byte:
399 e342de7d 2015-11-11 adrien s += size9p(uint32(0), *v)
400 e342de7d 2015-11-11 adrien case string:
401 e342de7d 2015-11-11 adrien s += uint32(binary.Size(uint16(0)) + len(v))
402 e342de7d 2015-11-11 adrien case *string:
403 e342de7d 2015-11-11 adrien s += size9p(*v)
404 e342de7d 2015-11-11 adrien case []string:
405 e342de7d 2015-11-11 adrien s += size9p(uint16(0))
406 e342de7d 2015-11-11 adrien
407 e342de7d 2015-11-11 adrien for _, sv := range v {
408 e342de7d 2015-11-11 adrien s += size9p(sv)
409 e342de7d 2015-11-11 adrien }
410 e342de7d 2015-11-11 adrien case *[]string:
411 e342de7d 2015-11-11 adrien s += size9p(*v)
412 e342de7d 2015-11-11 adrien case time.Time, *time.Time:
413 e342de7d 2015-11-11 adrien // BUG(stevvooe): Y2038 is coming.
414 e342de7d 2015-11-11 adrien s += size9p(uint32(0))
415 e342de7d 2015-11-11 adrien case Qid:
416 e342de7d 2015-11-11 adrien s += size9p(v.Type, v.Version, v.Path)
417 e342de7d 2015-11-11 adrien case *Qid:
418 e342de7d 2015-11-11 adrien s += size9p(*v)
419 e342de7d 2015-11-11 adrien case []Qid:
420 e342de7d 2015-11-11 adrien s += size9p(uint16(0))
421 e342de7d 2015-11-11 adrien elements := make([]interface{}, len(v))
422 e342de7d 2015-11-11 adrien for i := range elements {
423 e342de7d 2015-11-11 adrien elements[i] = &v[i]
424 e342de7d 2015-11-11 adrien }
425 e342de7d 2015-11-11 adrien s += size9p(elements...)
426 e342de7d 2015-11-11 adrien case *[]Qid:
427 e342de7d 2015-11-11 adrien s += size9p(*v)
428 e342de7d 2015-11-11 adrien
429 e342de7d 2015-11-11 adrien case Dir:
430 e342de7d 2015-11-11 adrien // walk the fields of the message to get the total size. we just
431 e342de7d 2015-11-11 adrien // use the field order from the message struct. We may add tag
432 e342de7d 2015-11-11 adrien // ignoring if needed.
433 e342de7d 2015-11-11 adrien elements, err := fields9p(v)
434 e342de7d 2015-11-11 adrien if err != nil {
435 e342de7d 2015-11-11 adrien // BUG(stevvooe): The options here are to return 0, panic or
436 e342de7d 2015-11-11 adrien // make this return an error. Ideally, we make it safe to
437 e342de7d 2015-11-11 adrien // return 0 and have the rest of the package do the right
438 e342de7d 2015-11-11 adrien // thing. For now, we do this, but may want to panic until
439 e342de7d 2015-11-11 adrien // things are stable.
440 e342de7d 2015-11-11 adrien panic(err)
441 e342de7d 2015-11-11 adrien }
442 e342de7d 2015-11-11 adrien
443 e342de7d 2015-11-11 adrien s += size9p(elements...) + size9p(uint16(0))
444 e342de7d 2015-11-11 adrien case *Dir:
445 e342de7d 2015-11-11 adrien s += size9p(*v)
446 e342de7d 2015-11-11 adrien case Fcall:
447 e342de7d 2015-11-11 adrien s += size9p(v.Type, v.Tag, v.Message)
448 e342de7d 2015-11-11 adrien case *Fcall:
449 e342de7d 2015-11-11 adrien s += size9p(*v)
450 e342de7d 2015-11-11 adrien case Message:
451 e342de7d 2015-11-11 adrien // special case twstat and rstat for size fields. See bugs in
452 e342de7d 2015-11-11 adrien // http://man.cat-v.org/plan_9/5/stat to make sense of this.
453 e342de7d 2015-11-11 adrien switch v.(type) {
454 e342de7d 2015-11-11 adrien case *MessageRstat, MessageRstat:
455 e342de7d 2015-11-11 adrien s += size9p(uint16(0)) // for extra size field before dir
456 e342de7d 2015-11-11 adrien }
457 e342de7d 2015-11-11 adrien
458 e342de7d 2015-11-11 adrien // walk the fields of the message to get the total size. we just
459 e342de7d 2015-11-11 adrien // use the field order from the message struct. We may add tag
460 e342de7d 2015-11-11 adrien // ignoring if needed.
461 e342de7d 2015-11-11 adrien elements, err := fields9p(v)
462 e342de7d 2015-11-11 adrien if err != nil {
463 e342de7d 2015-11-11 adrien // BUG(stevvooe): The options here are to return 0, panic or
464 e342de7d 2015-11-11 adrien // make this return an error. Ideally, we make it safe to
465 e342de7d 2015-11-11 adrien // return 0 and have the rest of the package do the right
466 e342de7d 2015-11-11 adrien // thing. For now, we do this, but may want to panic until
467 e342de7d 2015-11-11 adrien // things are stable.
468 e342de7d 2015-11-11 adrien panic(err)
469 e342de7d 2015-11-11 adrien }
470 e342de7d 2015-11-11 adrien
471 e342de7d 2015-11-11 adrien s += size9p(elements...)
472 e342de7d 2015-11-11 adrien }
473 e342de7d 2015-11-11 adrien }
474 e342de7d 2015-11-11 adrien
475 e342de7d 2015-11-11 adrien return s
476 e342de7d 2015-11-11 adrien }
477 e342de7d 2015-11-11 adrien
478 e342de7d 2015-11-11 adrien // fields9p lists the settable fields from a struct type for reading and
479 e342de7d 2015-11-11 adrien // writing. We are using a lot of reflection here for fairly static
480 e342de7d 2015-11-11 adrien // serialization but we can replace this in the future with generated code if
481 e342de7d 2015-11-11 adrien // performance is an issue.
482 e342de7d 2015-11-11 adrien func fields9p(v interface{}) ([]interface{}, error) {
483 e342de7d 2015-11-11 adrien rv := reflect.Indirect(reflect.ValueOf(v))
484 e342de7d 2015-11-11 adrien
485 e342de7d 2015-11-11 adrien if rv.Kind() != reflect.Struct {
486 e342de7d 2015-11-11 adrien return nil, fmt.Errorf("cannot extract fields from non-struct: %v", rv)
487 e342de7d 2015-11-11 adrien }
488 e342de7d 2015-11-11 adrien
489 e342de7d 2015-11-11 adrien var elements []interface{}
490 e342de7d 2015-11-11 adrien for i := 0; i < rv.NumField(); i++ {
491 e342de7d 2015-11-11 adrien f := rv.Field(i)
492 e342de7d 2015-11-11 adrien
493 e342de7d 2015-11-11 adrien if !f.CanInterface() {
494 e342de7d 2015-11-11 adrien // unexported field, skip it.
495 e342de7d 2015-11-11 adrien continue
496 e342de7d 2015-11-11 adrien }
497 e342de7d 2015-11-11 adrien
498 e342de7d 2015-11-11 adrien if f.CanAddr() {
499 e342de7d 2015-11-11 adrien f = f.Addr()
500 e342de7d 2015-11-11 adrien }
501 e342de7d 2015-11-11 adrien
502 e342de7d 2015-11-11 adrien elements = append(elements, f.Interface())
503 e342de7d 2015-11-11 adrien }
504 e342de7d 2015-11-11 adrien
505 e342de7d 2015-11-11 adrien return elements, nil
506 e342de7d 2015-11-11 adrien }
507 e342de7d 2015-11-11 adrien
508 e342de7d 2015-11-11 adrien func string9p(v interface{}) string {
509 e342de7d 2015-11-11 adrien if v == nil {
510 e342de7d 2015-11-11 adrien return "nil"
511 e342de7d 2015-11-11 adrien }
512 e342de7d 2015-11-11 adrien
513 e342de7d 2015-11-11 adrien rv := reflect.Indirect(reflect.ValueOf(v))
514 e342de7d 2015-11-11 adrien
515 e342de7d 2015-11-11 adrien if rv.Kind() != reflect.Struct {
516 e342de7d 2015-11-11 adrien panic("not a struct")
517 e342de7d 2015-11-11 adrien }
518 e342de7d 2015-11-11 adrien
519 e342de7d 2015-11-11 adrien var s string
520 e342de7d 2015-11-11 adrien
521 e342de7d 2015-11-11 adrien for i := 0; i < rv.NumField(); i++ {
522 e342de7d 2015-11-11 adrien f := rv.Field(i)
523 e342de7d 2015-11-11 adrien
524 e342de7d 2015-11-11 adrien s += fmt.Sprintf(" %v=%v", strings.ToLower(rv.Type().Field(i).Name), f.Interface())
525 e342de7d 2015-11-11 adrien }
526 e342de7d 2015-11-11 adrien
527 e342de7d 2015-11-11 adrien return s
528 e342de7d 2015-11-11 adrien }