xref: /titanic_50/usr/src/uts/common/fs/nfs/nfs_xdr.c (revision ea8dc4b6d2251b437950c0056bc626b311c73c27)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/systm.h>
35 #include <sys/user.h>
36 #include <sys/vnode.h>
37 #include <sys/file.h>
38 #include <sys/dirent.h>
39 #include <sys/vfs.h>
40 #include <sys/stream.h>
41 #include <sys/strsubr.h>
42 #include <sys/debug.h>
43 #include <sys/t_lock.h>
44 
45 #include <rpc/types.h>
46 #include <rpc/xdr.h>
47 
48 #include <nfs/nfs.h>
49 
50 #include <vm/hat.h>
51 #include <vm/as.h>
52 #include <vm/seg.h>
53 #include <vm/seg_map.h>
54 #include <vm/seg_kmem.h>
55 
56 static bool_t xdr_fastshorten(XDR *, uint_t);
57 
58 /*
59  * These are the XDR routines used to serialize and deserialize
60  * the various structures passed as parameters accross the network
61  * between NFS clients and servers.
62  */
63 
64 /*
65  * File access handle
66  * The fhandle struct is treated a opaque data on the wire
67  */
68 bool_t
69 xdr_fhandle(XDR *xdrs, fhandle_t *fh)
70 {
71 	int32_t *ptr;
72 	int32_t *fhp;
73 
74 	if (xdrs->x_op == XDR_FREE)
75 		return (TRUE);
76 
77 	ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)));
78 	if (ptr != NULL) {
79 		fhp = (int32_t *)fh;
80 		if (xdrs->x_op == XDR_DECODE) {
81 			*fhp++ = *ptr++;
82 			*fhp++ = *ptr++;
83 			*fhp++ = *ptr++;
84 			*fhp++ = *ptr++;
85 			*fhp++ = *ptr++;
86 			*fhp++ = *ptr++;
87 			*fhp++ = *ptr++;
88 			*fhp = *ptr;
89 		} else {
90 			*ptr++ = *fhp++;
91 			*ptr++ = *fhp++;
92 			*ptr++ = *fhp++;
93 			*ptr++ = *fhp++;
94 			*ptr++ = *fhp++;
95 			*ptr++ = *fhp++;
96 			*ptr++ = *fhp++;
97 			*ptr = *fhp;
98 		}
99 		return (TRUE);
100 	}
101 
102 	return (xdr_opaque(xdrs, (caddr_t)fh, NFS_FHSIZE));
103 }
104 
105 bool_t
106 xdr_fastfhandle(XDR *xdrs, fhandle_t **fh)
107 {
108 	int32_t *ptr;
109 
110 	if (xdrs->x_op != XDR_DECODE)
111 		return (FALSE);
112 
113 	ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)));
114 	if (ptr != NULL) {
115 		*fh = (fhandle_t *)ptr;
116 		return (TRUE);
117 	}
118 
119 	return (FALSE);
120 }
121 
122 /*
123  * Arguments to remote write and writecache
124  */
125 bool_t
126 xdr_writeargs(XDR *xdrs, struct nfswriteargs *wa)
127 {
128 	int32_t *ptr;
129 	int32_t *fhp;
130 
131 	if (xdrs->x_op == XDR_DECODE) {
132 		wa->wa_args = &wa->wa_args_buf;
133 		ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) +
134 		    3 * BYTES_PER_XDR_UNIT);
135 		if (ptr != NULL) {
136 			fhp = (int32_t *)&wa->wa_fhandle;
137 			*fhp++ = *ptr++;
138 			*fhp++ = *ptr++;
139 			*fhp++ = *ptr++;
140 			*fhp++ = *ptr++;
141 			*fhp++ = *ptr++;
142 			*fhp++ = *ptr++;
143 			*fhp++ = *ptr++;
144 			*fhp = *ptr++;
145 			wa->wa_begoff = IXDR_GET_U_INT32(ptr);
146 			wa->wa_offset = IXDR_GET_U_INT32(ptr);
147 			wa->wa_totcount = IXDR_GET_U_INT32(ptr);
148 			if (xdrs->x_ops == &xdrmblk_ops)
149 				return (xdrmblk_getmblk(xdrs, &wa->wa_mblk,
150 				    &wa->wa_count));
151 			/*
152 			 * It is just as efficient to xdr_bytes
153 			 * an array of unknown length as to inline copy it.
154 			 */
155 			return (xdr_bytes(xdrs, &wa->wa_data,
156 				    &wa->wa_count, NFS_MAXDATA));
157 		}
158 	}
159 
160 	if (xdrs->x_op == XDR_ENCODE) {
161 		ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) +
162 		    3 * BYTES_PER_XDR_UNIT);
163 		if (ptr != NULL) {
164 			fhp = (int32_t *)&wa->wa_fhandle;
165 			*ptr++ = *fhp++;
166 			*ptr++ = *fhp++;
167 			*ptr++ = *fhp++;
168 			*ptr++ = *fhp++;
169 			*ptr++ = *fhp++;
170 			*ptr++ = *fhp++;
171 			*ptr++ = *fhp++;
172 			*ptr++ = *fhp;
173 			IXDR_PUT_U_INT32(ptr, wa->wa_begoff);
174 			IXDR_PUT_U_INT32(ptr, wa->wa_offset);
175 			IXDR_PUT_U_INT32(ptr, wa->wa_totcount);
176 		} else {
177 			if (!(xdr_fhandle(xdrs, &wa->wa_fhandle) &&
178 			    xdr_u_int(xdrs, &wa->wa_begoff) &&
179 			    xdr_u_int(xdrs, &wa->wa_offset) &&
180 			    xdr_u_int(xdrs, &wa->wa_totcount)))
181 				return (FALSE);
182 		}
183 #if 0 /* notdef */
184 		if (wa->wa_mblk != NULL && xdrs->x_ops == &xdrmblk_ops) {
185 			mblk_t *mp;
186 
187 			mp = dupb(wa->wa_mblk);
188 			if (mp != NULL) {
189 				mp->b_wptr += wa->wa_count;
190 				if (xdrmblk_putmblk(xdrs, mp,
191 				    wa->wa_count) == TRUE) {
192 					return (TRUE);
193 				} else
194 					freeb(mp);
195 			}
196 			/* else Fall thru for the xdr_bytes() */
197 		}
198 		/* wa_mblk == NULL || xdrs->x_ops != &xdrmblk_ops Fall thru */
199 #endif /* notdef */
200 		return (xdr_bytes(xdrs, &wa->wa_data, &wa->wa_count,
201 		    NFS_MAXDATA));
202 	}
203 
204 	if (xdrs->x_op == XDR_FREE) {
205 		if (wa->wa_data != NULL) {
206 			kmem_free(wa->wa_data, wa->wa_count);
207 			wa->wa_data = NULL;
208 		}
209 		return (TRUE);
210 	}
211 
212 	if (xdr_fhandle(xdrs, &wa->wa_fhandle) &&
213 	    xdr_u_int(xdrs, &wa->wa_begoff) &&
214 	    xdr_u_int(xdrs, &wa->wa_offset) &&
215 	    xdr_u_int(xdrs, &wa->wa_totcount) &&
216 	    (xdrs->x_op == XDR_DECODE && xdrs->x_ops == &xdrmblk_ops) ?
217 	    xdrmblk_getmblk(xdrs, &wa->wa_mblk, &wa->wa_count) :
218 	    xdr_bytes(xdrs, &wa->wa_data, &wa->wa_count, NFS_MAXDATA)) {
219 		return (TRUE);
220 	}
221 	return (FALSE);
222 }
223 
224 
225 /*
226  * File attributes
227  */
228 bool_t
229 xdr_fattr(XDR *xdrs, struct nfsfattr *na)
230 {
231 	int32_t *ptr;
232 
233 	if (xdrs->x_op == XDR_FREE)
234 		return (TRUE);
235 
236 	ptr = XDR_INLINE(xdrs, 17 * BYTES_PER_XDR_UNIT);
237 	if (ptr != NULL) {
238 		if (xdrs->x_op == XDR_DECODE) {
239 			na->na_type = IXDR_GET_ENUM(ptr, enum nfsftype);
240 			na->na_mode = IXDR_GET_U_INT32(ptr);
241 			na->na_nlink = IXDR_GET_U_INT32(ptr);
242 			na->na_uid = IXDR_GET_U_INT32(ptr);
243 			na->na_gid = IXDR_GET_U_INT32(ptr);
244 			na->na_size = IXDR_GET_U_INT32(ptr);
245 			na->na_blocksize = IXDR_GET_U_INT32(ptr);
246 			na->na_rdev = IXDR_GET_U_INT32(ptr);
247 			na->na_blocks = IXDR_GET_U_INT32(ptr);
248 			na->na_fsid = IXDR_GET_U_INT32(ptr);
249 			na->na_nodeid = IXDR_GET_U_INT32(ptr);
250 			na->na_atime.tv_sec = IXDR_GET_U_INT32(ptr);
251 			na->na_atime.tv_usec = IXDR_GET_U_INT32(ptr);
252 			na->na_mtime.tv_sec = IXDR_GET_U_INT32(ptr);
253 			na->na_mtime.tv_usec = IXDR_GET_U_INT32(ptr);
254 			na->na_ctime.tv_sec = IXDR_GET_U_INT32(ptr);
255 			na->na_ctime.tv_usec = IXDR_GET_U_INT32(ptr);
256 		} else {
257 			IXDR_PUT_ENUM(ptr, na->na_type);
258 			IXDR_PUT_U_INT32(ptr, na->na_mode);
259 			IXDR_PUT_U_INT32(ptr, na->na_nlink);
260 			IXDR_PUT_U_INT32(ptr, na->na_uid);
261 			IXDR_PUT_U_INT32(ptr, na->na_gid);
262 			IXDR_PUT_U_INT32(ptr, na->na_size);
263 			IXDR_PUT_U_INT32(ptr, na->na_blocksize);
264 			IXDR_PUT_U_INT32(ptr, na->na_rdev);
265 			IXDR_PUT_U_INT32(ptr, na->na_blocks);
266 			IXDR_PUT_U_INT32(ptr, na->na_fsid);
267 			IXDR_PUT_U_INT32(ptr, na->na_nodeid);
268 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_sec);
269 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_usec);
270 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_sec);
271 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_usec);
272 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_sec);
273 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_usec);
274 		}
275 		return (TRUE);
276 	}
277 
278 	if (xdr_enum(xdrs, (enum_t *)&na->na_type) &&
279 	    xdr_u_int(xdrs, &na->na_mode) &&
280 	    xdr_u_int(xdrs, &na->na_nlink) &&
281 	    xdr_u_int(xdrs, &na->na_uid) &&
282 	    xdr_u_int(xdrs, &na->na_gid) &&
283 	    xdr_u_int(xdrs, &na->na_size) &&
284 	    xdr_u_int(xdrs, &na->na_blocksize) &&
285 	    xdr_u_int(xdrs, &na->na_rdev) &&
286 	    xdr_u_int(xdrs, &na->na_blocks) &&
287 	    xdr_u_int(xdrs, &na->na_fsid) &&
288 	    xdr_u_int(xdrs, &na->na_nodeid) &&
289 	    xdr_nfs2_timeval(xdrs, &na->na_atime) &&
290 	    xdr_nfs2_timeval(xdrs, &na->na_mtime) &&
291 	    xdr_nfs2_timeval(xdrs, &na->na_ctime)) {
292 		return (TRUE);
293 	}
294 	return (FALSE);
295 }
296 
297 #ifdef _LITTLE_ENDIAN
298 bool_t
299 xdr_fastfattr(XDR *xdrs, struct nfsfattr *na)
300 {
301 	if (xdrs->x_op == XDR_FREE)
302 		return (TRUE);
303 	if (xdrs->x_op == XDR_DECODE)
304 		return (FALSE);
305 
306 	na->na_type = htonl(na->na_type);
307 	na->na_mode = htonl(na->na_mode);
308 	na->na_nlink = htonl(na->na_nlink);
309 	na->na_uid = htonl(na->na_uid);
310 	na->na_gid = htonl(na->na_gid);
311 	na->na_size = htonl(na->na_size);
312 	na->na_blocksize = htonl(na->na_blocksize);
313 	na->na_rdev = htonl(na->na_rdev);
314 	na->na_blocks = htonl(na->na_blocks);
315 	na->na_fsid = htonl(na->na_fsid);
316 	na->na_nodeid = htonl(na->na_nodeid);
317 	na->na_atime.tv_sec = htonl(na->na_atime.tv_sec);
318 	na->na_atime.tv_usec = htonl(na->na_atime.tv_usec);
319 	na->na_mtime.tv_sec = htonl(na->na_mtime.tv_sec);
320 	na->na_mtime.tv_usec = htonl(na->na_mtime.tv_usec);
321 	na->na_ctime.tv_sec = htonl(na->na_ctime.tv_sec);
322 	na->na_ctime.tv_usec = htonl(na->na_ctime.tv_usec);
323 	return (TRUE);
324 }
325 #endif
326 
327 /*
328  * Arguments to remote read
329  */
330 bool_t
331 xdr_readargs(XDR *xdrs, struct nfsreadargs *ra)
332 {
333 	int32_t *ptr;
334 	int32_t *fhp;
335 
336 	if (xdrs->x_op == XDR_FREE)
337 		return (TRUE);
338 
339 	ptr = XDR_INLINE(xdrs,
340 			RNDUP(sizeof (fhandle_t)) + 3 * BYTES_PER_XDR_UNIT);
341 	if (ptr != NULL) {
342 		if (xdrs->x_op == XDR_DECODE) {
343 			fhp = (int32_t *)&ra->ra_fhandle;
344 			*fhp++ = *ptr++;
345 			*fhp++ = *ptr++;
346 			*fhp++ = *ptr++;
347 			*fhp++ = *ptr++;
348 			*fhp++ = *ptr++;
349 			*fhp++ = *ptr++;
350 			*fhp++ = *ptr++;
351 			*fhp = *ptr++;
352 			ra->ra_offset = IXDR_GET_INT32(ptr);
353 			ra->ra_count = IXDR_GET_INT32(ptr);
354 			ra->ra_totcount = IXDR_GET_INT32(ptr);
355 		} else {
356 			fhp = (int32_t *)&ra->ra_fhandle;
357 			*ptr++ = *fhp++;
358 			*ptr++ = *fhp++;
359 			*ptr++ = *fhp++;
360 			*ptr++ = *fhp++;
361 			*ptr++ = *fhp++;
362 			*ptr++ = *fhp++;
363 			*ptr++ = *fhp++;
364 			*ptr++ = *fhp;
365 			IXDR_PUT_INT32(ptr, ra->ra_offset);
366 			IXDR_PUT_INT32(ptr, ra->ra_count);
367 			IXDR_PUT_INT32(ptr, ra->ra_totcount);
368 		}
369 		if (ra->ra_count > NFS_MAXDATA)
370 			return (FALSE);
371 		return (TRUE);
372 	}
373 
374 	if (xdr_fhandle(xdrs, &ra->ra_fhandle) &&
375 	    xdr_u_int(xdrs, &ra->ra_offset) &&
376 	    xdr_u_int(xdrs, &ra->ra_count) &&
377 	    xdr_u_int(xdrs, &ra->ra_totcount)) {
378 		if (ra->ra_count > NFS_MAXDATA)
379 			return (FALSE);
380 		return (TRUE);
381 	}
382 	return (FALSE);
383 }
384 
385 
386 /*
387  * Status OK portion of remote read reply
388  */
389 bool_t
390 xdr_rrok(XDR *xdrs, struct nfsrrok *rrok)
391 {
392 	bool_t ret;
393 	mblk_t *mp;
394 
395 	if (xdr_fattr(xdrs, &rrok->rrok_attr) == FALSE)
396 		return (FALSE);
397 
398 	if (xdrs->x_op == XDR_ENCODE) {
399 		int i, rndup;
400 
401 		mp = rrok->rrok_mp;
402 		if (mp != NULL && xdrs->x_ops == &xdrmblk_ops) {
403 			mp->b_wptr += rrok->rrok_count;
404 			rndup = BYTES_PER_XDR_UNIT -
405 				(rrok->rrok_count % BYTES_PER_XDR_UNIT);
406 			if (rndup != BYTES_PER_XDR_UNIT)
407 				for (i = 0; i < rndup; i++)
408 					*mp->b_wptr++ = '\0';
409 			if (xdrmblk_putmblk(xdrs, mp,
410 					    rrok->rrok_count) == TRUE) {
411 				rrok->rrok_mp = NULL;
412 				return (TRUE);
413 			}
414 		}
415 		/*
416 		 * Fall thru for the xdr_bytes()
417 		 *
418 		 * Note: the mblk mp will be freed in rfs_rdfree
419 		 */
420 	}
421 
422 	ret = xdr_bytes(xdrs, (char **)&rrok->rrok_data,
423 	    &rrok->rrok_count, NFS_MAXDATA);
424 
425 	return (ret);
426 }
427 
428 static struct xdr_discrim rdres_discrim[2] = {
429 	{ NFS_OK, xdr_rrok },
430 	{ __dontcare__, NULL_xdrproc_t }
431 };
432 
433 /*
434  * Reply from remote read
435  */
436 bool_t
437 xdr_rdresult(XDR *xdrs, struct nfsrdresult *rr)
438 {
439 	return (xdr_union(xdrs, (enum_t *)&(rr->rr_status),
440 	    (caddr_t)&(rr->rr_ok), rdres_discrim, xdr_void));
441 }
442 
443 /*
444  * File attributes which can be set
445  */
446 bool_t
447 xdr_sattr(XDR *xdrs, struct nfssattr *sa)
448 {
449 	if (xdr_u_int(xdrs, &sa->sa_mode) &&
450 	    xdr_u_int(xdrs, &sa->sa_uid) &&
451 	    xdr_u_int(xdrs, &sa->sa_gid) &&
452 	    xdr_u_int(xdrs, &sa->sa_size) &&
453 	    xdr_nfs2_timeval(xdrs, &sa->sa_atime) &&
454 	    xdr_nfs2_timeval(xdrs, &sa->sa_mtime)) {
455 		return (TRUE);
456 	}
457 	return (FALSE);
458 }
459 
460 static struct xdr_discrim attrstat_discrim[2] = {
461 	{ (int)NFS_OK, xdr_fattr },
462 	{ __dontcare__, NULL_xdrproc_t }
463 };
464 
465 /*
466  * Reply status with file attributes
467  */
468 bool_t
469 xdr_attrstat(XDR *xdrs, struct nfsattrstat *ns)
470 {
471 	return (xdr_union(xdrs, (enum_t *)&(ns->ns_status),
472 	    (caddr_t)&(ns->ns_attr), attrstat_discrim, xdr_void));
473 }
474 
475 /*
476  * Fast reply status with file attributes
477  */
478 bool_t
479 xdr_fastattrstat(XDR *xdrs, struct nfsattrstat *ns)
480 {
481 #if defined(_LITTLE_ENDIAN)
482 	/*
483 	 * we deal with the discriminator;  it's an enum
484 	 */
485 	if (!xdr_fastenum(xdrs, (enum_t *)&ns->ns_status))
486 		return (FALSE);
487 
488 	if (ns->ns_status == NFS_OK)
489 		return (xdr_fastfattr(xdrs, &ns->ns_attr));
490 #elif defined(_BIG_ENDIAN)
491 	if (ns->ns_status == NFS_OK)
492 		return (TRUE);
493 #endif
494 	return (xdr_fastshorten(xdrs, sizeof (*ns)));
495 }
496 
497 /*
498  * NFS_OK part of read sym link reply union
499  */
500 bool_t
501 xdr_srok(XDR *xdrs, struct nfssrok *srok)
502 {
503 	/*
504 	 * It is just as efficient to xdr_bytes
505 	 * an array of unknown length as to inline copy it.
506 	 */
507 	return (xdr_bytes(xdrs, &srok->srok_data, &srok->srok_count,
508 	    NFS_MAXPATHLEN));
509 }
510 
511 static struct xdr_discrim rdlnres_discrim[2] = {
512 	{ (int)NFS_OK, xdr_srok },
513 	{ __dontcare__, NULL_xdrproc_t }
514 };
515 
516 /*
517  * Result of reading symbolic link
518  */
519 bool_t
520 xdr_rdlnres(XDR *xdrs, struct nfsrdlnres *rl)
521 {
522 	return (xdr_union(xdrs, (enum_t *)&(rl->rl_status),
523 	    (caddr_t)&(rl->rl_srok), rdlnres_discrim, xdr_void));
524 }
525 
526 /*
527  * Arguments to readdir
528  */
529 bool_t
530 xdr_rddirargs(XDR *xdrs, struct nfsrddirargs *rda)
531 {
532 	int32_t *ptr;
533 	int32_t *fhp;
534 
535 	if (xdrs->x_op == XDR_FREE)
536 		return (TRUE);
537 
538 	ptr = XDR_INLINE(xdrs,
539 	    RNDUP(sizeof (fhandle_t)) + 2 * BYTES_PER_XDR_UNIT);
540 	if (ptr != NULL) {
541 		if (xdrs->x_op == XDR_DECODE) {
542 			fhp = (int32_t *)&rda->rda_fh;
543 			*fhp++ = *ptr++;
544 			*fhp++ = *ptr++;
545 			*fhp++ = *ptr++;
546 			*fhp++ = *ptr++;
547 			*fhp++ = *ptr++;
548 			*fhp++ = *ptr++;
549 			*fhp++ = *ptr++;
550 			*fhp = *ptr++;
551 			rda->rda_offset = IXDR_GET_U_INT32(ptr);
552 			rda->rda_count = IXDR_GET_U_INT32(ptr);
553 		} else {
554 			fhp = (int32_t *)&rda->rda_fh;
555 			*ptr++ = *fhp++;
556 			*ptr++ = *fhp++;
557 			*ptr++ = *fhp++;
558 			*ptr++ = *fhp++;
559 			*ptr++ = *fhp++;
560 			*ptr++ = *fhp++;
561 			*ptr++ = *fhp++;
562 			*ptr++ = *fhp;
563 			IXDR_PUT_U_INT32(ptr, rda->rda_offset);
564 			IXDR_PUT_U_INT32(ptr, rda->rda_count);
565 		}
566 		return (TRUE);
567 	}
568 
569 	if (xdr_fhandle(xdrs, &rda->rda_fh) &&
570 	    xdr_u_int(xdrs, &rda->rda_offset) &&
571 	    xdr_u_int(xdrs, &rda->rda_count)) {
572 		return (TRUE);
573 	}
574 	return (FALSE);
575 }
576 
577 
578 /*
579  * Directory read reply:
580  * union (enum status) {
581  *	NFS_OK: entlist;
582  *		boolean eof;
583  *	default:
584  * }
585  *
586  * Directory entries
587  *	struct  direct {
588  *		off_t   d_off;			* offset of next entry *
589  *		u_int	d_fileno;		* inode number of entry *
590  *		u_short d_reclen;		* length of this record *
591  *		u_short d_namlen;		* length of string in d_name *
592  *		char    d_name[MAXNAMLEN + 1];	* name no longer than this *
593  *	};
594  * are on the wire as:
595  * union entlist (boolean valid) {
596  * 	TRUE:	struct otw_dirent;
597  *		u_int nxtoffset;
598  *		union entlist;
599  *	FALSE:
600  * }
601  * where otw_dirent is:
602  * 	struct dirent {
603  *		u_int	de_fid;
604  *		string	de_name<NFS_MAXNAMELEN>;
605  *	}
606  */
607 
608 #ifdef nextdp
609 #undef	nextdp
610 #endif
611 #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
612 #ifdef roundup
613 #undef	roundup
614 #endif
615 #define	roundup(x, y)	((((x) + ((y) - 1)) / (y)) * (y))
616 
617 /*
618  * ENCODE ONLY
619  */
620 bool_t
621 xdr_putrddirres(XDR *xdrs, struct nfsrddirres *rd)
622 {
623 	struct dirent64 *dp;
624 	char *name;
625 	int size;
626 	uint_t namlen;
627 	bool_t true = TRUE;
628 	bool_t false = FALSE;
629 	int entrysz;
630 	int tofit;
631 	int bufsize;
632 	uint32_t ino, off;
633 
634 	if (xdrs->x_op != XDR_ENCODE)
635 		return (FALSE);
636 	if (!xdr_enum(xdrs, (enum_t *)&rd->rd_status))
637 		return (FALSE);
638 	if (rd->rd_status != NFS_OK)
639 		return (TRUE);
640 
641 	bufsize = 1 * BYTES_PER_XDR_UNIT;
642 	for (size = rd->rd_size, dp = rd->rd_entries;
643 		size > 0;
644 		size -= dp->d_reclen, dp = nextdp(dp)) {
645 		if (dp->d_reclen == 0 /* || DIRSIZ(dp) > dp->d_reclen */)
646 			return (FALSE);
647 		if (dp->d_ino == 0)
648 			continue;
649 		ino = (uint32_t)dp->d_ino; /* for LP64 we clip the bits */
650 		if (dp->d_ino != (ino64_t)ino)	/* and they better be zeros */
651 			return (FALSE);
652 		off = (uint32_t)dp->d_off;
653 		name = dp->d_name;
654 		namlen = (uint_t)strlen(name);
655 		entrysz = (1 + 1 + 1 + 1) * BYTES_PER_XDR_UNIT +
656 		    roundup(namlen, BYTES_PER_XDR_UNIT);
657 		tofit = entrysz + 2 * BYTES_PER_XDR_UNIT;
658 		if (bufsize + tofit > rd->rd_bufsize) {
659 			rd->rd_eof = FALSE;
660 			break;
661 		}
662 		if (!xdr_bool(xdrs, &true) ||
663 		    !xdr_u_int(xdrs, &ino) ||
664 		    !xdr_bytes(xdrs, &name, &namlen, NFS_MAXNAMLEN) ||
665 		    !xdr_u_int(xdrs, &off)) {
666 			return (FALSE);
667 		}
668 		bufsize += entrysz;
669 	}
670 	if (!xdr_bool(xdrs, &false))
671 		return (FALSE);
672 	if (!xdr_bool(xdrs, &rd->rd_eof))
673 		return (FALSE);
674 	return (TRUE);
675 }
676 
677 /*
678  * DECODE ONLY
679  */
680 bool_t
681 xdr_getrddirres(XDR *xdrs, struct nfsrddirres *rd)
682 {
683 	struct dirent64 *dp;
684 	uint_t namlen;
685 	int size;
686 	bool_t valid;
687 	uint32_t offset;
688 	uint_t fileid, this_reclen;
689 
690 	if (xdrs->x_op != XDR_DECODE)
691 		return (FALSE);
692 
693 	if (!xdr_enum(xdrs, (enum_t *)&rd->rd_status))
694 		return (FALSE);
695 	if (rd->rd_status != NFS_OK)
696 		return (TRUE);
697 
698 	size = rd->rd_size;
699 	dp = rd->rd_entries;
700 	offset = rd->rd_offset;
701 	for (;;) {
702 		if (!xdr_bool(xdrs, &valid))
703 			return (FALSE);
704 		if (!valid)
705 			break;
706 		if (!xdr_u_int(xdrs, &fileid) ||
707 		    !xdr_u_int(xdrs, &namlen))
708 			return (FALSE);
709 		this_reclen = DIRENT64_RECLEN(namlen);
710 		if (this_reclen > size) {
711 			rd->rd_eof = FALSE;
712 			goto bufovflw;
713 		}
714 		if (!xdr_opaque(xdrs, dp->d_name, namlen)||
715 		    !xdr_u_int(xdrs, &offset)) {
716 			return (FALSE);
717 		}
718 		bzero(&dp->d_name[namlen],
719 		    DIRENT64_NAMELEN(this_reclen) - namlen);
720 		dp->d_ino = (ino64_t)fileid;
721 		dp->d_reclen = this_reclen;
722 		dp->d_off = (off64_t)offset;
723 		size -= dp->d_reclen;
724 		dp = nextdp(dp);
725 	}
726 	if (!xdr_bool(xdrs, &rd->rd_eof))
727 		return (FALSE);
728 bufovflw:
729 	rd->rd_size = (uint32_t)((char *)dp - (char *)(rd->rd_entries));
730 	rd->rd_offset = offset;
731 	return (TRUE);
732 }
733 
734 /*
735  * Arguments for directory operations
736  */
737 bool_t
738 xdr_diropargs(XDR *xdrs, struct nfsdiropargs *da)
739 {
740 	int32_t *ptr;
741 	int32_t *fhp;
742 	uint32_t size;
743 	uint32_t nodesize;
744 	int i;
745 	int rndup;
746 	char *cptr;
747 
748 	if (xdrs->x_op == XDR_DECODE) {
749 		da->da_fhandle = &da->da_fhandle_buf;
750 		ptr = XDR_INLINE(xdrs, RNDUP(sizeof (fhandle_t)) +
751 		    1 * BYTES_PER_XDR_UNIT);
752 		if (ptr != NULL) {
753 			fhp = (int32_t *)da->da_fhandle;
754 			*fhp++ = *ptr++;
755 			*fhp++ = *ptr++;
756 			*fhp++ = *ptr++;
757 			*fhp++ = *ptr++;
758 			*fhp++ = *ptr++;
759 			*fhp++ = *ptr++;
760 			*fhp++ = *ptr++;
761 			*fhp = *ptr++;
762 			size = IXDR_GET_U_INT32(ptr);
763 			if (size > NFS_MAXNAMLEN)
764 				return (FALSE);
765 			nodesize = size + 1;
766 			if (nodesize == 0)
767 				return (TRUE);
768 			if (da->da_name == NULL) {
769 				da->da_name = kmem_alloc(nodesize, KM_NOSLEEP);
770 				if (da->da_name == NULL)
771 					return (FALSE);
772 				da->da_flags |= DA_FREENAME;
773 			}
774 			ptr = XDR_INLINE(xdrs, RNDUP(size));
775 			if (ptr == NULL) {
776 				if (!xdr_opaque(xdrs, da->da_name, size)) {
777 					if (da->da_flags & DA_FREENAME) {
778 						kmem_free(da->da_name,
779 						    nodesize);
780 						da->da_name = NULL;
781 					}
782 					return (FALSE);
783 				}
784 				da->da_name[size] = '\0';
785 				if (strlen(da->da_name) != size) {
786 					if (da->da_flags & DA_FREENAME) {
787 						kmem_free(da->da_name,
788 						    nodesize);
789 						da->da_name = NULL;
790 					}
791 					return (FALSE);
792 				}
793 				return (TRUE);
794 			}
795 			bcopy(ptr, da->da_name, size);
796 			da->da_name[size] = '\0';
797 			if (strlen(da->da_name) != size) {
798 				if (da->da_flags & DA_FREENAME) {
799 					kmem_free(da->da_name, nodesize);
800 					da->da_name = NULL;
801 				}
802 				return (FALSE);
803 			}
804 			return (TRUE);
805 		}
806 		if (da->da_name == NULL)
807 			da->da_flags |= DA_FREENAME;
808 	}
809 
810 	if (xdrs->x_op == XDR_ENCODE) {
811 		size = (uint32_t)strlen(da->da_name);
812 		if (size > NFS_MAXNAMLEN)
813 			return (FALSE);
814 		ptr = XDR_INLINE(xdrs, (int)(RNDUP(sizeof (fhandle_t)) +
815 		    1 * BYTES_PER_XDR_UNIT + RNDUP(size)));
816 		if (ptr != NULL) {
817 			fhp = (int32_t *)da->da_fhandle;
818 			*ptr++ = *fhp++;
819 			*ptr++ = *fhp++;
820 			*ptr++ = *fhp++;
821 			*ptr++ = *fhp++;
822 			*ptr++ = *fhp++;
823 			*ptr++ = *fhp++;
824 			*ptr++ = *fhp++;
825 			*ptr++ = *fhp;
826 			IXDR_PUT_U_INT32(ptr, (uint32_t)size);
827 			bcopy(da->da_name, ptr, size);
828 			rndup = BYTES_PER_XDR_UNIT -
829 				(size % BYTES_PER_XDR_UNIT);
830 			if (rndup != BYTES_PER_XDR_UNIT) {
831 				cptr = (char *)ptr + size;
832 				for (i = 0; i < rndup; i++)
833 					*cptr++ = '\0';
834 			}
835 			return (TRUE);
836 		}
837 	}
838 
839 	if (xdrs->x_op == XDR_FREE) {
840 		if (da->da_name == NULL)
841 			return (TRUE);
842 		size = (uint32_t)strlen(da->da_name);
843 		if (size > NFS_MAXNAMLEN)
844 			return (FALSE);
845 		if (da->da_flags & DA_FREENAME)
846 			kmem_free(da->da_name, size + 1);
847 		da->da_name = NULL;
848 		return (TRUE);
849 	}
850 
851 	if (xdr_fhandle(xdrs, da->da_fhandle) &&
852 	    xdr_string(xdrs, &da->da_name, NFS_MAXNAMLEN)) {
853 		return (TRUE);
854 	}
855 	return (FALSE);
856 }
857 
858 /*
859  * NFS_OK part of directory operation result
860  */
861 bool_t
862 xdr_drok(XDR *xdrs, struct nfsdrok *drok)
863 {
864 	int32_t *ptr;
865 	int32_t *fhp;
866 	struct nfsfattr *na;
867 
868 	if (xdrs->x_op == XDR_FREE)
869 		return (TRUE);
870 
871 	ptr = XDR_INLINE(xdrs,
872 	    RNDUP(sizeof (fhandle_t)) + 17 * BYTES_PER_XDR_UNIT);
873 	if (ptr != NULL) {
874 		if (xdrs->x_op == XDR_DECODE) {
875 			fhp = (int32_t *)&drok->drok_fhandle;
876 			*fhp++ = *ptr++;
877 			*fhp++ = *ptr++;
878 			*fhp++ = *ptr++;
879 			*fhp++ = *ptr++;
880 			*fhp++ = *ptr++;
881 			*fhp++ = *ptr++;
882 			*fhp++ = *ptr++;
883 			*fhp = *ptr++;
884 			na = &drok->drok_attr;
885 			na->na_type = IXDR_GET_ENUM(ptr, enum nfsftype);
886 			na->na_mode = IXDR_GET_U_INT32(ptr);
887 			na->na_nlink = IXDR_GET_U_INT32(ptr);
888 			na->na_uid = IXDR_GET_U_INT32(ptr);
889 			na->na_gid = IXDR_GET_U_INT32(ptr);
890 			na->na_size = IXDR_GET_U_INT32(ptr);
891 			na->na_blocksize = IXDR_GET_U_INT32(ptr);
892 			na->na_rdev = IXDR_GET_U_INT32(ptr);
893 			na->na_blocks = IXDR_GET_U_INT32(ptr);
894 			na->na_fsid = IXDR_GET_U_INT32(ptr);
895 			na->na_nodeid = IXDR_GET_U_INT32(ptr);
896 			na->na_atime.tv_sec = IXDR_GET_U_INT32(ptr);
897 			na->na_atime.tv_usec = IXDR_GET_U_INT32(ptr);
898 			na->na_mtime.tv_sec = IXDR_GET_U_INT32(ptr);
899 			na->na_mtime.tv_usec = IXDR_GET_U_INT32(ptr);
900 			na->na_ctime.tv_sec = IXDR_GET_U_INT32(ptr);
901 			na->na_ctime.tv_usec = IXDR_GET_U_INT32(ptr);
902 		} else {
903 			fhp = (int32_t *)&drok->drok_fhandle;
904 			*ptr++ = *fhp++;
905 			*ptr++ = *fhp++;
906 			*ptr++ = *fhp++;
907 			*ptr++ = *fhp++;
908 			*ptr++ = *fhp++;
909 			*ptr++ = *fhp++;
910 			*ptr++ = *fhp++;
911 			*ptr++ = *fhp;
912 			na = &drok->drok_attr;
913 			IXDR_PUT_ENUM(ptr, na->na_type);
914 			IXDR_PUT_U_INT32(ptr, na->na_mode);
915 			IXDR_PUT_U_INT32(ptr, na->na_nlink);
916 			IXDR_PUT_U_INT32(ptr, na->na_uid);
917 			IXDR_PUT_U_INT32(ptr, na->na_gid);
918 			IXDR_PUT_U_INT32(ptr, na->na_size);
919 			IXDR_PUT_U_INT32(ptr, na->na_blocksize);
920 			IXDR_PUT_U_INT32(ptr, na->na_rdev);
921 			IXDR_PUT_U_INT32(ptr, na->na_blocks);
922 			IXDR_PUT_U_INT32(ptr, na->na_fsid);
923 			IXDR_PUT_U_INT32(ptr, na->na_nodeid);
924 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_sec);
925 			IXDR_PUT_U_INT32(ptr, na->na_atime.tv_usec);
926 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_sec);
927 			IXDR_PUT_U_INT32(ptr, na->na_mtime.tv_usec);
928 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_sec);
929 			IXDR_PUT_U_INT32(ptr, na->na_ctime.tv_usec);
930 		}
931 		return (TRUE);
932 	}
933 
934 	if (xdr_fhandle(xdrs, &drok->drok_fhandle) &&
935 	    xdr_fattr(xdrs, &drok->drok_attr)) {
936 		return (TRUE);
937 	}
938 	return (FALSE);
939 }
940 
941 #ifdef _LITTLE_ENDIAN
942 bool_t
943 xdr_fastdrok(XDR *xdrs, struct nfsdrok *drok)
944 {
945 	struct nfsfattr *na;
946 
947 	if (xdrs->x_op == XDR_FREE)
948 		return (TRUE);
949 	if (xdrs->x_op == XDR_DECODE)
950 		return (FALSE);
951 
952 	na = &drok->drok_attr;
953 	na->na_type = (enum nfsftype)htonl(na->na_type);
954 	na->na_mode = (uint32_t)htonl(na->na_mode);
955 	na->na_nlink = (uint32_t)htonl(na->na_nlink);
956 	na->na_uid = (uint32_t)htonl(na->na_uid);
957 	na->na_gid = (uint32_t)htonl(na->na_gid);
958 	na->na_size = (uint32_t)htonl(na->na_size);
959 	na->na_blocksize = (uint32_t)htonl(na->na_blocksize);
960 	na->na_rdev = (uint32_t)htonl(na->na_rdev);
961 	na->na_blocks = (uint32_t)htonl(na->na_blocks);
962 	na->na_fsid = (uint32_t)htonl(na->na_fsid);
963 	na->na_nodeid = (uint32_t)htonl(na->na_nodeid);
964 	na->na_atime.tv_sec = htonl(na->na_atime.tv_sec);
965 	na->na_atime.tv_usec = htonl(na->na_atime.tv_usec);
966 	na->na_mtime.tv_sec = htonl(na->na_mtime.tv_sec);
967 	na->na_mtime.tv_usec = htonl(na->na_mtime.tv_usec);
968 	na->na_ctime.tv_sec = htonl(na->na_ctime.tv_sec);
969 	na->na_ctime.tv_usec = htonl(na->na_ctime.tv_usec);
970 	return (TRUE);
971 }
972 #endif
973 
974 static struct xdr_discrim diropres_discrim[2] = {
975 	{ NFS_OK, xdr_drok },
976 	{ __dontcare__, NULL_xdrproc_t }
977 };
978 
979 /*
980  * Results from directory operation
981  */
982 bool_t
983 xdr_diropres(XDR *xdrs, struct nfsdiropres *dr)
984 {
985 	return (xdr_union(xdrs, (enum_t *)&(dr->dr_status),
986 	    (caddr_t)&(dr->dr_drok), diropres_discrim, xdr_void));
987 }
988 
989 /*
990  * Results from directory operation
991  */
992 bool_t
993 xdr_fastdiropres(XDR *xdrs, struct nfsdiropres *dr)
994 {
995 #if defined(_LITTLE_ENDIAN)
996 	/*
997 	 * we deal with the discriminator;  it's an enum
998 	 */
999 	if (!xdr_fastenum(xdrs, (enum_t *)&dr->dr_status))
1000 		return (FALSE);
1001 
1002 	if (dr->dr_status == NFS_OK)
1003 		return (xdr_fastdrok(xdrs, &dr->dr_drok));
1004 #elif defined(_BIG_ENDIAN)
1005 	if (dr->dr_status == NFS_OK)
1006 		return (TRUE);
1007 #endif
1008 	return (xdr_fastshorten(xdrs, sizeof (*dr)));
1009 }
1010 
1011 /*
1012  * Time Structure, unsigned
1013  */
1014 bool_t
1015 xdr_nfs2_timeval(XDR *xdrs, struct nfs2_timeval *tv)
1016 {
1017 	if (xdr_u_int(xdrs, &tv->tv_sec) &&
1018 	    xdr_u_int(xdrs, &tv->tv_usec))
1019 		return (TRUE);
1020 	return (FALSE);
1021 }
1022 
1023 /*
1024  * arguments to setattr
1025  */
1026 bool_t
1027 xdr_saargs(XDR *xdrs, struct nfssaargs *argp)
1028 {
1029 	int32_t *ptr;
1030 	int32_t *arg;
1031 	struct nfssattr *sa;
1032 
1033 	if (xdrs->x_op == XDR_FREE)
1034 		return (TRUE);
1035 
1036 	ptr = XDR_INLINE(xdrs,
1037 	    RNDUP(sizeof (fhandle_t)) + 8 * BYTES_PER_XDR_UNIT);
1038 	if (ptr != NULL) {
1039 		if (xdrs->x_op == XDR_DECODE) {
1040 			arg = (int32_t *)&argp->saa_fh;
1041 			*arg++ = *ptr++;
1042 			*arg++ = *ptr++;
1043 			*arg++ = *ptr++;
1044 			*arg++ = *ptr++;
1045 			*arg++ = *ptr++;
1046 			*arg++ = *ptr++;
1047 			*arg++ = *ptr++;
1048 			*arg = *ptr++;
1049 			sa = &argp->saa_sa;
1050 			sa->sa_mode = IXDR_GET_U_INT32(ptr);
1051 			sa->sa_uid = IXDR_GET_U_INT32(ptr);
1052 			sa->sa_gid = IXDR_GET_U_INT32(ptr);
1053 			sa->sa_size = IXDR_GET_U_INT32(ptr);
1054 			sa->sa_atime.tv_sec = IXDR_GET_U_INT32(ptr);
1055 			sa->sa_atime.tv_usec = IXDR_GET_U_INT32(ptr);
1056 			sa->sa_mtime.tv_sec = IXDR_GET_U_INT32(ptr);
1057 			sa->sa_mtime.tv_usec = IXDR_GET_U_INT32(ptr);
1058 		} else {
1059 			arg = (int32_t *)&argp->saa_fh;
1060 			*ptr++ = *arg++;
1061 			*ptr++ = *arg++;
1062 			*ptr++ = *arg++;
1063 			*ptr++ = *arg++;
1064 			*ptr++ = *arg++;
1065 			*ptr++ = *arg++;
1066 			*ptr++ = *arg++;
1067 			*ptr++ = *arg;
1068 			sa = &argp->saa_sa;
1069 			IXDR_PUT_U_INT32(ptr, sa->sa_mode);
1070 			IXDR_PUT_U_INT32(ptr, sa->sa_uid);
1071 			IXDR_PUT_U_INT32(ptr, sa->sa_gid);
1072 			IXDR_PUT_U_INT32(ptr, sa->sa_size);
1073 			IXDR_PUT_U_INT32(ptr, sa->sa_atime.tv_sec);
1074 			IXDR_PUT_U_INT32(ptr, sa->sa_atime.tv_usec);
1075 			IXDR_PUT_U_INT32(ptr, sa->sa_mtime.tv_sec);
1076 			IXDR_PUT_U_INT32(ptr, sa->sa_mtime.tv_usec);
1077 		}
1078 		return (TRUE);
1079 	}
1080 
1081 	if (xdr_fhandle(xdrs, &argp->saa_fh) &&
1082 	    xdr_sattr(xdrs, &argp->saa_sa)) {
1083 		return (TRUE);
1084 	}
1085 	return (FALSE);
1086 }
1087 
1088 
1089 /*
1090  * arguments to create and mkdir
1091  */
1092 bool_t
1093 xdr_creatargs(XDR *xdrs, struct nfscreatargs *argp)
1094 {
1095 	argp->ca_sa = &argp->ca_sa_buf;
1096 
1097 	if (xdrs->x_op == XDR_DECODE)
1098 		argp->ca_sa = &argp->ca_sa_buf;
1099 	if (xdr_diropargs(xdrs, &argp->ca_da) &&
1100 	    xdr_sattr(xdrs, argp->ca_sa)) {
1101 		return (TRUE);
1102 	}
1103 	return (FALSE);
1104 }
1105 
1106 /*
1107  * arguments to link
1108  */
1109 bool_t
1110 xdr_linkargs(XDR *xdrs, struct nfslinkargs *argp)
1111 {
1112 	if (xdrs->x_op == XDR_DECODE)
1113 		argp->la_from = &argp->la_from_buf;
1114 	if (xdr_fhandle(xdrs, argp->la_from) &&
1115 	    xdr_diropargs(xdrs, &argp->la_to)) {
1116 		return (TRUE);
1117 	}
1118 	return (FALSE);
1119 }
1120 
1121 /*
1122  * arguments to rename
1123  */
1124 bool_t
1125 xdr_rnmargs(XDR *xdrs, struct nfsrnmargs *argp)
1126 {
1127 	if (xdr_diropargs(xdrs, &argp->rna_from) &&
1128 	    xdr_diropargs(xdrs, &argp->rna_to))
1129 		return (TRUE);
1130 	return (FALSE);
1131 }
1132 
1133 
1134 /*
1135  * arguments to symlink
1136  */
1137 bool_t
1138 xdr_slargs(XDR *xdrs, struct nfsslargs *argp)
1139 {
1140 	if (xdrs->x_op == XDR_FREE) {
1141 		if (!xdr_diropargs(xdrs, &argp->sla_from))
1142 			return (FALSE);
1143 		if ((argp->sla_tnm_flags & SLA_FREETNM) &&
1144 		    !xdr_string(xdrs, &argp->sla_tnm, (uint_t)NFS_MAXPATHLEN))
1145 			return (FALSE);
1146 		return (TRUE);
1147 	}
1148 
1149 	if (xdrs->x_op == XDR_DECODE) {
1150 		argp->sla_sa = &argp->sla_sa_buf;
1151 		if (argp->sla_tnm == NULL)
1152 			argp->sla_tnm_flags |= SLA_FREETNM;
1153 	}
1154 
1155 	if (xdr_diropargs(xdrs, &argp->sla_from) &&
1156 	    xdr_string(xdrs, &argp->sla_tnm, (uint_t)NFS_MAXPATHLEN) &&
1157 	    xdr_sattr(xdrs, argp->sla_sa)) {
1158 		return (TRUE);
1159 	}
1160 	return (FALSE);
1161 }
1162 
1163 
1164 /*
1165  * NFS_OK part of statfs operation
1166  */
1167 bool_t
1168 xdr_fsok(XDR *xdrs, struct nfsstatfsok *fsok)
1169 {
1170 	int32_t *ptr;
1171 
1172 	if (xdrs->x_op == XDR_FREE)
1173 		return (TRUE);
1174 
1175 	ptr = XDR_INLINE(xdrs, 5 * BYTES_PER_XDR_UNIT);
1176 	if (ptr != NULL) {
1177 		if (xdrs->x_op == XDR_DECODE) {
1178 			fsok->fsok_tsize = IXDR_GET_INT32(ptr);
1179 			fsok->fsok_bsize = IXDR_GET_INT32(ptr);
1180 			fsok->fsok_blocks = IXDR_GET_INT32(ptr);
1181 			fsok->fsok_bfree = IXDR_GET_INT32(ptr);
1182 			fsok->fsok_bavail = IXDR_GET_INT32(ptr);
1183 		} else {
1184 			IXDR_PUT_INT32(ptr, fsok->fsok_tsize);
1185 			IXDR_PUT_INT32(ptr, fsok->fsok_bsize);
1186 			IXDR_PUT_INT32(ptr, fsok->fsok_blocks);
1187 			IXDR_PUT_INT32(ptr, fsok->fsok_bfree);
1188 			IXDR_PUT_INT32(ptr, fsok->fsok_bavail);
1189 		}
1190 		return (TRUE);
1191 	}
1192 
1193 	if (xdr_u_int(xdrs, &fsok->fsok_tsize) &&
1194 	    xdr_u_int(xdrs, &fsok->fsok_bsize) &&
1195 	    xdr_u_int(xdrs, &fsok->fsok_blocks) &&
1196 	    xdr_u_int(xdrs, &fsok->fsok_bfree) &&
1197 	    xdr_u_int(xdrs, &fsok->fsok_bavail)) {
1198 		return (TRUE);
1199 	}
1200 	return (FALSE);
1201 }
1202 
1203 #ifdef _LITTLE_ENDIAN
1204 bool_t
1205 xdr_fastfsok(XDR *xdrs, struct nfsstatfsok *fsok)
1206 {
1207 
1208 	if (xdrs->x_op == XDR_FREE)
1209 		return (TRUE);
1210 	if (xdrs->x_op == XDR_DECODE)
1211 		return (FALSE);
1212 
1213 	fsok->fsok_tsize = htonl(fsok->fsok_tsize);
1214 	fsok->fsok_bsize = htonl(fsok->fsok_bsize);
1215 	fsok->fsok_blocks = htonl(fsok->fsok_blocks);
1216 	fsok->fsok_bfree = htonl(fsok->fsok_bfree);
1217 	fsok->fsok_bavail = htonl(fsok->fsok_bavail);
1218 	return (TRUE);
1219 }
1220 #endif
1221 
1222 static struct xdr_discrim statfs_discrim[2] = {
1223 	{ NFS_OK, xdr_fsok },
1224 	{ __dontcare__, NULL_xdrproc_t }
1225 };
1226 
1227 /*
1228  * Results of statfs operation
1229  */
1230 bool_t
1231 xdr_statfs(XDR *xdrs, struct nfsstatfs *fs)
1232 {
1233 	return (xdr_union(xdrs, (enum_t *)&(fs->fs_status),
1234 	    (caddr_t)&(fs->fs_fsok), statfs_discrim, xdr_void));
1235 }
1236 
1237 /*
1238  * Results of statfs operation
1239  */
1240 bool_t
1241 xdr_faststatfs(XDR *xdrs, struct nfsstatfs *fs)
1242 {
1243 #if defined(_LITTLE_ENDIAN)
1244 	/*
1245 	 * we deal with the discriminator;  it's an enum
1246 	 */
1247 	if (!xdr_fastenum(xdrs, (enum_t *)&fs->fs_status))
1248 		return (FALSE);
1249 
1250 	if (fs->fs_status == NFS_OK)
1251 		return (xdr_fastfsok(xdrs, &fs->fs_fsok));
1252 #elif defined(_BIG_ENDIAN)
1253 	if (fs->fs_status == NFS_OK)
1254 		return (TRUE);
1255 #endif
1256 	return (xdr_fastshorten(xdrs, sizeof (*fs)));
1257 }
1258 
1259 #ifdef _LITTLE_ENDIAN
1260 /*
1261  * XDR enumerations
1262  */
1263 #ifndef lint
1264 static enum sizecheck { SIZEVAL } sizecheckvar;	/* used to find the size of */
1265 						/* an enum */
1266 #endif
1267 bool_t
1268 xdr_fastenum(XDR *xdrs, enum_t *ep)
1269 {
1270 	if (xdrs->x_op == XDR_FREE)
1271 		return (TRUE);
1272 	if (xdrs->x_op == XDR_DECODE)
1273 		return (FALSE);
1274 
1275 #ifndef lint
1276 	/*
1277 	 * enums are treated as ints
1278 	 */
1279 	if (sizeof (sizecheckvar) == sizeof (int32_t)) {
1280 		*ep = (enum_t)htonl((int32_t)(*ep));
1281 	} else if (sizeof (sizecheckvar) == sizeof (short)) {
1282 		*ep = (enum_t)htons((short)(*ep));
1283 	} else {
1284 		return (FALSE);
1285 	}
1286 	return (TRUE);
1287 #else
1288 	(void) (xdr_short(xdrs, (short *)ep));
1289 	return (xdr_int(xdrs, (int *)ep));
1290 #endif
1291 }
1292 #endif
1293 
1294 static bool_t
1295 xdr_fastshorten(XDR *xdrs, uint_t ressize)
1296 {
1297 	uint_t curpos;
1298 
1299 	curpos = XDR_GETPOS(xdrs);
1300 	ressize -= BYTES_PER_XDR_UNIT;
1301 	curpos -= ressize;
1302 	return (XDR_SETPOS(xdrs, curpos));
1303 }
1304