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 #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
l9p_iov_io(struct l9p_message * msg,void * buffer,size_t len)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
l9p_pu8(struct l9p_message * msg,uint8_t * val)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
l9p_pu16(struct l9p_message * msg,uint16_t * val)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, ©, 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
l9p_pu32(struct l9p_message * msg,uint32_t * val)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, ©, 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
l9p_pu64(struct l9p_message * msg,uint64_t * val)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, ©, 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
l9p_pustring(struct l9p_message * msg,char ** s)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
l9p_pustrings(struct l9p_message * msg,uint16_t * num,char ** strings,size_t max)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
l9p_puqid(struct l9p_message * msg,struct l9p_qid * qid)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
l9p_puqids(struct l9p_message * msg,uint16_t * num,struct l9p_qid * qids)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
l9p_pustat(struct l9p_message * msg,struct l9p_stat * stat,enum l9p_version version)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
l9p_pudirent(struct l9p_message * msg,struct l9p_dirent * de)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
l9p_pufcall(struct l9p_message * msg,union l9p_fcall * fcall,enum l9p_version version)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
l9p_freefcall(union l9p_fcall * fcall)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
l9p_freestat(struct l9p_stat * stat)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
l9p_sizeof_stat(struct l9p_stat * stat,enum l9p_version version)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