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