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