Annotation of src/usr.bin/rsync/io.c, Revision 1.21
1.21 ! claudio 1: /* $OpenBSD: io.c,v 1.20 2021/06/30 13:10:04 claudio Exp $ */
1.1 benno 2: /*
3: * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <sys/stat.h>
18:
19: #include <assert.h>
20: #include <endian.h>
21: #include <errno.h>
22: #include <poll.h>
23: #include <stdint.h>
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <unistd.h>
28:
29: #include "extern.h"
1.7 florian 30:
31: /*
32: * A non-blocking check to see whether there's POLLIN data in fd.
33: * Returns <0 on failure, 0 if there's no data, >0 if there is.
34: */
1.1 benno 35: int
1.17 benno 36: io_read_check(int fd)
1.1 benno 37: {
38: struct pollfd pfd;
39:
40: pfd.fd = fd;
41: pfd.events = POLLIN;
42:
1.18 deraadt 43: if (poll(&pfd, 1, 0) == -1) {
1.16 benno 44: ERR("poll");
1.1 benno 45: return -1;
46: }
1.7 florian 47: return (pfd.revents & POLLIN);
1.1 benno 48: }
49:
50: /*
51: * Write buffer to non-blocking descriptor.
52: * Returns zero on failure, non-zero on success (zero or more bytes).
1.7 florian 53: * On success, fills in "sz" with the amount written.
1.1 benno 54: */
55: static int
1.17 benno 56: io_write_nonblocking(int fd, const void *buf, size_t bsz,
1.5 deraadt 57: size_t *sz)
1.1 benno 58: {
59: struct pollfd pfd;
60: ssize_t wsz;
1.6 florian 61: int c;
1.1 benno 62:
63: *sz = 0;
64:
1.4 deraadt 65: if (bsz == 0)
1.1 benno 66: return 1;
67:
68: pfd.fd = fd;
69: pfd.events = POLLOUT;
70:
1.7 florian 71: /* Poll and check for all possible errors. */
72:
1.19 claudio 73: if ((c = poll(&pfd, 1, poll_timeout)) == -1) {
1.16 benno 74: ERR("poll");
1.1 benno 75: return 0;
1.6 florian 76: } else if (c == 0) {
1.16 benno 77: ERRX("poll: timeout");
1.6 florian 78: return 0;
1.7 florian 79: } else if ((pfd.revents & (POLLERR|POLLNVAL))) {
1.16 benno 80: ERRX("poll: bad fd");
1.1 benno 81: return 0;
82: } else if ((pfd.revents & POLLHUP)) {
1.16 benno 83: ERRX("poll: hangup");
1.1 benno 84: return 0;
1.3 deraadt 85: } else if (!(pfd.revents & POLLOUT)) {
1.16 benno 86: ERRX("poll: unknown event");
1.1 benno 87: return 0;
88: }
89:
1.7 florian 90: /* Now the non-blocking write. */
91:
1.18 deraadt 92: if ((wsz = write(fd, buf, bsz)) == -1) {
1.16 benno 93: ERR("write");
1.1 benno 94: return 0;
95: }
96:
97: *sz = wsz;
98: return 1;
99: }
100:
101: /*
102: * Blocking write of the full size of the buffer.
103: * Returns 0 on failure, non-zero on success (all bytes written).
104: */
105: static int
1.17 benno 106: io_write_blocking(int fd, const void *buf, size_t sz)
1.1 benno 107: {
108: size_t wsz;
109: int c;
110:
111: while (sz > 0) {
1.17 benno 112: c = io_write_nonblocking(fd, buf, sz, &wsz);
1.3 deraadt 113: if (!c) {
1.16 benno 114: ERRX1("io_write_nonblocking");
1.1 benno 115: return 0;
1.4 deraadt 116: } else if (wsz == 0) {
1.16 benno 117: ERRX("io_write_nonblocking: short write");
1.1 benno 118: return 0;
119: }
120: buf += wsz;
121: sz -= wsz;
122: }
123:
124: return 1;
125: }
126:
127: /*
128: * Write "buf" of size "sz" to non-blocking descriptor.
129: * Returns zero on failure, non-zero on success (all bytes written to
130: * the descriptor).
131: */
132: int
133: io_write_buf(struct sess *sess, int fd, const void *buf, size_t sz)
134: {
135: int32_t tag, tagbuf;
136: size_t wsz;
137: int c;
138:
1.3 deraadt 139: if (!sess->mplex_writes) {
1.17 benno 140: c = io_write_blocking(fd, buf, sz);
1.1 benno 141: sess->total_write += sz;
142: return c;
143: }
144:
145: while (sz > 0) {
1.21 ! claudio 146: wsz = (sz < 0xFFFFFF) ? sz : 0xFFFFFF;
1.1 benno 147: tag = (7 << 24) + wsz;
148: tagbuf = htole32(tag);
1.17 benno 149: if (!io_write_blocking(fd, &tagbuf, sizeof(tagbuf))) {
1.16 benno 150: ERRX1("io_write_blocking");
1.1 benno 151: return 0;
152: }
1.17 benno 153: if (!io_write_blocking(fd, buf, wsz)) {
1.16 benno 154: ERRX1("io_write_blocking");
1.1 benno 155: return 0;
156: }
157: sess->total_write += wsz;
158: sz -= wsz;
159: buf += wsz;
160: }
161:
162: return 1;
163: }
164:
165: /*
166: * Write "line" (NUL-terminated) followed by a newline.
167: * Returns zero on failure, non-zero on succcess.
168: */
169: int
170: io_write_line(struct sess *sess, int fd, const char *line)
171: {
172:
1.3 deraadt 173: if (!io_write_buf(sess, fd, line, strlen(line)))
1.16 benno 174: ERRX1("io_write_buf");
1.3 deraadt 175: else if (!io_write_byte(sess, fd, '\n'))
1.16 benno 176: ERRX1("io_write_byte");
1.1 benno 177: else
178: return 1;
179:
180: return 0;
181: }
182:
183: /*
184: * Read buffer from non-blocking descriptor.
185: * Returns zero on failure, non-zero on success (zero or more bytes).
186: */
187: static int
1.17 benno 188: io_read_nonblocking(int fd, void *buf, size_t bsz, size_t *sz)
1.1 benno 189: {
190: struct pollfd pfd;
191: ssize_t rsz;
1.6 florian 192: int c;
1.1 benno 193:
194: *sz = 0;
195:
1.4 deraadt 196: if (bsz == 0)
1.1 benno 197: return 1;
198:
199: pfd.fd = fd;
200: pfd.events = POLLIN;
201:
1.7 florian 202: /* Poll and check for all possible errors. */
203:
1.19 claudio 204: if ((c = poll(&pfd, 1, poll_timeout)) == -1) {
1.16 benno 205: ERR("poll");
1.1 benno 206: return 0;
1.6 florian 207: } else if (c == 0) {
1.16 benno 208: ERRX("poll: timeout");
1.6 florian 209: return 0;
1.7 florian 210: } else if ((pfd.revents & (POLLERR|POLLNVAL))) {
1.16 benno 211: ERRX("poll: bad fd");
1.1 benno 212: return 0;
1.3 deraadt 213: } else if (!(pfd.revents & (POLLIN|POLLHUP))) {
1.16 benno 214: ERRX("poll: unknown event");
1.1 benno 215: return 0;
216: }
217:
1.7 florian 218: /* Now the non-blocking read, checking for EOF. */
219:
1.18 deraadt 220: if ((rsz = read(fd, buf, bsz)) == -1) {
1.16 benno 221: ERR("read");
1.1 benno 222: return 0;
1.4 deraadt 223: } else if (rsz == 0) {
1.16 benno 224: ERRX("unexpected end of file");
1.1 benno 225: return 0;
226: }
227:
228: *sz = rsz;
229: return 1;
230: }
231:
232: /*
233: * Blocking read of the full size of the buffer.
234: * This can be called from either the error type message or a regular
235: * message---or for that matter, multiplexed or not.
236: * Returns 0 on failure, non-zero on success (all bytes read).
237: */
238: static int
1.17 benno 239: io_read_blocking(int fd, void *buf, size_t sz)
1.1 benno 240: {
241: size_t rsz;
242: int c;
243:
244: while (sz > 0) {
1.17 benno 245: c = io_read_nonblocking(fd, buf, sz, &rsz);
1.3 deraadt 246: if (!c) {
1.16 benno 247: ERRX1("io_read_nonblocking");
1.1 benno 248: return 0;
1.4 deraadt 249: } else if (rsz == 0) {
1.16 benno 250: ERRX("io_read_nonblocking: short read");
1.1 benno 251: return 0;
252: }
253: buf += rsz;
254: sz -= rsz;
255: }
256:
257: return 1;
258: }
259:
260: /*
261: * When we do a lot of writes in a row (such as when the sender emits
262: * the file list), the server might be sending us multiplexed log
263: * messages.
264: * If it sends too many, it clogs the socket.
265: * This function looks into the read buffer and clears out any log
266: * messages pending.
267: * If called when there are valid data reads available, this function
268: * does nothing.
269: * Returns zero on failure, non-zero on success.
270: */
271: int
272: io_read_flush(struct sess *sess, int fd)
273: {
274: int32_t tagbuf, tag;
275: char mpbuf[1024];
276:
277: if (sess->mplex_read_remain)
278: return 1;
279:
280: /*
281: * First, read the 4-byte multiplex tag.
282: * The first byte is the tag identifier (7 for normal
283: * data, !7 for out-of-band data), the last three are
284: * for the remaining data size.
285: */
286:
1.17 benno 287: if (!io_read_blocking(fd, &tagbuf, sizeof(tagbuf))) {
1.16 benno 288: ERRX1("io_read_blocking");
1.1 benno 289: return 0;
290: }
291: tag = le32toh(tagbuf);
292: sess->mplex_read_remain = tag & 0xFFFFFF;
293: tag >>= 24;
1.4 deraadt 294: if (tag == 7)
1.1 benno 295: return 1;
296:
297: tag -= 7;
298:
299: if (sess->mplex_read_remain > sizeof(mpbuf)) {
1.16 benno 300: ERRX("multiplex buffer overflow");
1.1 benno 301: return 0;
1.4 deraadt 302: } else if (sess->mplex_read_remain == 0)
1.1 benno 303: return 1;
304:
1.17 benno 305: if (!io_read_blocking(fd, mpbuf, sess->mplex_read_remain)) {
1.16 benno 306: ERRX1("io_read_blocking");
1.1 benno 307: return 0;
308: }
1.4 deraadt 309: if (mpbuf[sess->mplex_read_remain - 1] == '\n')
1.1 benno 310: mpbuf[--sess->mplex_read_remain] = '\0';
311:
312: /*
313: * Always print the server's messages, as the server
314: * will control its own log levelling.
315: */
316:
1.16 benno 317: LOG0("%.*s", (int)sess->mplex_read_remain, mpbuf);
1.1 benno 318: sess->mplex_read_remain = 0;
319:
1.2 benno 320: /*
1.1 benno 321: * I only know that a tag of one means an error.
322: * This means that we should exit.
323: */
324:
1.4 deraadt 325: if (tag == 1) {
1.16 benno 326: ERRX1("error from remote host");
1.1 benno 327: return 0;
328: }
329: return 1;
330: }
331:
332: /*
333: * Read buffer from non-blocking descriptor, possibly in multiplex read
334: * mode.
335: * Returns zero on failure, non-zero on success (all bytes read from
336: * the descriptor).
337: */
338: int
339: io_read_buf(struct sess *sess, int fd, void *buf, size_t sz)
340: {
341: size_t rsz;
342: int c;
343:
344: /* If we're not multiplexing, read directly. */
345:
1.3 deraadt 346: if (!sess->mplex_reads) {
1.4 deraadt 347: assert(sess->mplex_read_remain == 0);
1.17 benno 348: c = io_read_blocking(fd, buf, sz);
1.1 benno 349: sess->total_read += sz;
350: return c;
351: }
352:
353: while (sz > 0) {
354: /*
355: * First, check to see if we have any regular data
356: * hanging around waiting to be read.
357: * If so, read the lesser of that data and whatever
358: * amount we currently want.
359: */
360:
361: if (sess->mplex_read_remain) {
362: rsz = sess->mplex_read_remain < sz ?
363: sess->mplex_read_remain : sz;
1.17 benno 364: if (!io_read_blocking(fd, buf, rsz)) {
1.16 benno 365: ERRX1("io_read_blocking");
1.1 benno 366: return 0;
367: }
368: sz -= rsz;
369: sess->mplex_read_remain -= rsz;
370: buf += rsz;
371: sess->total_read += rsz;
372: continue;
373: }
374:
1.4 deraadt 375: assert(sess->mplex_read_remain == 0);
1.3 deraadt 376: if (!io_read_flush(sess, fd)) {
1.16 benno 377: ERRX1("io_read_flush");
1.1 benno 378: return 0;
379: }
380: }
381:
382: return 1;
383: }
384:
1.7 florian 385: /*
386: * Like io_write_buf(), but for a long (which is a composite type).
387: * Returns zero on failure, non-zero on success.
388: */
1.1 benno 389: int
1.15 deraadt 390: io_write_ulong(struct sess *sess, int fd, uint64_t val)
1.1 benno 391: {
1.15 deraadt 392: uint64_t nv;
393: int64_t sval = (int64_t)val;
1.1 benno 394:
395: /* Short-circuit: send as an integer if possible. */
396:
1.15 deraadt 397: if (sval <= INT32_MAX && sval >= 0) {
1.7 florian 398: if (!io_write_int(sess, fd, (int32_t)val)) {
1.16 benno 399: ERRX1("io_write_int");
1.7 florian 400: return 0;
401: }
402: return 1;
403: }
1.1 benno 404:
1.15 deraadt 405: /* Otherwise, pad with -1 32-bit, then send 64-bit. */
1.1 benno 406:
407: nv = htole64(val);
408:
1.14 deraadt 409: if (!io_write_int(sess, fd, -1))
1.16 benno 410: ERRX1("io_write_int");
1.3 deraadt 411: else if (!io_write_buf(sess, fd, &nv, sizeof(int64_t)))
1.16 benno 412: ERRX1("io_write_buf");
1.1 benno 413: else
414: return 1;
415:
416: return 0;
417: }
418:
1.15 deraadt 419: int
420: io_write_long(struct sess *sess, int fd, int64_t val)
421: {
422: return io_write_ulong(sess, fd, (uint64_t)val);
423: }
424:
1.7 florian 425: /*
1.15 deraadt 426: * Like io_write_buf(), but for an unsigned integer.
1.7 florian 427: * Returns zero on failure, non-zero on success.
428: */
1.1 benno 429: int
1.15 deraadt 430: io_write_uint(struct sess *sess, int fd, uint32_t val)
1.1 benno 431: {
1.15 deraadt 432: uint32_t nv;
1.1 benno 433:
434: nv = htole32(val);
435:
1.15 deraadt 436: if (!io_write_buf(sess, fd, &nv, sizeof(uint32_t))) {
1.16 benno 437: ERRX1("io_write_buf");
1.1 benno 438: return 0;
439: }
440: return 1;
441: }
442:
443: /*
1.15 deraadt 444: * Like io_write_buf(), but for an integer.
445: * Returns zero on failure, non-zero on success.
446: */
447: int
448: io_write_int(struct sess *sess, int fd, int32_t val)
449: {
450: return io_write_uint(sess, fd, (uint32_t)val);
451: }
452:
453: /*
1.1 benno 454: * A simple assertion-protected memory copy from th einput "val" or size
455: * "valsz" into our buffer "buf", full size "buflen", position "bufpos".
456: * Increases our "bufpos" appropriately.
457: * This has no return value, but will assert() if the size of the buffer
458: * is insufficient for the new data.
459: */
460: void
1.17 benno 461: io_buffer_buf(void *buf, size_t *bufpos, size_t buflen, const void *val,
462: size_t valsz)
1.1 benno 463: {
464:
465: assert(*bufpos + valsz <= buflen);
466: memcpy(buf + *bufpos, val, valsz);
467: *bufpos += valsz;
468: }
469:
470: /*
1.7 florian 471: * Like io_buffer_buf(), but also accomodating for multiplexing codes.
472: * This should NEVER be passed to io_write_buf(), but instead passed
473: * directly to a write operation.
474: */
475: void
476: io_lowbuffer_buf(struct sess *sess, void *buf,
477: size_t *bufpos, size_t buflen, const void *val, size_t valsz)
478: {
479: int32_t tagbuf;
480:
1.9 deraadt 481: if (valsz == 0)
1.7 florian 482: return;
483:
484: if (!sess->mplex_writes) {
1.17 benno 485: io_buffer_buf(buf, bufpos, buflen, val, valsz);
1.7 florian 486: return;
487: }
488:
489: assert(*bufpos + valsz + sizeof(int32_t) <= buflen);
490: assert(valsz == (valsz & 0xFFFFFF));
491: tagbuf = htole32((7 << 24) + valsz);
492:
1.17 benno 493: io_buffer_int(buf, bufpos, buflen, tagbuf);
494: io_buffer_buf(buf, bufpos, buflen, val, valsz);
1.7 florian 495: }
496:
497: /*
498: * Allocate the space needed for io_lowbuffer_buf() and friends.
499: * This should be called for *each* lowbuffer operation, so:
500: * io_lowbuffer_alloc(... sizeof(int32_t));
501: * io_lowbuffer_int(...);
502: * io_lowbuffer_alloc(... sizeof(int32_t));
503: * io_lowbuffer_int(...);
504: * And not sizeof(int32_t) * 2 or whatnot.
505: * Returns zero on failure, non-zero on succes.
506: */
507: int
508: io_lowbuffer_alloc(struct sess *sess, void **buf,
509: size_t *bufsz, size_t *bufmax, size_t sz)
510: {
511: void *pp;
512: size_t extra;
513:
514: extra = sess->mplex_writes ? sizeof(int32_t) : 0;
515:
516: if (*bufsz + sz + extra > *bufmax) {
517: pp = realloc(*buf, *bufsz + sz + extra);
518: if (pp == NULL) {
1.16 benno 519: ERR("realloc");
1.7 florian 520: return 0;
521: }
522: *buf = pp;
523: *bufmax = *bufsz + sz + extra;
524: }
525: *bufsz += sz + extra;
526: return 1;
527: }
528:
529: /*
530: * Like io_lowbuffer_buf(), but for a single integer.
531: */
532: void
533: io_lowbuffer_int(struct sess *sess, void *buf,
534: size_t *bufpos, size_t buflen, int32_t val)
535: {
536: int32_t nv = htole32(val);
537:
538: io_lowbuffer_buf(sess, buf, bufpos, buflen, &nv, sizeof(int32_t));
539: }
540:
541: /*
542: * Like io_buffer_buf(), but for a single integer.
1.1 benno 543: */
544: void
1.17 benno 545: io_buffer_int(void *buf, size_t *bufpos, size_t buflen, int32_t val)
1.1 benno 546: {
547: int32_t nv = htole32(val);
548:
1.17 benno 549: io_buffer_buf(buf, bufpos, buflen, &nv, sizeof(int32_t));
1.1 benno 550: }
551:
1.7 florian 552: /*
553: * Like io_read_buf(), but for a long >=0.
554: * Returns zero on failure, non-zero on success.
555: */
1.1 benno 556: int
1.15 deraadt 557: io_read_long(struct sess *sess, int fd, int64_t *val)
1.1 benno 558: {
1.15 deraadt 559: uint64_t uoval;
1.1 benno 560:
1.15 deraadt 561: if (!io_read_ulong(sess, fd, &uoval)) {
1.16 benno 562: ERRX1("io_read_long");
1.1 benno 563: return 0;
564: }
1.15 deraadt 565: *val = (int64_t)uoval;
566: if (*val < 0) {
1.16 benno 567: ERRX1("io_read_long negative");
1.15 deraadt 568: return 0;
569: }
1.1 benno 570: return 1;
571: }
572:
1.7 florian 573: /*
574: * Like io_read_buf(), but for a long.
575: * Returns zero on failure, non-zero on success.
576: */
1.1 benno 577: int
1.15 deraadt 578: io_read_ulong(struct sess *sess, int fd, uint64_t *val)
1.1 benno 579: {
1.15 deraadt 580: uint64_t oval;
581: int32_t sval;
1.1 benno 582:
583: /* Start with the short-circuit: read as an int. */
584:
1.3 deraadt 585: if (!io_read_int(sess, fd, &sval)) {
1.16 benno 586: ERRX1("io_read_int");
1.1 benno 587: return 0;
1.13 deraadt 588: } else if (sval != -1) {
1.15 deraadt 589: *val = (uint64_t)le32toh(sval);
1.1 benno 590: return 1;
591: }
592:
1.15 deraadt 593: /* If the int is -1, read as 64 bits. */
1.1 benno 594:
1.15 deraadt 595: if (!io_read_buf(sess, fd, &oval, sizeof(uint64_t))) {
1.16 benno 596: ERRX1("io_read_buf");
1.1 benno 597: return 0;
598: }
599:
600: *val = le64toh(oval);
601: return 1;
602: }
603:
604: /*
605: * One thing we often need to do is read a size_t.
606: * These are transmitted as int32_t, so make sure that the value
607: * transmitted is not out of range.
608: * FIXME: I assume that size_t can handle int32_t's max.
1.7 florian 609: * Returns zero on failure, non-zero on success.
1.1 benno 610: */
611: int
612: io_read_size(struct sess *sess, int fd, size_t *val)
613: {
614: int32_t oval;
615:
1.3 deraadt 616: if (!io_read_int(sess, fd, &oval)) {
1.16 benno 617: ERRX1("io_read_int");
1.1 benno 618: return 0;
619: } else if (oval < 0) {
1.16 benno 620: ERRX("io_read_size: negative value");
1.1 benno 621: return 0;
622: }
623:
624: *val = oval;
625: return 1;
626: }
627:
1.7 florian 628: /*
629: * Like io_read_buf(), but for an integer.
630: * Returns zero on failure, non-zero on success.
631: */
1.1 benno 632: int
1.15 deraadt 633: io_read_uint(struct sess *sess, int fd, uint32_t *val)
1.1 benno 634: {
1.15 deraadt 635: uint32_t oval;
1.1 benno 636:
1.15 deraadt 637: if (!io_read_buf(sess, fd, &oval, sizeof(uint32_t))) {
1.16 benno 638: ERRX1("io_read_buf");
1.1 benno 639: return 0;
640: }
641:
642: *val = le32toh(oval);
643: return 1;
1.15 deraadt 644: }
645:
646: int
647: io_read_int(struct sess *sess, int fd, int32_t *val)
648: {
649: return io_read_uint(sess, fd, (uint32_t *)val);
1.1 benno 650: }
651:
652: /*
653: * Copies "valsz" from "buf", full size "bufsz" at position" bufpos",
654: * into "val".
655: * Calls assert() if the source doesn't have enough data.
656: * Increases "bufpos" to the new position.
657: */
658: void
1.17 benno 659: io_unbuffer_buf(const void *buf, size_t *bufpos, size_t bufsz, void *val,
660: size_t valsz)
1.1 benno 661: {
662:
663: assert(*bufpos + valsz <= bufsz);
664: memcpy(val, buf + *bufpos, valsz);
665: *bufpos += valsz;
666: }
667:
668: /*
1.7 florian 669: * Calls io_unbuffer_buf() and converts.
1.1 benno 670: */
671: void
1.17 benno 672: io_unbuffer_int(const void *buf, size_t *bufpos, size_t bufsz, int32_t *val)
1.1 benno 673: {
674: int32_t oval;
675:
1.17 benno 676: io_unbuffer_buf(buf, bufpos, bufsz, &oval, sizeof(int32_t));
1.1 benno 677: *val = le32toh(oval);
678: }
679:
1.7 florian 680: /*
681: * Calls io_unbuffer_buf() and converts.
682: */
1.1 benno 683: int
1.17 benno 684: io_unbuffer_size(const void *buf, size_t *bufpos, size_t bufsz, size_t *val)
1.1 benno 685: {
686: int32_t oval;
687:
1.17 benno 688: io_unbuffer_int(buf, bufpos, bufsz, &oval);
1.1 benno 689: if (oval < 0) {
1.16 benno 690: ERRX("io_unbuffer_size: negative value");
1.1 benno 691: return 0;
692: }
693: *val = oval;
694: return 1;
695: }
696:
1.7 florian 697: /*
698: * Like io_read_buf(), but for a single byte >=0.
699: * Returns zero on failure, non-zero on success.
700: */
1.1 benno 701: int
702: io_read_byte(struct sess *sess, int fd, uint8_t *val)
703: {
704:
1.3 deraadt 705: if (!io_read_buf(sess, fd, val, sizeof(uint8_t))) {
1.16 benno 706: ERRX1("io_read_buf");
1.1 benno 707: return 0;
708: }
709: return 1;
710: }
711:
1.7 florian 712: /*
713: * Like io_write_buf(), but for a single byte.
714: * Returns zero on failure, non-zero on success.
715: */
1.1 benno 716: int
717: io_write_byte(struct sess *sess, int fd, uint8_t val)
718: {
719:
1.3 deraadt 720: if (!io_write_buf(sess, fd, &val, sizeof(uint8_t))) {
1.16 benno 721: ERRX1("io_write_buf");
1.1 benno 722: return 0;
723: }
724: return 1;
725: }