Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/lib9p/pack.c
39478 views
1
/*
2
* Copyright 2016 Jakub Klama <[email protected]>
3
* All rights reserved
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted providing that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
* POSSIBILITY OF SUCH DAMAGE.
25
*
26
*/
27
28
/*
29
* Based on libixp code: ©2007-2010 Kris Maglione <maglione.k at Gmail>
30
*/
31
32
#include <stdlib.h>
33
#include <string.h>
34
#include <assert.h>
35
#include <sys/types.h>
36
#include <sys/param.h>
37
#ifdef __APPLE__
38
# include "apple_endian.h"
39
#else
40
# include <sys/endian.h>
41
#endif
42
#include <sys/uio.h>
43
#include "lib9p.h"
44
#include "lib9p_impl.h"
45
#include "log.h"
46
47
#define N(ary) (sizeof(ary) / sizeof(*ary))
48
#define STRING_SIZE(s) (L9P_WORD + (s != NULL ? (uint16_t)strlen(s) : 0))
49
#define QID_SIZE (L9P_BYTE + L9P_DWORD + L9P_QWORD)
50
51
static ssize_t l9p_iov_io(struct l9p_message *, void *, size_t);
52
static inline ssize_t l9p_pu8(struct l9p_message *, uint8_t *);
53
static inline ssize_t l9p_pu16(struct l9p_message *, uint16_t *);
54
static inline ssize_t l9p_pu32(struct l9p_message *, uint32_t *);
55
static inline ssize_t l9p_pu64(struct l9p_message *, uint64_t *);
56
static ssize_t l9p_pustring(struct l9p_message *, char **s);
57
static ssize_t l9p_pustrings(struct l9p_message *, uint16_t *, char **, size_t);
58
static ssize_t l9p_puqid(struct l9p_message *, struct l9p_qid *);
59
static ssize_t l9p_puqids(struct l9p_message *, uint16_t *, struct l9p_qid *q);
60
61
/*
62
* Transfer data from incoming request, or to outgoing response,
63
* using msg to track position and direction within request/response.
64
*
65
* Returns the number of bytes actually transferred (which is always
66
* just len itself, converted to signed), or -1 if we ran out of space.
67
*
68
* Note that if we return -1, subsequent l9p_iov_io() calls with
69
* the same (and not-reset) msg and len > 0 will also return -1.
70
* This means most users can just check the *last* call for failure.
71
*/
72
static ssize_t
73
l9p_iov_io(struct l9p_message *msg, void *buffer, size_t len)
74
{
75
size_t done = 0;
76
size_t left = len;
77
78
assert(msg != NULL);
79
80
if (len == 0)
81
return (0);
82
83
if (msg->lm_cursor_iov >= msg->lm_niov)
84
return (-1);
85
86
assert(buffer != NULL);
87
88
while (left > 0) {
89
size_t idx = msg->lm_cursor_iov;
90
size_t space = msg->lm_iov[idx].iov_len - msg->lm_cursor_offset;
91
size_t towrite = MIN(space, left);
92
93
if (msg->lm_mode == L9P_PACK) {
94
memcpy((char *)msg->lm_iov[idx].iov_base +
95
msg->lm_cursor_offset, (char *)buffer + done,
96
towrite);
97
}
98
99
if (msg->lm_mode == L9P_UNPACK) {
100
memcpy((char *)buffer + done,
101
(char *)msg->lm_iov[idx].iov_base +
102
msg->lm_cursor_offset, towrite);
103
}
104
105
msg->lm_cursor_offset += towrite;
106
107
done += towrite;
108
left -= towrite;
109
110
if (space - towrite == 0) {
111
/* Advance to next iov */
112
msg->lm_cursor_iov++;
113
msg->lm_cursor_offset = 0;
114
115
if (msg->lm_cursor_iov >= msg->lm_niov && left > 0)
116
return (-1);
117
}
118
}
119
120
msg->lm_size += done;
121
return ((ssize_t)done);
122
}
123
124
/*
125
* Pack or unpack a byte (8 bits).
126
*
127
* Returns 1 (success, 1 byte) or -1 (error).
128
*/
129
static inline ssize_t
130
l9p_pu8(struct l9p_message *msg, uint8_t *val)
131
{
132
133
return (l9p_iov_io(msg, val, sizeof (uint8_t)));
134
}
135
136
/*
137
* Pack or unpack 16-bit value.
138
*
139
* Returns 2 or -1.
140
*/
141
static inline ssize_t
142
l9p_pu16(struct l9p_message *msg, uint16_t *val)
143
{
144
#if _BYTE_ORDER != _LITTLE_ENDIAN
145
/*
146
* The ifdefs are annoying, but there is no need
147
* for all of this foolery on little-endian hosts,
148
* and I don't expect the compiler to optimize it
149
* all away.
150
*/
151
uint16_t copy;
152
ssize_t ret;
153
154
if (msg->lm_mode == L9P_PACK) {
155
copy = htole16(*val);
156
return (l9p_iov_io(msg, &copy, sizeof (uint16_t)));
157
}
158
ret = l9p_iov_io(msg, val, sizeof (uint16_t));
159
*val = le16toh(*val);
160
return (ret);
161
#else
162
return (l9p_iov_io(msg, val, sizeof (uint16_t)));
163
#endif
164
}
165
166
/*
167
* Pack or unpack 32-bit value.
168
*
169
* Returns 4 or -1.
170
*/
171
static inline ssize_t
172
l9p_pu32(struct l9p_message *msg, uint32_t *val)
173
{
174
#if _BYTE_ORDER != _LITTLE_ENDIAN
175
uint32_t copy;
176
ssize_t ret;
177
178
if (msg->lm_mode == L9P_PACK) {
179
copy = htole32(*val);
180
return (l9p_iov_io(msg, &copy, sizeof (uint32_t)));
181
}
182
ret = l9p_iov_io(msg, val, sizeof (uint32_t));
183
*val = le32toh(*val);
184
return (ret);
185
#else
186
return (l9p_iov_io(msg, val, sizeof (uint32_t)));
187
#endif
188
}
189
190
/*
191
* Pack or unpack 64-bit value.
192
*
193
* Returns 8 or -1.
194
*/
195
static inline ssize_t
196
l9p_pu64(struct l9p_message *msg, uint64_t *val)
197
{
198
#if _BYTE_ORDER != _LITTLE_ENDIAN
199
uint64_t copy;
200
ssize_t ret;
201
202
if (msg->lm_mode == L9P_PACK) {
203
copy = htole64(*val);
204
return (l9p_iov_io(msg, &copy, sizeof (uint64_t)));
205
}
206
ret = l9p_iov_io(msg, val, sizeof (uint32_t));
207
*val = le64toh(*val);
208
return (ret);
209
#else
210
return (l9p_iov_io(msg, val, sizeof (uint64_t)));
211
#endif
212
}
213
214
/*
215
* Pack or unpack a string, encoded as 2-byte length followed by
216
* string bytes. The returned length is 2 greater than the
217
* length of the string itself.
218
*
219
* When unpacking, this allocates a new string (NUL-terminated).
220
*
221
* Return -1 on error (not space, or failed to allocate string,
222
* or illegal string).
223
*
224
* Note that pustring (and hence pustrings) can return an error
225
* even when l9p_iov_io succeeds.
226
*/
227
static ssize_t
228
l9p_pustring(struct l9p_message *msg, char **s)
229
{
230
uint16_t len;
231
232
if (msg->lm_mode == L9P_PACK)
233
len = *s != NULL ? (uint16_t)strlen(*s) : 0;
234
235
if (l9p_pu16(msg, &len) < 0)
236
return (-1);
237
238
if (msg->lm_mode == L9P_UNPACK) {
239
*s = l9p_calloc(1, len + 1);
240
if (*s == NULL)
241
return (-1);
242
}
243
244
if (l9p_iov_io(msg, *s, len) < 0)
245
return (-1);
246
247
if (msg->lm_mode == L9P_UNPACK) {
248
/*
249
* An embedded NUL byte in a string is illegal.
250
* We don't necessarily have to check (we'll just
251
* treat it as a shorter string), but checking
252
* seems like a good idea.
253
*/
254
if (memchr(*s, '\0', len) != NULL)
255
return (-1);
256
}
257
258
return ((ssize_t)len + 2);
259
}
260
261
/*
262
* Pack or unpack a number (*num) of strings (but at most max of
263
* them).
264
*
265
* Returns the number of bytes transferred, including the packed
266
* number of strings. If packing and the packed number of strings
267
* was reduced, the original *num value is unchanged; only the
268
* wire-format number is reduced. If unpacking and the input
269
* number of strings exceeds the max, the incoming *num is reduced
270
* to lim, if needed. (NOTE ASYMMETRY HERE!)
271
*
272
* Returns -1 on error.
273
*/
274
static ssize_t
275
l9p_pustrings(struct l9p_message *msg, uint16_t *num, char **strings,
276
size_t max)
277
{
278
size_t i, lim;
279
ssize_t r, ret;
280
uint16_t adjusted;
281
282
if (msg->lm_mode == L9P_PACK) {
283
lim = *num;
284
if (lim > max)
285
lim = max;
286
adjusted = (uint16_t)lim;
287
r = l9p_pu16(msg, &adjusted);
288
} else {
289
r = l9p_pu16(msg, num);
290
lim = *num;
291
if (lim > max)
292
*num = (uint16_t)(lim = max);
293
}
294
if (r < 0)
295
return (-1);
296
297
for (i = 0; i < lim; i++) {
298
ret = l9p_pustring(msg, &strings[i]);
299
if (ret < 1)
300
return (-1);
301
302
r += ret;
303
}
304
305
return (r);
306
}
307
308
/*
309
* Pack or unpack a qid.
310
*
311
* Returns 13 (success) or -1 (error).
312
*/
313
static ssize_t
314
l9p_puqid(struct l9p_message *msg, struct l9p_qid *qid)
315
{
316
ssize_t r;
317
uint8_t type;
318
319
if (msg->lm_mode == L9P_PACK) {
320
type = qid->type;
321
r = l9p_pu8(msg, &type);
322
} else {
323
r = l9p_pu8(msg, &type);
324
qid->type = type;
325
}
326
if (r > 0)
327
r = l9p_pu32(msg, &qid->version);
328
if (r > 0)
329
r = l9p_pu64(msg, &qid->path);
330
331
return (r > 0 ? QID_SIZE : r);
332
}
333
334
/*
335
* Pack or unpack *num qids.
336
*
337
* Returns 2 + 13 * *num (after possibly setting *num), or -1 on error.
338
*/
339
static ssize_t
340
l9p_puqids(struct l9p_message *msg, uint16_t *num, struct l9p_qid *qids)
341
{
342
size_t i, lim;
343
ssize_t ret, r;
344
345
r = l9p_pu16(msg, num);
346
if (r <= 0)
347
return (r);
348
349
if (*num > L9P_MAX_WELEM)
350
return (-1);
351
352
for (i = 0, lim = *num; i < lim; i++) {
353
ret = l9p_puqid(msg, &qids[i]);
354
if (ret < 0)
355
return (-1);
356
r += ret;
357
}
358
return (r);
359
}
360
361
/*
362
* Pack or unpack a l9p_stat.
363
*
364
* These have variable size, and the size further depends on
365
* the protocol version.
366
*
367
* Returns the number of bytes packed/unpacked, or -1 on error.
368
*/
369
ssize_t
370
l9p_pustat(struct l9p_message *msg, struct l9p_stat *stat,
371
enum l9p_version version)
372
{
373
ssize_t r = 0;
374
uint16_t size;
375
376
/* The on-wire size field excludes the size of the size field. */
377
if (msg->lm_mode == L9P_PACK)
378
size = l9p_sizeof_stat(stat, version) - 2;
379
380
r += l9p_pu16(msg, &size);
381
r += l9p_pu16(msg, &stat->type);
382
r += l9p_pu32(msg, &stat->dev);
383
r += l9p_puqid(msg, &stat->qid);
384
r += l9p_pu32(msg, &stat->mode);
385
r += l9p_pu32(msg, &stat->atime);
386
r += l9p_pu32(msg, &stat->mtime);
387
r += l9p_pu64(msg, &stat->length);
388
r += l9p_pustring(msg, &stat->name);
389
r += l9p_pustring(msg, &stat->uid);
390
r += l9p_pustring(msg, &stat->gid);
391
r += l9p_pustring(msg, &stat->muid);
392
393
if (version >= L9P_2000U) {
394
r += l9p_pustring(msg, &stat->extension);
395
r += l9p_pu32(msg, &stat->n_uid);
396
r += l9p_pu32(msg, &stat->n_gid);
397
r += l9p_pu32(msg, &stat->n_muid);
398
}
399
400
if (r < size + 2)
401
return (-1);
402
403
return (r);
404
}
405
406
/*
407
* Pack or unpack a variable-length dirent.
408
*
409
* If unpacking, the name field is malloc()ed and the caller must
410
* free it.
411
*
412
* Returns the wire-format length, or -1 if we ran out of room.
413
*/
414
ssize_t
415
l9p_pudirent(struct l9p_message *msg, struct l9p_dirent *de)
416
{
417
ssize_t r, s;
418
419
r = l9p_puqid(msg, &de->qid);
420
r += l9p_pu64(msg, &de->offset);
421
r += l9p_pu8(msg, &de->type);
422
s = l9p_pustring(msg, &de->name);
423
if (r < QID_SIZE + 8 + 1 || s < 0)
424
return (-1);
425
return (r + s);
426
}
427
428
/*
429
* Pack or unpack a request or response (fcall).
430
*
431
* Returns 0 on success, -1 on error. (It's up to the caller
432
* to call l9p_freefcall on our failure.)
433
*/
434
int
435
l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall,
436
enum l9p_version version)
437
{
438
uint32_t length = 0;
439
ssize_t r;
440
441
/*
442
* Get overall length, type, and tag, which should appear
443
* in all messages. If not even that works, abort immediately.
444
*/
445
l9p_pu32(msg, &length);
446
l9p_pu8(msg, &fcall->hdr.type);
447
r = l9p_pu16(msg, &fcall->hdr.tag);
448
if (r < 0)
449
return (-1);
450
451
/*
452
* Decode remainder of message. When unpacking, this may
453
* allocate memory, even if we fail during the decode.
454
* Note that the initial fcall is zeroed out, though, so
455
* we can just freefcall() to release whatever might have
456
* gotten allocated, if the unpack fails due to a short
457
* packet.
458
*/
459
switch (fcall->hdr.type) {
460
case L9P_TVERSION:
461
case L9P_RVERSION:
462
l9p_pu32(msg, &fcall->version.msize);
463
r = l9p_pustring(msg, &fcall->version.version);
464
break;
465
466
case L9P_TAUTH:
467
l9p_pu32(msg, &fcall->tauth.afid);
468
r = l9p_pustring(msg, &fcall->tauth.uname);
469
if (r < 0)
470
break;
471
r = l9p_pustring(msg, &fcall->tauth.aname);
472
if (r < 0)
473
break;
474
if (version >= L9P_2000U)
475
r = l9p_pu32(msg, &fcall->tauth.n_uname);
476
break;
477
478
case L9P_RAUTH:
479
r = l9p_puqid(msg, &fcall->rauth.aqid);
480
break;
481
482
case L9P_TATTACH:
483
l9p_pu32(msg, &fcall->hdr.fid);
484
l9p_pu32(msg, &fcall->tattach.afid);
485
r = l9p_pustring(msg, &fcall->tattach.uname);
486
if (r < 0)
487
break;
488
r = l9p_pustring(msg, &fcall->tattach.aname);
489
if (r < 0)
490
break;
491
if (version >= L9P_2000U)
492
r = l9p_pu32(msg, &fcall->tattach.n_uname);
493
break;
494
495
case L9P_RATTACH:
496
r = l9p_puqid(msg, &fcall->rattach.qid);
497
break;
498
499
case L9P_RERROR:
500
r = l9p_pustring(msg, &fcall->error.ename);
501
if (r < 0)
502
break;
503
if (version >= L9P_2000U)
504
r = l9p_pu32(msg, &fcall->error.errnum);
505
break;
506
507
case L9P_RLERROR:
508
r = l9p_pu32(msg, &fcall->error.errnum);
509
break;
510
511
case L9P_TFLUSH:
512
r = l9p_pu16(msg, &fcall->tflush.oldtag);
513
break;
514
515
case L9P_RFLUSH:
516
break;
517
518
case L9P_TWALK:
519
l9p_pu32(msg, &fcall->hdr.fid);
520
l9p_pu32(msg, &fcall->twalk.newfid);
521
r = l9p_pustrings(msg, &fcall->twalk.nwname,
522
fcall->twalk.wname, N(fcall->twalk.wname));
523
break;
524
525
case L9P_RWALK:
526
r = l9p_puqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid);
527
break;
528
529
case L9P_TOPEN:
530
l9p_pu32(msg, &fcall->hdr.fid);
531
r = l9p_pu8(msg, &fcall->topen.mode);
532
break;
533
534
case L9P_ROPEN:
535
l9p_puqid(msg, &fcall->ropen.qid);
536
r = l9p_pu32(msg, &fcall->ropen.iounit);
537
break;
538
539
case L9P_TCREATE:
540
l9p_pu32(msg, &fcall->hdr.fid);
541
r = l9p_pustring(msg, &fcall->tcreate.name);
542
if (r < 0)
543
break;
544
l9p_pu32(msg, &fcall->tcreate.perm);
545
r = l9p_pu8(msg, &fcall->tcreate.mode);
546
if (version >= L9P_2000U)
547
r = l9p_pustring(msg, &fcall->tcreate.extension);
548
break;
549
550
case L9P_RCREATE:
551
l9p_puqid(msg, &fcall->rcreate.qid);
552
r = l9p_pu32(msg, &fcall->rcreate.iounit);
553
break;
554
555
case L9P_TREAD:
556
case L9P_TREADDIR:
557
l9p_pu32(msg, &fcall->hdr.fid);
558
l9p_pu64(msg, &fcall->io.offset);
559
r = l9p_pu32(msg, &fcall->io.count);
560
break;
561
562
case L9P_RREAD:
563
case L9P_RREADDIR:
564
r = l9p_pu32(msg, &fcall->io.count);
565
break;
566
567
case L9P_TWRITE:
568
l9p_pu32(msg, &fcall->hdr.fid);
569
l9p_pu64(msg, &fcall->io.offset);
570
r = l9p_pu32(msg, &fcall->io.count);
571
break;
572
573
case L9P_RWRITE:
574
r = l9p_pu32(msg, &fcall->io.count);
575
break;
576
577
case L9P_TCLUNK:
578
case L9P_TSTAT:
579
case L9P_TREMOVE:
580
case L9P_TSTATFS:
581
r = l9p_pu32(msg, &fcall->hdr.fid);
582
break;
583
584
case L9P_RCLUNK:
585
case L9P_RREMOVE:
586
break;
587
588
case L9P_RSTAT:
589
{
590
uint16_t size = l9p_sizeof_stat(&fcall->rstat.stat,
591
version);
592
l9p_pu16(msg, &size);
593
r = l9p_pustat(msg, &fcall->rstat.stat, version);
594
}
595
break;
596
597
case L9P_TWSTAT:
598
{
599
uint16_t size;
600
l9p_pu32(msg, &fcall->hdr.fid);
601
l9p_pu16(msg, &size);
602
r = l9p_pustat(msg, &fcall->twstat.stat, version);
603
}
604
break;
605
606
case L9P_RWSTAT:
607
break;
608
609
case L9P_RSTATFS:
610
l9p_pu32(msg, &fcall->rstatfs.statfs.type);
611
l9p_pu32(msg, &fcall->rstatfs.statfs.bsize);
612
l9p_pu64(msg, &fcall->rstatfs.statfs.blocks);
613
l9p_pu64(msg, &fcall->rstatfs.statfs.bfree);
614
l9p_pu64(msg, &fcall->rstatfs.statfs.bavail);
615
l9p_pu64(msg, &fcall->rstatfs.statfs.files);
616
l9p_pu64(msg, &fcall->rstatfs.statfs.ffree);
617
l9p_pu64(msg, &fcall->rstatfs.statfs.fsid);
618
r = l9p_pu32(msg, &fcall->rstatfs.statfs.namelen);
619
break;
620
621
case L9P_TLOPEN:
622
l9p_pu32(msg, &fcall->hdr.fid);
623
r = l9p_pu32(msg, &fcall->tlopen.flags);
624
break;
625
626
case L9P_RLOPEN:
627
l9p_puqid(msg, &fcall->rlopen.qid);
628
r = l9p_pu32(msg, &fcall->rlopen.iounit);
629
break;
630
631
case L9P_TLCREATE:
632
l9p_pu32(msg, &fcall->hdr.fid);
633
r = l9p_pustring(msg, &fcall->tlcreate.name);
634
if (r < 0)
635
break;
636
l9p_pu32(msg, &fcall->tlcreate.flags);
637
l9p_pu32(msg, &fcall->tlcreate.mode);
638
r = l9p_pu32(msg, &fcall->tlcreate.gid);
639
break;
640
641
case L9P_RLCREATE:
642
l9p_puqid(msg, &fcall->rlcreate.qid);
643
r = l9p_pu32(msg, &fcall->rlcreate.iounit);
644
break;
645
646
case L9P_TSYMLINK:
647
l9p_pu32(msg, &fcall->hdr.fid);
648
r = l9p_pustring(msg, &fcall->tsymlink.name);
649
if (r < 0)
650
break;
651
r = l9p_pustring(msg, &fcall->tsymlink.symtgt);
652
if (r < 0)
653
break;
654
r = l9p_pu32(msg, &fcall->tlcreate.gid);
655
break;
656
657
case L9P_RSYMLINK:
658
r = l9p_puqid(msg, &fcall->rsymlink.qid);
659
break;
660
661
case L9P_TMKNOD:
662
l9p_pu32(msg, &fcall->hdr.fid);
663
r = l9p_pustring(msg, &fcall->tmknod.name);
664
if (r < 0)
665
break;
666
l9p_pu32(msg, &fcall->tmknod.mode);
667
l9p_pu32(msg, &fcall->tmknod.major);
668
l9p_pu32(msg, &fcall->tmknod.minor);
669
r = l9p_pu32(msg, &fcall->tmknod.gid);
670
break;
671
672
case L9P_RMKNOD:
673
r = l9p_puqid(msg, &fcall->rmknod.qid);
674
break;
675
676
case L9P_TRENAME:
677
l9p_pu32(msg, &fcall->hdr.fid);
678
l9p_pu32(msg, &fcall->trename.dfid);
679
r = l9p_pustring(msg, &fcall->trename.name);
680
break;
681
682
case L9P_RRENAME:
683
break;
684
685
case L9P_TREADLINK:
686
r = l9p_pu32(msg, &fcall->hdr.fid);
687
break;
688
689
case L9P_RREADLINK:
690
r = l9p_pustring(msg, &fcall->rreadlink.target);
691
break;
692
693
case L9P_TGETATTR:
694
l9p_pu32(msg, &fcall->hdr.fid);
695
r = l9p_pu64(msg, &fcall->tgetattr.request_mask);
696
break;
697
698
case L9P_RGETATTR:
699
l9p_pu64(msg, &fcall->rgetattr.valid);
700
l9p_puqid(msg, &fcall->rgetattr.qid);
701
l9p_pu32(msg, &fcall->rgetattr.mode);
702
l9p_pu32(msg, &fcall->rgetattr.uid);
703
l9p_pu32(msg, &fcall->rgetattr.gid);
704
l9p_pu64(msg, &fcall->rgetattr.nlink);
705
l9p_pu64(msg, &fcall->rgetattr.rdev);
706
l9p_pu64(msg, &fcall->rgetattr.size);
707
l9p_pu64(msg, &fcall->rgetattr.blksize);
708
l9p_pu64(msg, &fcall->rgetattr.blocks);
709
l9p_pu64(msg, &fcall->rgetattr.atime_sec);
710
l9p_pu64(msg, &fcall->rgetattr.atime_nsec);
711
l9p_pu64(msg, &fcall->rgetattr.mtime_sec);
712
l9p_pu64(msg, &fcall->rgetattr.mtime_nsec);
713
l9p_pu64(msg, &fcall->rgetattr.ctime_sec);
714
l9p_pu64(msg, &fcall->rgetattr.ctime_nsec);
715
l9p_pu64(msg, &fcall->rgetattr.btime_sec);
716
l9p_pu64(msg, &fcall->rgetattr.btime_nsec);
717
l9p_pu64(msg, &fcall->rgetattr.gen);
718
r = l9p_pu64(msg, &fcall->rgetattr.data_version);
719
break;
720
721
case L9P_TSETATTR:
722
l9p_pu32(msg, &fcall->hdr.fid);
723
l9p_pu32(msg, &fcall->tsetattr.valid);
724
l9p_pu32(msg, &fcall->tsetattr.mode);
725
l9p_pu32(msg, &fcall->tsetattr.uid);
726
l9p_pu32(msg, &fcall->tsetattr.gid);
727
l9p_pu64(msg, &fcall->tsetattr.size);
728
l9p_pu64(msg, &fcall->tsetattr.atime_sec);
729
l9p_pu64(msg, &fcall->tsetattr.atime_nsec);
730
l9p_pu64(msg, &fcall->tsetattr.mtime_sec);
731
r = l9p_pu64(msg, &fcall->tsetattr.mtime_nsec);
732
break;
733
734
case L9P_RSETATTR:
735
break;
736
737
case L9P_TXATTRWALK:
738
l9p_pu32(msg, &fcall->hdr.fid);
739
l9p_pu32(msg, &fcall->txattrwalk.newfid);
740
r = l9p_pustring(msg, &fcall->txattrwalk.name);
741
break;
742
743
case L9P_RXATTRWALK:
744
r = l9p_pu64(msg, &fcall->rxattrwalk.size);
745
break;
746
747
case L9P_TXATTRCREATE:
748
l9p_pu32(msg, &fcall->hdr.fid);
749
r = l9p_pustring(msg, &fcall->txattrcreate.name);
750
if (r < 0)
751
break;
752
l9p_pu64(msg, &fcall->txattrcreate.attr_size);
753
r = l9p_pu32(msg, &fcall->txattrcreate.flags);
754
break;
755
756
case L9P_RXATTRCREATE:
757
break;
758
759
case L9P_TFSYNC:
760
r = l9p_pu32(msg, &fcall->hdr.fid);
761
break;
762
763
case L9P_RFSYNC:
764
break;
765
766
case L9P_TLOCK:
767
l9p_pu32(msg, &fcall->hdr.fid);
768
l9p_pu8(msg, &fcall->tlock.type);
769
l9p_pu32(msg, &fcall->tlock.flags);
770
l9p_pu64(msg, &fcall->tlock.start);
771
l9p_pu64(msg, &fcall->tlock.length);
772
l9p_pu32(msg, &fcall->tlock.proc_id);
773
r = l9p_pustring(msg, &fcall->tlock.client_id);
774
break;
775
776
case L9P_RLOCK:
777
r = l9p_pu8(msg, &fcall->rlock.status);
778
break;
779
780
case L9P_TGETLOCK:
781
l9p_pu32(msg, &fcall->hdr.fid);
782
/* FALLTHROUGH */
783
784
case L9P_RGETLOCK:
785
l9p_pu8(msg, &fcall->getlock.type);
786
l9p_pu64(msg, &fcall->getlock.start);
787
l9p_pu64(msg, &fcall->getlock.length);
788
l9p_pu32(msg, &fcall->getlock.proc_id);
789
r = l9p_pustring(msg, &fcall->getlock.client_id);
790
break;
791
792
case L9P_TLINK:
793
l9p_pu32(msg, &fcall->tlink.dfid);
794
l9p_pu32(msg, &fcall->hdr.fid);
795
r = l9p_pustring(msg, &fcall->tlink.name);
796
break;
797
798
case L9P_RLINK:
799
break;
800
801
case L9P_TMKDIR:
802
l9p_pu32(msg, &fcall->hdr.fid);
803
r = l9p_pustring(msg, &fcall->tmkdir.name);
804
if (r < 0)
805
break;
806
l9p_pu32(msg, &fcall->tmkdir.mode);
807
r = l9p_pu32(msg, &fcall->tmkdir.gid);
808
break;
809
810
case L9P_RMKDIR:
811
r = l9p_puqid(msg, &fcall->rmkdir.qid);
812
break;
813
814
case L9P_TRENAMEAT:
815
l9p_pu32(msg, &fcall->hdr.fid);
816
r = l9p_pustring(msg, &fcall->trenameat.oldname);
817
if (r < 0)
818
break;
819
l9p_pu32(msg, &fcall->trenameat.newdirfid);
820
r = l9p_pustring(msg, &fcall->trenameat.newname);
821
break;
822
823
case L9P_RRENAMEAT:
824
break;
825
826
case L9P_TUNLINKAT:
827
l9p_pu32(msg, &fcall->hdr.fid);
828
r = l9p_pustring(msg, &fcall->tunlinkat.name);
829
if (r < 0)
830
break;
831
r = l9p_pu32(msg, &fcall->tunlinkat.flags);
832
break;
833
834
case L9P_RUNLINKAT:
835
break;
836
837
default:
838
L9P_LOG(L9P_ERROR, "%s(): missing case for type %d",
839
__func__, fcall->hdr.type);
840
break;
841
}
842
843
/* Check for over- or under-run, or pustring error. */
844
if (r < 0)
845
return (-1);
846
847
if (msg->lm_mode == L9P_PACK) {
848
/* Rewind to the beginning and install size at front. */
849
uint32_t len = (uint32_t)msg->lm_size;
850
msg->lm_cursor_offset = 0;
851
msg->lm_cursor_iov = 0;
852
853
/*
854
* Subtract 4 bytes from current size, becase we're
855
* overwriting size (rewinding message to the beginning)
856
* and writing again, which will increase it 4 more.
857
*/
858
msg->lm_size -= sizeof(uint32_t);
859
860
if (fcall->hdr.type == L9P_RREAD ||
861
fcall->hdr.type == L9P_RREADDIR)
862
len += fcall->io.count;
863
864
l9p_pu32(msg, &len);
865
}
866
867
return (0);
868
}
869
870
/*
871
* Free any strings or other data malloc'ed in the process of
872
* packing or unpacking an fcall.
873
*/
874
void
875
l9p_freefcall(union l9p_fcall *fcall)
876
{
877
uint16_t i;
878
879
switch (fcall->hdr.type) {
880
881
case L9P_TVERSION:
882
case L9P_RVERSION:
883
free(fcall->version.version);
884
return;
885
886
case L9P_TATTACH:
887
free(fcall->tattach.aname);
888
free(fcall->tattach.uname);
889
return;
890
891
case L9P_TWALK:
892
for (i = 0; i < fcall->twalk.nwname; i++)
893
free(fcall->twalk.wname[i]);
894
return;
895
896
case L9P_TCREATE:
897
case L9P_TOPEN:
898
free(fcall->tcreate.name);
899
free(fcall->tcreate.extension);
900
return;
901
902
case L9P_RSTAT:
903
l9p_freestat(&fcall->rstat.stat);
904
return;
905
906
case L9P_TWSTAT:
907
l9p_freestat(&fcall->twstat.stat);
908
return;
909
910
case L9P_TLCREATE:
911
free(fcall->tlcreate.name);
912
return;
913
914
case L9P_TSYMLINK:
915
free(fcall->tsymlink.name);
916
free(fcall->tsymlink.symtgt);
917
return;
918
919
case L9P_TMKNOD:
920
free(fcall->tmknod.name);
921
return;
922
923
case L9P_TRENAME:
924
free(fcall->trename.name);
925
return;
926
927
case L9P_RREADLINK:
928
free(fcall->rreadlink.target);
929
return;
930
931
case L9P_TXATTRWALK:
932
free(fcall->txattrwalk.name);
933
return;
934
935
case L9P_TXATTRCREATE:
936
free(fcall->txattrcreate.name);
937
return;
938
939
case L9P_TLOCK:
940
free(fcall->tlock.client_id);
941
return;
942
943
case L9P_TGETLOCK:
944
case L9P_RGETLOCK:
945
free(fcall->getlock.client_id);
946
return;
947
948
case L9P_TLINK:
949
free(fcall->tlink.name);
950
return;
951
952
case L9P_TMKDIR:
953
free(fcall->tmkdir.name);
954
return;
955
956
case L9P_TRENAMEAT:
957
free(fcall->trenameat.oldname);
958
free(fcall->trenameat.newname);
959
return;
960
961
case L9P_TUNLINKAT:
962
free(fcall->tunlinkat.name);
963
return;
964
}
965
}
966
967
void
968
l9p_freestat(struct l9p_stat *stat)
969
{
970
free(stat->name);
971
free(stat->extension);
972
free(stat->uid);
973
free(stat->gid);
974
free(stat->muid);
975
}
976
977
uint16_t
978
l9p_sizeof_stat(struct l9p_stat *stat, enum l9p_version version)
979
{
980
uint16_t size = L9P_WORD /* size */
981
+ L9P_WORD /* type */
982
+ L9P_DWORD /* dev */
983
+ QID_SIZE /* qid */
984
+ 3 * L9P_DWORD /* mode, atime, mtime */
985
+ L9P_QWORD /* length */
986
+ STRING_SIZE(stat->name)
987
+ STRING_SIZE(stat->uid)
988
+ STRING_SIZE(stat->gid)
989
+ STRING_SIZE(stat->muid);
990
991
if (version >= L9P_2000U) {
992
size += STRING_SIZE(stat->extension)
993
+ 3 * L9P_DWORD;
994
}
995
996
return (size);
997
}
998
999