Home | History | Annotate | Line # | Download | only in rpc
xdr_rec.c revision 1.11
      1 /*	$NetBSD: xdr_rec.c,v 1.11 1998/02/12 01:57:54 lukem Exp $	*/
      2 
      3 /*
      4  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
      5  * unrestricted use provided that this legend is included on all tape
      6  * media and as a part of the software program in whole or part.  Users
      7  * may copy or modify Sun RPC without charge, but are not authorized
      8  * to license or distribute it to anyone else except as part of a product or
      9  * program developed by the user.
     10  *
     11  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
     12  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
     13  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
     14  *
     15  * Sun RPC is provided with no support and without any obligation on the
     16  * part of Sun Microsystems, Inc. to assist in its use, correction,
     17  * modification or enhancement.
     18  *
     19  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
     20  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
     21  * OR ANY PART THEREOF.
     22  *
     23  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
     24  * or profits or other special, indirect and consequential damages, even if
     25  * Sun has been advised of the possibility of such damages.
     26  *
     27  * Sun Microsystems, Inc.
     28  * 2550 Garcia Avenue
     29  * Mountain View, California  94043
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 #if defined(LIBC_SCCS) && !defined(lint)
     34 #if 0
     35 static char *sccsid = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";
     36 static char *sccsid = "@(#)xdr_rec.c	2.2 88/08/01 4.0 RPCSRC";
     37 #else
     38 __RCSID("$NetBSD: xdr_rec.c,v 1.11 1998/02/12 01:57:54 lukem Exp $");
     39 #endif
     40 #endif
     41 
     42 /*
     43  * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
     44  * layer above tcp (for rpc's use).
     45  *
     46  * Copyright (C) 1984, Sun Microsystems, Inc.
     47  *
     48  * These routines interface XDRSTREAMS to a tcp/ip connection.
     49  * There is a record marking layer between the xdr stream
     50  * and the tcp transport level.  A record is composed on one or more
     51  * record fragments.  A record fragment is a thirty-two bit header followed
     52  * by n bytes of data, where n is contained in the header.  The header
     53  * is represented as a htonl(u_long).  Thegh order bit encodes
     54  * whether or not the fragment is the last fragment of the record
     55  * (1 => fragment is last, 0 => more fragments to follow.
     56  * The other 31 bits encode the byte length of the fragment.
     57  */
     58 
     59 #include "namespace.h"
     60 #include <stdio.h>
     61 #include <stdlib.h>
     62 #include <string.h>
     63 #include <rpc/types.h>
     64 #include <rpc/xdr.h>
     65 #include <netinet/in.h>
     66 
     67 #ifdef __weak_alias
     68 __weak_alias(xdrrec_create,_xdrrec_create);
     69 __weak_alias(xdrrec_endofrecord,_xdrrec_endofrecord);
     70 __weak_alias(xdrrec_eof,_xdrrec_eof);
     71 __weak_alias(xdrrec_skiprecord,_xdrrec_skiprecord);
     72 #endif
     73 
     74 static bool_t	xdrrec_getlong __P((XDR *, long *));
     75 static bool_t	xdrrec_putlong __P((XDR *, long *));
     76 static bool_t	xdrrec_getbytes __P((XDR *, caddr_t, u_int));
     77 
     78 static bool_t	xdrrec_putbytes __P((XDR *, caddr_t, u_int));
     79 static u_int	xdrrec_getpos __P((XDR *));
     80 static bool_t	xdrrec_setpos __P((XDR *, u_int));
     81 static int32_t *xdrrec_inline __P((XDR *, u_int));
     82 static void	xdrrec_destroy __P((XDR *));
     83 
     84 static struct  xdr_ops xdrrec_ops = {
     85 	xdrrec_getlong,
     86 	xdrrec_putlong,
     87 	xdrrec_getbytes,
     88 	xdrrec_putbytes,
     89 	xdrrec_getpos,
     90 	xdrrec_setpos,
     91 	xdrrec_inline,
     92 	xdrrec_destroy
     93 };
     94 
     95 /*
     96  * A record is composed of one or more record fragments.
     97  * A record fragment is a two-byte header followed by zero to
     98  * 2**32-1 bytes.  The header is treated as a long unsigned and is
     99  * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
    100  * are a byte count of the fragment.  The highest order bit is a boolean:
    101  * 1 => this fragment is the last fragment of the record,
    102  * 0 => this fragment is followed by more fragment(s).
    103  *
    104  * The fragment/record machinery is not general;  it is constructed to
    105  * meet the needs of xdr and rpc based on tcp.
    106  */
    107 
    108 #define LAST_FRAG ((u_int32_t)(1 << 31))
    109 
    110 typedef struct rec_strm {
    111 	caddr_t tcp_handle;
    112 	caddr_t the_buffer;
    113 	/*
    114 	 * out-goung bits
    115 	 */
    116 	int (*writeit) __P((caddr_t, caddr_t, int));
    117 	caddr_t out_base;	/* output buffer (points to frag header) */
    118 	caddr_t out_finger;	/* next output position */
    119 	caddr_t out_boundry;	/* data cannot up to this address */
    120 	u_int32_t *frag_header;	/* beginning of curren fragment */
    121 	bool_t frag_sent;	/* true if buffer sent in middle of record */
    122 	/*
    123 	 * in-coming bits
    124 	 */
    125 	int (*readit) __P((caddr_t, caddr_t, int));
    126 	u_long in_size;	/* fixed size of the input buffer */
    127 	caddr_t in_base;
    128 	caddr_t in_finger;	/* location of next byte to be had */
    129 	caddr_t in_boundry;	/* can read up to this location */
    130 	long fbtbc;		/* fragment bytes to be consumed */
    131 	bool_t last_frag;
    132 	u_int sendsize;
    133 	u_int recvsize;
    134 } RECSTREAM;
    135 
    136 static u_int	fix_buf_size __P((u_int));
    137 static bool_t	flush_out __P((RECSTREAM *, bool_t));
    138 static bool_t	fill_input_buf __P((RECSTREAM *));
    139 static bool_t	get_input_bytes __P((RECSTREAM *, caddr_t, int));
    140 static bool_t	set_input_fragment __P((RECSTREAM *));
    141 static bool_t	skip_input_bytes __P((RECSTREAM *, long));
    142 
    143 
    144 /*
    145  * Create an xdr handle for xdrrec
    146  * xdrrec_create fills in xdrs.  Sendsize and recvsize are
    147  * send and recv buffer sizes (0 => use default).
    148  * tcp_handle is an opaque handle that is passed as the first parameter to
    149  * the procedures readit and writeit.  Readit and writeit are read and
    150  * write respectively.   They are like the system
    151  * calls expect that they take an opaque handle rather than an fd.
    152  */
    153 void
    154 xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit)
    155 	register XDR *xdrs;
    156 	register u_int sendsize;
    157 	register u_int recvsize;
    158 	caddr_t tcp_handle;
    159 	/* like read, but pass it a tcp_handle, not sock */
    160 	int (*readit) __P((caddr_t, caddr_t, int));
    161 	/* like write, but pass it a tcp_handle, not sock */
    162 	int (*writeit) __P((caddr_t, caddr_t, int));
    163 {
    164 	register RECSTREAM *rstrm =
    165 		(RECSTREAM *)mem_alloc(sizeof(RECSTREAM));
    166 
    167 	if (rstrm == NULL) {
    168 		(void)fprintf(stderr, "xdrrec_create: out of memory\n");
    169 		/*
    170 		 *  This is bad.  Should rework xdrrec_create to
    171 		 *  return a handle, and in this case return NULL
    172 		 */
    173 		return;
    174 	}
    175 	/*
    176 	 * adjust sizes and allocate buffer quad byte aligned
    177 	 */
    178 	rstrm->sendsize = sendsize = fix_buf_size(sendsize);
    179 	rstrm->recvsize = recvsize = fix_buf_size(recvsize);
    180 	rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT);
    181 	if (rstrm->the_buffer == NULL) {
    182 		(void)fprintf(stderr, "xdrrec_create: out of memory\n");
    183 		return;
    184 	}
    185 	for (rstrm->out_base = rstrm->the_buffer;
    186 		(u_long)rstrm->out_base % BYTES_PER_XDR_UNIT != 0;
    187 		rstrm->out_base++);
    188 	rstrm->in_base = rstrm->out_base + sendsize;
    189 	/*
    190 	 * now the rest ...
    191 	 */
    192 	xdrs->x_ops = &xdrrec_ops;
    193 	xdrs->x_private = (caddr_t)rstrm;
    194 	rstrm->tcp_handle = tcp_handle;
    195 	rstrm->readit = readit;
    196 	rstrm->writeit = writeit;
    197 	rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
    198 	rstrm->frag_header = (u_int32_t *)rstrm->out_base;
    199 	rstrm->out_finger += sizeof(u_int32_t);
    200 	rstrm->out_boundry += sendsize;
    201 	rstrm->frag_sent = FALSE;
    202 	rstrm->in_size = recvsize;
    203 	rstrm->in_boundry = rstrm->in_base;
    204 	rstrm->in_finger = (rstrm->in_boundry += recvsize);
    205 	rstrm->fbtbc = 0;
    206 	rstrm->last_frag = TRUE;
    207 }
    208 
    209 
    210 /*
    211  * The reoutines defined below are the xdr ops which will go into the
    212  * xdr handle filled in by xdrrec_create.
    213  */
    214 
    215 static bool_t
    216 xdrrec_getlong(xdrs, lp)
    217 	XDR *xdrs;
    218 	long *lp;
    219 {
    220 	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
    221 	register int32_t *buflp = (int32_t *)(rstrm->in_finger);
    222 	int32_t mylong;
    223 
    224 	/* first try the inline, fast case */
    225 	if ((rstrm->fbtbc >= sizeof(int32_t)) &&
    226 		(((long)rstrm->in_boundry - (long)buflp) >= sizeof(int32_t))) {
    227 		*lp = (long)ntohl((u_int32_t)(*buflp));
    228 		rstrm->fbtbc -= sizeof(int32_t);
    229 		rstrm->in_finger += sizeof(int32_t);
    230 	} else {
    231 		if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(int32_t)))
    232 			return (FALSE);
    233 		*lp = (long)ntohl((u_int32_t)mylong);
    234 	}
    235 	return (TRUE);
    236 }
    237 
    238 static bool_t
    239 xdrrec_putlong(xdrs, lp)
    240 	XDR *xdrs;
    241 	long *lp;
    242 {
    243 	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
    244 	register int32_t *dest_lp = ((int32_t *)(rstrm->out_finger));
    245 
    246 	if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) {
    247 		/*
    248 		 * this case should almost never happen so the code is
    249 		 * inefficient
    250 		 */
    251 		rstrm->out_finger -= sizeof(int32_t);
    252 		rstrm->frag_sent = TRUE;
    253 		if (! flush_out(rstrm, FALSE))
    254 			return (FALSE);
    255 		dest_lp = ((int32_t *)(rstrm->out_finger));
    256 		rstrm->out_finger += sizeof(int32_t);
    257 	}
    258 	*dest_lp = (int32_t)htonl((u_int32_t)(*lp));
    259 	return (TRUE);
    260 }
    261 
    262 static bool_t  /* must manage buffers, fragments, and records */
    263 xdrrec_getbytes(xdrs, addr, len)
    264 	XDR *xdrs;
    265 	register caddr_t addr;
    266 	register u_int len;
    267 {
    268 	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
    269 	register int current;
    270 
    271 	while (len > 0) {
    272 		current = rstrm->fbtbc;
    273 		if (current == 0) {
    274 			if (rstrm->last_frag)
    275 				return (FALSE);
    276 			if (! set_input_fragment(rstrm))
    277 				return (FALSE);
    278 			continue;
    279 		}
    280 		current = (len < current) ? len : current;
    281 		if (! get_input_bytes(rstrm, addr, current))
    282 			return (FALSE);
    283 		addr += current;
    284 		rstrm->fbtbc -= current;
    285 		len -= current;
    286 	}
    287 	return (TRUE);
    288 }
    289 
    290 static bool_t
    291 xdrrec_putbytes(xdrs, addr, len)
    292 	XDR *xdrs;
    293 	register caddr_t addr;
    294 	register u_int len;
    295 {
    296 	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
    297 	register long current;
    298 
    299 	while (len > 0) {
    300 		current = (u_long)rstrm->out_boundry -
    301 		    (u_long)rstrm->out_finger;
    302 		current = (len < current) ? len : current;
    303 		bcopy(addr, rstrm->out_finger, current);
    304 		rstrm->out_finger += current;
    305 		addr += current;
    306 		len -= current;
    307 		if (rstrm->out_finger == rstrm->out_boundry) {
    308 			rstrm->frag_sent = TRUE;
    309 			if (! flush_out(rstrm, FALSE))
    310 				return (FALSE);
    311 		}
    312 	}
    313 	return (TRUE);
    314 }
    315 
    316 static u_int
    317 xdrrec_getpos(xdrs)
    318 	register XDR *xdrs;
    319 {
    320 	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
    321 	register long pos;
    322 
    323 	pos = lseek((off_t)(long)rstrm->tcp_handle, 0, 1);
    324 	if (pos != -1)
    325 		switch (xdrs->x_op) {
    326 
    327 		case XDR_ENCODE:
    328 			pos += rstrm->out_finger - rstrm->out_base;
    329 			break;
    330 
    331 		case XDR_DECODE:
    332 			pos -= rstrm->in_boundry - rstrm->in_finger;
    333 			break;
    334 
    335 		default:
    336 			pos = (u_int) -1;
    337 			break;
    338 		}
    339 	return ((u_int) pos);
    340 }
    341 
    342 static bool_t
    343 xdrrec_setpos(xdrs, pos)
    344 	register XDR *xdrs;
    345 	u_int pos;
    346 {
    347 	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
    348 	u_int currpos = xdrrec_getpos(xdrs);
    349 	int delta = currpos - pos;
    350 	caddr_t newpos;
    351 
    352 	if ((int)currpos != -1)
    353 		switch (xdrs->x_op) {
    354 
    355 		case XDR_ENCODE:
    356 			newpos = rstrm->out_finger - delta;
    357 			if ((newpos > (caddr_t)(rstrm->frag_header)) &&
    358 				(newpos < rstrm->out_boundry)) {
    359 				rstrm->out_finger = newpos;
    360 				return (TRUE);
    361 			}
    362 			break;
    363 
    364 		case XDR_DECODE:
    365 			newpos = rstrm->in_finger - delta;
    366 			if ((delta < (int)(rstrm->fbtbc)) &&
    367 				(newpos <= rstrm->in_boundry) &&
    368 				(newpos >= rstrm->in_base)) {
    369 				rstrm->in_finger = newpos;
    370 				rstrm->fbtbc -= delta;
    371 				return (TRUE);
    372 			}
    373 			break;
    374 
    375 		case XDR_FREE:
    376 			break;
    377 		}
    378 	return (FALSE);
    379 }
    380 
    381 static int32_t *
    382 xdrrec_inline(xdrs, len)
    383 	register XDR *xdrs;
    384 	u_int len;
    385 {
    386 	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
    387 	int32_t *buf = NULL;
    388 
    389 	switch (xdrs->x_op) {
    390 
    391 	case XDR_ENCODE:
    392 		if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
    393 			buf = (int32_t *) rstrm->out_finger;
    394 			rstrm->out_finger += len;
    395 		}
    396 		break;
    397 
    398 	case XDR_DECODE:
    399 		if ((len <= rstrm->fbtbc) &&
    400 			((rstrm->in_finger + len) <= rstrm->in_boundry)) {
    401 			buf = (int32_t *) rstrm->in_finger;
    402 			rstrm->fbtbc -= len;
    403 			rstrm->in_finger += len;
    404 		}
    405 		break;
    406 
    407 	case XDR_FREE:
    408 		break;
    409 	}
    410 	return (buf);
    411 }
    412 
    413 static void
    414 xdrrec_destroy(xdrs)
    415 	register XDR *xdrs;
    416 {
    417 	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
    418 
    419 	mem_free(rstrm->the_buffer,
    420 		rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
    421 	mem_free((caddr_t)rstrm, sizeof(RECSTREAM));
    422 }
    423 
    424 
    425 /*
    426  * Exported routines to manage xdr records
    427  */
    428 
    429 /*
    430  * Before reading (deserializing from the stream, one should always call
    431  * this procedure to guarantee proper record alignment.
    432  */
    433 bool_t
    434 xdrrec_skiprecord(xdrs)
    435 	XDR *xdrs;
    436 {
    437 	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
    438 
    439 	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
    440 		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
    441 			return (FALSE);
    442 		rstrm->fbtbc = 0;
    443 		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
    444 			return (FALSE);
    445 	}
    446 	rstrm->last_frag = FALSE;
    447 	return (TRUE);
    448 }
    449 
    450 /*
    451  * Look ahead fuction.
    452  * Returns TRUE iff there is no more input in the buffer
    453  * after consuming the rest of the current record.
    454  */
    455 bool_t
    456 xdrrec_eof(xdrs)
    457 	XDR *xdrs;
    458 {
    459 	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
    460 
    461 	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
    462 		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
    463 			return (TRUE);
    464 		rstrm->fbtbc = 0;
    465 		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
    466 			return (TRUE);
    467 	}
    468 	if (rstrm->in_finger == rstrm->in_boundry)
    469 		return (TRUE);
    470 	return (FALSE);
    471 }
    472 
    473 /*
    474  * The client must tell the package when an end-of-record has occurred.
    475  * The second paraemters tells whether the record should be flushed to the
    476  * (output) tcp stream.  (This let's the package support batched or
    477  * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection.
    478  */
    479 bool_t
    480 xdrrec_endofrecord(xdrs, sendnow)
    481 	XDR *xdrs;
    482 	bool_t sendnow;
    483 {
    484 	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
    485 	register u_long len;  /* fragment length */
    486 
    487 	if (sendnow || rstrm->frag_sent ||
    488 		((u_long)rstrm->out_finger + sizeof(u_int32_t) >=
    489 		(u_long)rstrm->out_boundry)) {
    490 		rstrm->frag_sent = FALSE;
    491 		return (flush_out(rstrm, TRUE));
    492 	}
    493 	len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) -
    494 	   sizeof(u_int32_t);
    495 	*(rstrm->frag_header) = htonl((u_long)len | LAST_FRAG);
    496 	rstrm->frag_header = (u_int32_t *)rstrm->out_finger;
    497 	rstrm->out_finger += sizeof(u_int32_t);
    498 	return (TRUE);
    499 }
    500 
    501 
    502 /*
    503  * Internal useful routines
    504  */
    505 static bool_t
    506 flush_out(rstrm, eor)
    507 	register RECSTREAM *rstrm;
    508 	bool_t eor;
    509 {
    510 	register u_long eormask = (eor == TRUE) ? LAST_FRAG : 0;
    511 	register u_int32_t len = (u_long)(rstrm->out_finger) -
    512 		(u_long)(rstrm->frag_header) - sizeof(u_int32_t);
    513 
    514 	*(rstrm->frag_header) = htonl(len | eormask);
    515 	len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->out_base);
    516 	if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
    517 		!= (int)len)
    518 		return (FALSE);
    519 	rstrm->frag_header = (u_int32_t *)rstrm->out_base;
    520 	rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(u_int32_t);
    521 	return (TRUE);
    522 }
    523 
    524 static bool_t  /* knows nothing about records!  Only about input buffers */
    525 fill_input_buf(rstrm)
    526 	register RECSTREAM *rstrm;
    527 {
    528 	register caddr_t where;
    529 	u_long i;
    530 	register long len;
    531 
    532 	where = rstrm->in_base;
    533 	i = (u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT;
    534 	where += i;
    535 	len = rstrm->in_size - i;
    536 	if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
    537 		return (FALSE);
    538 	rstrm->in_finger = where;
    539 	where += len;
    540 	rstrm->in_boundry = where;
    541 	return (TRUE);
    542 }
    543 
    544 static bool_t  /* knows nothing about records!  Only about input buffers */
    545 get_input_bytes(rstrm, addr, len)
    546 	register RECSTREAM *rstrm;
    547 	register caddr_t addr;
    548 	register int len;
    549 {
    550 	register long current;
    551 
    552 	while (len > 0) {
    553 		current = (long)rstrm->in_boundry - (long)rstrm->in_finger;
    554 		if (current == 0) {
    555 			if (! fill_input_buf(rstrm))
    556 				return (FALSE);
    557 			continue;
    558 		}
    559 		current = (len < current) ? len : current;
    560 		bcopy(rstrm->in_finger, addr, current);
    561 		rstrm->in_finger += current;
    562 		addr += current;
    563 		len -= current;
    564 	}
    565 	return (TRUE);
    566 }
    567 
    568 static bool_t  /* next two bytes of the input stream are treated as a header */
    569 set_input_fragment(rstrm)
    570 	register RECSTREAM *rstrm;
    571 {
    572 	u_int32_t header;
    573 
    574 	if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header)))
    575 		return (FALSE);
    576 	header = (long)ntohl(header);
    577 	rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
    578 	rstrm->fbtbc = header & (~LAST_FRAG);
    579 	return (TRUE);
    580 }
    581 
    582 static bool_t  /* consumes input bytes; knows nothing about records! */
    583 skip_input_bytes(rstrm, cnt)
    584 	register RECSTREAM *rstrm;
    585 	long cnt;
    586 {
    587 	register long current;
    588 
    589 	while (cnt > 0) {
    590 		current = (long)rstrm->in_boundry - (long)rstrm->in_finger;
    591 		if (current == 0) {
    592 			if (! fill_input_buf(rstrm))
    593 				return (FALSE);
    594 			continue;
    595 		}
    596 		current = (cnt < current) ? cnt : current;
    597 		rstrm->in_finger += current;
    598 		cnt -= current;
    599 	}
    600 	return (TRUE);
    601 }
    602 
    603 static u_int
    604 fix_buf_size(s)
    605 	register u_int s;
    606 {
    607 
    608 	if (s < 100)
    609 		s = 4000;
    610 	return (RNDUP(s));
    611 }
    612