xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/nfs/rpc/xdr.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  */
9 /* @(#)xdr.c	2.1 88/07/29 4.0 RPCSRC */
10 /*
11  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
12  * unrestricted use provided that this legend is included on all tape
13  * media and as a part of the software program in whole or part.  Users
14  * may copy or modify Sun RPC without charge, but are not authorized
15  * to license or distribute it to anyone else except as part of a product or
16  * program developed by the user.
17  *
18  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
19  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
21  *
22  * Sun RPC is provided with no support and without any obligation on the
23  * part of Sun Microsystems, Inc. to assist in its use, correction,
24  * modification or enhancement.
25  *
26  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
27  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
28  * OR ANY PART THEREOF.
29  *
30  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
31  * or profits or other special, indirect and consequential damages, even if
32  * Sun has been advised of the possibility of such damages.
33  *
34  * Sun Microsystems, Inc.
35  * 2550 Garcia Avenue
36  * Mountain View, California  94043
37  */
38 #if !defined(lint) && defined(SCCSIDS)
39 static char sccsid[] = "@(#)xdr.c 1.35 87/08/12";
40 #endif
41 
42 /*
43  * xdr.c, Generic XDR routines implementation.
44  *
45  * Copyright (C) 1986, Sun Microsystems, Inc.
46  *
47  * These are the "generic" xdr routines used to serialize and de-serialize
48  * most common data items.  See xdr.h for more info on the interface to
49  * xdr.
50  */
51 
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <rpc/types.h>
55 #include <rpc/xdr.h>
56 #include <string.h>
57 
58 /*
59  * constants specific to the xdr "protocol"
60  */
61 #define XDR_FALSE		((long) 0)
62 #define XDR_TRUE		((long) 1)
63 #define LASTUNSIGNED	((unsigned int) 0-1)
64 
65 /*
66  * for unit alignment
67  */
68 static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
69 
70 /*
71  * Free a data structure using XDR
72  * Not a filter, but a convenient utility nonetheless
73  */
xdr_free(xdrproc_t proc,char * objp)74 void xdr_free(xdrproc_t proc, char* objp)
75 {
76 	XDR x;
77 
78 	x.x_op = XDR_FREE;
79 	(*proc) (&x, objp);
80 }
81 
82 /*
83  * XDR nothing
84  */
xdr_void()85 bool_t xdr_void( /* xdrs, addr */ )
86 	/* XDR *xdrs; */
87 	/* char* addr; */
88 {
89 
90 	return (TRUE);
91 }
92 
93 /*
94  * XDR integers
95  */
xdr_int(XDR * xdrs,int * ip)96 bool_t xdr_int(XDR* xdrs, int* ip)
97 {
98 	if (sizeof(int) == sizeof(long)) {
99 		return (xdr_long(xdrs, (long *) ip));
100 	} else if (sizeof(int) < sizeof(long)) {
101 	  long l;
102 	  switch (xdrs->x_op) {
103 	  case XDR_ENCODE:
104 		l = (long) *ip;
105 		return XDR_PUTLONG(xdrs, &l);
106 	  case XDR_DECODE:
107 		if (!XDR_GETLONG(xdrs, &l))
108 		  return FALSE;
109 		*ip = (int) l;
110 	  case XDR_FREE:
111 		return TRUE;
112 	  }
113 	  return FALSE;
114 	} else {
115 		return (xdr_short(xdrs, (short *) ip));
116 	}
117 }
118 
119 /*
120  * XDR unsigned integers
121  */
xdr_u_int(XDR * xdrs,unsigned int * up)122 bool_t xdr_u_int(XDR* xdrs, unsigned int* up)
123 {
124 	if (sizeof(unsigned int) == sizeof(unsigned long)) {
125 		return (xdr_u_long(xdrs, (unsigned long *) up));
126 	} else if (sizeof(unsigned int) < sizeof(unsigned long)) {
127 	  unsigned long l;
128 	  switch (xdrs->x_op) {
129 	  case XDR_ENCODE:
130 		l = (unsigned long) *up;
131 		return XDR_PUTLONG(xdrs, (long*)&l);
132 	  case XDR_DECODE:
133 		if (!XDR_GETLONG(xdrs, (long*)&l))
134 		  return FALSE;
135 		*up = (unsigned int) l;
136 	  case XDR_FREE:
137 		return TRUE;
138 	  }
139 	  return FALSE;
140 	} else {
141 		return (xdr_short(xdrs, (short *) up));
142 	}
143 }
144 
145 /*
146  * XDR long integers
147  * same as xdr_u_long - open coded to save a proc call!
148  */
xdr_long(XDR * xdrs,long * lp)149 bool_t xdr_long(XDR* xdrs, long* lp)
150 {
151 
152 	if (xdrs->x_op == XDR_ENCODE
153 		&& (sizeof(int32_t) == sizeof(long)
154 			|| (int32_t) *lp == *lp))
155 		return (XDR_PUTLONG(xdrs, lp));
156 
157 	if (xdrs->x_op == XDR_DECODE)
158 		return (XDR_GETLONG(xdrs, lp));
159 
160 	if (xdrs->x_op == XDR_FREE)
161 		return (TRUE);
162 
163 	return (FALSE);
164 }
165 
166 /*
167  * XDR unsigned long integers
168  * same as xdr_long - open coded to save a proc call!
169  */
xdr_u_long(XDR * xdrs,unsigned long * ulp)170 bool_t xdr_u_long(XDR* xdrs, unsigned long* ulp)
171 {
172 
173   if (xdrs->x_op == XDR_DECODE) {
174 	long l;
175 	if (XDR_GETLONG(xdrs, &l) == FALSE)
176 	  return FALSE;
177 	*ulp = (uint32_t) l;
178 	return TRUE;
179   }
180 
181   if (xdrs->x_op == XDR_ENCODE) {
182 	if (sizeof(uint32_t) != sizeof(unsigned long)
183 		&& (uint32_t) *ulp != *ulp)
184 	  return FALSE;
185 
186 		return (XDR_PUTLONG(xdrs, (long *) ulp));
187   }
188 
189 	if (xdrs->x_op == XDR_FREE)
190 		return (TRUE);
191 
192 	return (FALSE);
193 }
194 
195 
196 /*
197  * XDR long long integers
198  */
xdr_longlong_t(XDR * xdrs,long long * llp)199 bool_t xdr_longlong_t (XDR * xdrs, long long* llp)
200 {
201   int32_t t1, t2;
202 
203   switch (xdrs->x_op)
204     {
205     case XDR_ENCODE:
206       t1 = (int32_t) ((*llp) >> 32);
207       t2 = (int32_t) (*llp);
208       return (XDR_PUTLONG (xdrs, &t1) && XDR_PUTLONG (xdrs, &t2));
209 
210     case XDR_DECODE:
211       if (!XDR_GETLONG (xdrs, &t1) || !XDR_GETLONG (xdrs, &t2))
212         return FALSE;
213       *llp = ((int64_t) t1) << 32;
214       *llp |= (uint32_t) t2;
215       return TRUE;
216 
217     case XDR_FREE:
218       return TRUE;
219     }
220   return FALSE;
221 }
222 
223 /*
224  * XDR unsigned long long integers
225  */
xdr_u_longlong_t(XDR * xdrs,unsigned long long * ullp)226 bool_t xdr_u_longlong_t (XDR * xdrs, unsigned long long* ullp)
227 {
228   uint32_t t1, t2;
229 
230   switch (xdrs->x_op)
231     {
232     case XDR_ENCODE:
233       t1 = (uint32_t) ((*ullp) >> 32);
234       t2 = (uint32_t) (*ullp);
235       return (XDR_PUTLONG (xdrs, (int32_t *)&t1) &&
236               XDR_PUTLONG (xdrs, (int32_t *)&t2));
237 
238     case XDR_DECODE:
239       if (!XDR_GETLONG (xdrs, (int32_t *)&t1) ||
240           !XDR_GETLONG (xdrs, (int32_t *)&t2))
241         return FALSE;
242       *ullp = ((uint64_t) t1) << 32;
243       *ullp |= t2;
244       return TRUE;
245 
246     case XDR_FREE:
247       return TRUE;
248     }
249   return FALSE;
250 }
251 
252 /*
253  * XDR short integers
254  */
xdr_short(XDR * xdrs,short * sp)255 bool_t xdr_short(XDR* xdrs, short* sp)
256 {
257 	long l;
258 
259 	switch (xdrs->x_op) {
260 
261 	case XDR_ENCODE:
262 		l = (long) *sp;
263 		return (XDR_PUTLONG(xdrs, &l));
264 
265 	case XDR_DECODE:
266 		if (!XDR_GETLONG(xdrs, &l)) {
267 			return (FALSE);
268 		}
269 		*sp = (short) l;
270 		return (TRUE);
271 
272 	case XDR_FREE:
273 		return (TRUE);
274 	}
275 	return (FALSE);
276 }
277 
278 /*
279  * XDR unsigned short integers
280  */
xdr_u_short(XDR * xdrs,unsigned short * usp)281 bool_t xdr_u_short(XDR* xdrs, unsigned short* usp)
282 {
283 	unsigned long l;
284 
285 	switch (xdrs->x_op) {
286 
287 	case XDR_ENCODE:
288 		l = (unsigned long) * usp;
289 		return (XDR_PUTLONG(xdrs, (long*)&l));
290 
291 	case XDR_DECODE:
292 		if (!XDR_GETLONG(xdrs, (long*)&l)) {
293 			return (FALSE);
294 		}
295 		*usp = (unsigned short) l;
296 		return (TRUE);
297 
298 	case XDR_FREE:
299 		return (TRUE);
300 	}
301 	return (FALSE);
302 }
303 
304 
305 /*
306  * XDR a char
307  */
xdr_char(XDR * xdrs,char * cp)308 bool_t xdr_char(XDR* xdrs, char* cp)
309 {
310 	int i;
311 
312 	i = (*cp);
313 	if (!xdr_int(xdrs, &i)) {
314 		return (FALSE);
315 	}
316 	*cp = i;
317 	return (TRUE);
318 }
319 
320 /*
321  * XDR an unsigned char
322  */
xdr_u_char(XDR * xdrs,unsigned char * cp)323 bool_t xdr_u_char(XDR* xdrs, unsigned char* cp)
324 {
325 	unsigned int u;
326 
327 	u = (*cp);
328 	if (!xdr_u_int(xdrs, &u)) {
329 		return (FALSE);
330 	}
331 	*cp = u;
332 	return (TRUE);
333 }
334 
335 /*
336  * XDR booleans
337  */
xdr_bool(XDR * xdrs,bool_t * bp)338 bool_t xdr_bool(XDR *xdrs, bool_t *bp)
339 {
340 	long lb;
341 
342 	switch (xdrs->x_op) {
343 
344 	case XDR_ENCODE:
345 		lb = *bp ? XDR_TRUE : XDR_FALSE;
346 		return (XDR_PUTLONG(xdrs, &lb));
347 
348 	case XDR_DECODE:
349 		if (!XDR_GETLONG(xdrs, &lb)) {
350 			return (FALSE);
351 		}
352 		*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
353 		return (TRUE);
354 
355 	case XDR_FREE:
356 		return (TRUE);
357 	}
358 	return (FALSE);
359 }
360 
361 /*
362  * XDR enumerations
363  */
xdr_enum(XDR * xdrs,enum_t * ep)364 bool_t xdr_enum(XDR *xdrs, enum_t *ep)
365 {
366 	/*
367 	 * enums are treated as ints
368 	 */
369 	return (xdr_long(xdrs, (long *) ep));
370 }
371 
372 /*
373  * XDR opaque data
374  * Allows the specification of a fixed size sequence of opaque bytes.
375  * cp points to the opaque object and cnt gives the byte length.
376  */
xdr_opaque(XDR * xdrs,char * cp,unsigned int cnt)377 bool_t xdr_opaque(XDR *xdrs, char* cp, unsigned int cnt)
378 {
379 	register unsigned int rndup;
380 	static char crud[BYTES_PER_XDR_UNIT];
381 
382 	/*
383 	 * if no data we are done
384 	 */
385 	if (cnt == 0)
386 		return (TRUE);
387 
388 	/*
389 	 * round byte count to full xdr units
390 	 */
391 	rndup = cnt % BYTES_PER_XDR_UNIT;
392 	if (rndup > 0)
393 		rndup = BYTES_PER_XDR_UNIT - rndup;
394 
395 	if (xdrs->x_op == XDR_DECODE) {
396 		if (!XDR_GETBYTES(xdrs, cp, cnt)) {
397 			return (FALSE);
398 		}
399 		if (rndup == 0)
400 			return (TRUE);
401 		return (XDR_GETBYTES(xdrs, crud, rndup));
402 	}
403 
404 	if (xdrs->x_op == XDR_ENCODE) {
405 		if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
406 			return (FALSE);
407 		}
408 		if (rndup == 0)
409 			return (TRUE);
410 		return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
411 	}
412 
413 	if (xdrs->x_op == XDR_FREE) {
414 		return (TRUE);
415 	}
416 
417 	return (FALSE);
418 }
419 
420 /*
421  * XDR counted bytes
422  * *cpp is a pointer to the bytes, *sizep is the count.
423  * If *cpp is NULL maxsize bytes are allocated
424  */
xdr_bytes(XDR * xdrs,char ** cpp,unsigned int * sizep,unsigned int maxsize)425 bool_t xdr_bytes(XDR *xdrs, char** cpp, unsigned int *sizep, unsigned int maxsize)
426 {
427 	register char *sp = *cpp;	/* sp is the actual string pointer */
428 	register unsigned int nodesize;
429 
430 	/*
431 	 * first deal with the length since xdr bytes are counted
432 	 */
433 	if (!xdr_u_int(xdrs, sizep)) {
434 		return (FALSE);
435 	}
436 	nodesize = *sizep;
437 	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
438 		return (FALSE);
439 	}
440 
441 	/*
442 	 * now deal with the actual bytes
443 	 */
444 	switch (xdrs->x_op) {
445 
446 	case XDR_DECODE:
447 		if (nodesize == 0) {
448 			return (TRUE);
449 		}
450 		if (sp == NULL) {
451 			*cpp = sp = (char *) rt_malloc(nodesize);
452 		}
453 		if (sp == NULL) {
454 			rt_kprintf("xdr_bytes: out of memory\n");
455 			return (FALSE);
456 		}
457 		/* fall into ... */
458 
459 	case XDR_ENCODE:
460 		return (xdr_opaque(xdrs, sp, nodesize));
461 
462 	case XDR_FREE:
463 		if (sp != NULL) {
464 			rt_free(sp);
465 			*cpp = NULL;
466 		}
467 		return (TRUE);
468 	}
469 	return (FALSE);
470 }
471 
472 /*
473  * Implemented here due to commonality of the object.
474  */
xdr_netobj(XDR * xdrs,struct netobj * np)475 bool_t xdr_netobj(XDR *xdrs, struct netobj *np)
476 {
477 	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
478 }
479 
480 /*
481  * XDR a descriminated union
482  * Support routine for discriminated unions.
483  * You create an array of xdrdiscrim structures, terminated with
484  * an entry with a null procedure pointer.  The routine gets
485  * the discriminant value and then searches the array of xdrdiscrims
486  * looking for that value.  It calls the procedure given in the xdrdiscrim
487  * to handle the discriminant.  If there is no specific routine a default
488  * routine may be called.
489  * If there is no specific or default routine an error is returned.
490  */
xdr_union(XDR * xdrs,enum_t * dscmp,char * unp,const struct xdr_discrim * choices,xdrproc_t dfault)491 bool_t xdr_union(XDR* xdrs, enum_t* dscmp, char* unp, const struct xdr_discrim* choices, xdrproc_t dfault)
492 {
493 	register enum_t dscm;
494 
495 	/*
496 	 * we deal with the discriminator;  it's an enum
497 	 */
498 	if (!xdr_enum(xdrs, dscmp)) {
499 		return (FALSE);
500 	}
501 	dscm = *dscmp;
502 
503 	/*
504 	 * search choices for a value that matches the discriminator.
505 	 * if we find one, execute the xdr routine for that value.
506 	 */
507 	for (; choices->proc != NULL_xdrproc_t; choices++) {
508 		if (choices->value == dscm)
509 			return ((*(choices->proc)) (xdrs, unp, LASTUNSIGNED));
510 	}
511 
512 	/*
513 	 * no match - execute the default xdr routine if there is one
514 	 */
515 	return ((dfault == NULL_xdrproc_t) ? FALSE :
516 			(*dfault) (xdrs, unp, LASTUNSIGNED));
517 }
518 
519 
520 /*
521  * Non-portable xdr primitives.
522  * Care should be taken when moving these routines to new architectures.
523  */
524 
525 
526 /*
527  * XDR null terminated ASCII strings
528  * xdr_string deals with "C strings" - arrays of bytes that are
529  * terminated by a NULL character.  The parameter cpp references a
530  * pointer to storage; If the pointer is null, then the necessary
531  * storage is allocated.  The last parameter is the max allowed length
532  * of the string as specified by a protocol.
533  */
xdr_string(XDR * xdrs,char ** cpp,unsigned int maxsize)534 bool_t xdr_string(XDR *xdrs, char **cpp, unsigned int maxsize)
535 {
536 	register char *sp = *cpp;	/* sp is the actual string pointer */
537 	unsigned int size;
538 	unsigned int nodesize;
539 
540 	/*
541 	 * first deal with the length since xdr strings are counted-strings
542 	 */
543 	switch (xdrs->x_op) {
544 	case XDR_FREE:
545 		if (sp == NULL) {
546 			return (TRUE);		/* already free */
547 		}
548 		/* fall through... */
549 	case XDR_ENCODE:
550 		size = strlen(sp);
551 		break;
552 	}
553 	if (!xdr_u_int(xdrs, &size)) {
554 		return (FALSE);
555 	}
556 	if (size > maxsize) {
557 		return (FALSE);
558 	}
559 	nodesize = size + 1;
560 
561 	/*
562 	 * now deal with the actual bytes
563 	 */
564 	switch (xdrs->x_op) {
565 
566 	case XDR_DECODE:
567 		if (nodesize == 0) {
568 			return (TRUE);
569 		}
570 		if (sp == NULL)
571 			*cpp = sp = (char *) rt_malloc(nodesize);
572 		if (sp == NULL) {
573 			rt_kprintf("xdr_string: out of memory\n");
574 			return (FALSE);
575 		}
576 		sp[size] = 0;
577 		/* fall into ... */
578 
579 	case XDR_ENCODE:
580 		return (xdr_opaque(xdrs, sp, size));
581 
582 	case XDR_FREE:
583 		rt_free(sp);
584 		*cpp = NULL;
585 		return (TRUE);
586 	}
587 	return (FALSE);
588 }
589 
590 /*
591  * Wrapper for xdr_string that can be called directly from
592  * routines like clnt_call
593  */
xdr_wrapstring(XDR * xdrs,char ** cpp)594 bool_t xdr_wrapstring(XDR *xdrs, char **cpp)
595 {
596 	if (xdr_string(xdrs, cpp, LASTUNSIGNED)) {
597 		return (TRUE);
598 	}
599 	return (FALSE);
600 }
601 
602 /*
603  * XDR an array of arbitrary elements
604  * *addrp is a pointer to the array, *sizep is the number of elements.
605  * If addrp is NULL (*sizep * elsize) bytes are allocated.
606  * elsize is the size (in bytes) of each element, and elproc is the
607  * xdr procedure to call to handle each element of the array.
608  */
xdr_array(XDR * xdrs,char ** addrp,unsigned int * sizep,unsigned int maxsize,unsigned int elsize,xdrproc_t elproc)609 bool_t xdr_array(XDR *xdrs, char **addrp, unsigned int *sizep, unsigned int maxsize, unsigned int elsize, xdrproc_t elproc)
610 {
611 	register unsigned int i;
612 	register char* target = *addrp;
613 	register unsigned int c;			/* the actual element count */
614 	register bool_t stat = TRUE;
615 	register unsigned int nodesize;
616 
617 	/* like strings, arrays are really counted arrays */
618 	if (!xdr_u_int(xdrs, sizep)) {
619 		return (FALSE);
620 	}
621 	c = *sizep;
622 	if ((c > maxsize) && (xdrs->x_op != XDR_FREE)) {
623 		return (FALSE);
624 	}
625 	/* duh, look for integer overflow (fefe) */
626 	{
627 	  unsigned int i;
628 	  nodesize = 0;
629 	  for (i=c; i; --i) {
630 	    unsigned int tmp=nodesize+elsize;
631 	    if (tmp<nodesize)	/* overflow */
632 	      return FALSE;
633 	    nodesize=tmp;
634 	  }
635 	}
636 
637 	/*
638 	 * if we are deserializing, we may need to allocate an array.
639 	 * We also save time by checking for a null array if we are freeing.
640 	 */
641 	if (target == NULL)
642 		switch (xdrs->x_op) {
643 		case XDR_DECODE:
644 			if (c == 0)
645 				return (TRUE);
646 			*addrp = target = rt_malloc(nodesize);
647 			if (target == NULL) {
648 				rt_kprintf("xdr_array: out of memory\n");
649 				return (FALSE);
650 			}
651 			memset(target, 0, nodesize);
652 			break;
653 
654 		case XDR_FREE:
655 			return (TRUE);
656 		}
657 
658 	/*
659 	 * now we xdr each element of array
660 	 */
661 	for (i = 0; (i < c) && stat; i++) {
662 		stat = (*elproc) (xdrs, target, LASTUNSIGNED);
663 		target += elsize;
664 	}
665 
666 	/*
667 	 * the array may need freeing
668 	 */
669 	if (xdrs->x_op == XDR_FREE) {
670 		rt_free(*addrp);
671 		*addrp = NULL;
672 	}
673 	return (stat);
674 }
675 
676 /*
677  * xdr_vector():
678  *
679  * XDR a fixed length array. Unlike variable-length arrays,
680  * the storage of fixed length arrays is static and unfreeable.
681  * > basep: base of the array
682  * > size: size of the array
683  * > elemsize: size of each element
684  * > xdr_elem: routine to XDR each element
685  */
xdr_vector(XDR * xdrs,char * basep,unsigned int nelem,unsigned int elemsize,xdrproc_t xdr_elem)686 bool_t xdr_vector(XDR *xdrs, char *basep, unsigned int nelem, unsigned int elemsize, xdrproc_t xdr_elem)
687 {
688 	register unsigned int i;
689 	register char *elptr;
690 
691 	elptr = basep;
692 	for (i = 0; i < nelem; i++) {
693 		if (!(*xdr_elem) (xdrs, elptr, LASTUNSIGNED)) {
694 			return (FALSE);
695 		}
696 		elptr += elemsize;
697 	}
698 	return (TRUE);
699 }
700 
701 
702 /*
703  * XDR an indirect pointer
704  * xdr_reference is for recursively translating a structure that is
705  * referenced by a pointer inside the structure that is currently being
706  * translated.  pp references a pointer to storage. If *pp is null
707  * the  necessary storage is allocated.
708  * size is the sizeof the referneced structure.
709  * proc is the routine to handle the referenced structure.
710  */
xdr_reference(XDR * xdrs,char ** pp,unsigned int size,xdrproc_t proc)711 bool_t xdr_reference(XDR *xdrs, char **pp, unsigned int size, xdrproc_t proc)
712 {
713 	register char* loc = *pp;
714 	register bool_t stat;
715 
716 	if (loc == NULL)
717 		switch (xdrs->x_op) {
718 		case XDR_FREE:
719 			return (TRUE);
720 
721 		case XDR_DECODE:
722 			*pp = loc = (char*) rt_malloc(size);
723 			if (loc == NULL) {
724 				rt_kprintf("xdr_reference: out of memory\n");
725 				return (FALSE);
726 			}
727 			memset(loc, 0, (int) size);
728 			break;
729 		}
730 
731 	stat = (*proc) (xdrs, loc, LASTUNSIGNED);
732 
733 	if (xdrs->x_op == XDR_FREE) {
734 		rt_free(loc);
735 		*pp = NULL;
736 	}
737 	return (stat);
738 }
739 
740 
741 /*
742  * xdr_pointer():
743  *
744  * XDR a pointer to a possibly recursive data structure. This
745  * differs with xdr_reference in that it can serialize/deserialiaze
746  * trees correctly.
747  *
748  *  What's sent is actually a union:
749  *
750  *  union object_pointer switch (boolean b) {
751  *  case TRUE: object_data data;
752  *  case FALSE: void nothing;
753  *  }
754  *
755  * > objpp: Pointer to the pointer to the object.
756  * > obj_size: size of the object.
757  * > xdr_obj: routine to XDR an object.
758  *
759  */
xdr_pointer(XDR * xdrs,char ** objpp,unsigned int obj_size,xdrproc_t xdr_obj)760 bool_t xdr_pointer(XDR *xdrs, char **objpp, unsigned int obj_size, xdrproc_t xdr_obj)
761 {
762 
763 	bool_t more_data;
764 
765 	more_data = (*objpp != NULL);
766 	if (!xdr_bool(xdrs, &more_data)) {
767 		return (FALSE);
768 	}
769 	if (!more_data) {
770 		*objpp = NULL;
771 		return (TRUE);
772 	}
773 	return (xdr_reference(xdrs, objpp, obj_size, xdr_obj));
774 }
775