1 /* $OpenBSD: file.c,v 1.8 2021/02/11 08:28:45 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/uio.h> 22 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <imsg.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 #include "tmux.h" 32 33 /* 34 * IPC file handling. Both client and server use the same data structures 35 * (client_file and client_files) to store list of active files. Most functions 36 * are for use either in client or server but not both. 37 */ 38 39 static int file_next_stream = 3; 40 41 RB_GENERATE(client_files, client_file, entry, file_cmp); 42 43 /* Get path for file, either as given or from working directory. */ 44 static char * 45 file_get_path(struct client *c, const char *file) 46 { 47 char *path; 48 49 if (*file == '/') 50 path = xstrdup(file); 51 else 52 xasprintf(&path, "%s/%s", server_client_get_cwd(c, NULL), file); 53 return (path); 54 } 55 56 /* Tree comparison function. */ 57 int 58 file_cmp(struct client_file *cf1, struct client_file *cf2) 59 { 60 if (cf1->stream < cf2->stream) 61 return (-1); 62 if (cf1->stream > cf2->stream) 63 return (1); 64 return (0); 65 } 66 67 /* 68 * Create a file object in the client process - the peer is the server to send 69 * messages to. Check callback is fired when the file is finished with so the 70 * process can decide if it needs to exit (if it is waiting for files to 71 * flush). 72 */ 73 struct client_file * 74 file_create_with_peer(struct tmuxpeer *peer, struct client_files *files, 75 int stream, client_file_cb cb, void *cbdata) 76 { 77 struct client_file *cf; 78 79 cf = xcalloc(1, sizeof *cf); 80 cf->c = NULL; 81 cf->references = 1; 82 cf->stream = stream; 83 84 cf->buffer = evbuffer_new(); 85 if (cf->buffer == NULL) 86 fatalx("out of memory"); 87 88 cf->cb = cb; 89 cf->data = cbdata; 90 91 cf->peer = peer; 92 cf->tree = files; 93 RB_INSERT(client_files, files, cf); 94 95 return (cf); 96 } 97 98 /* Create a file object in the server, communicating with the given client. */ 99 struct client_file * 100 file_create_with_client(struct client *c, int stream, client_file_cb cb, 101 void *cbdata) 102 { 103 struct client_file *cf; 104 105 if (c != NULL && (c->flags & CLIENT_ATTACHED)) 106 c = NULL; 107 108 cf = xcalloc(1, sizeof *cf); 109 cf->c = c; 110 cf->references = 1; 111 cf->stream = stream; 112 113 cf->buffer = evbuffer_new(); 114 if (cf->buffer == NULL) 115 fatalx("out of memory"); 116 117 cf->cb = cb; 118 cf->data = cbdata; 119 120 if (cf->c != NULL) { 121 cf->peer = cf->c->peer; 122 cf->tree = &cf->c->files; 123 RB_INSERT(client_files, &cf->c->files, cf); 124 cf->c->references++; 125 } 126 127 return (cf); 128 } 129 130 /* Free a file. */ 131 void 132 file_free(struct client_file *cf) 133 { 134 if (--cf->references != 0) 135 return; 136 137 evbuffer_free(cf->buffer); 138 free(cf->path); 139 140 if (cf->tree != NULL) 141 RB_REMOVE(client_files, cf->tree, cf); 142 if (cf->c != NULL) 143 server_client_unref(cf->c); 144 145 free(cf); 146 } 147 148 /* Event to fire the done callback. */ 149 static void 150 file_fire_done_cb(__unused int fd, __unused short events, void *arg) 151 { 152 struct client_file *cf = arg; 153 struct client *c = cf->c; 154 155 if (cf->cb != NULL && (c == NULL || (~c->flags & CLIENT_DEAD))) 156 cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data); 157 file_free(cf); 158 } 159 160 /* Add an event to fire the done callback (used by the server). */ 161 void 162 file_fire_done(struct client_file *cf) 163 { 164 event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL); 165 } 166 167 /* Fire the read callback. */ 168 void 169 file_fire_read(struct client_file *cf) 170 { 171 if (cf->cb != NULL) 172 cf->cb(cf->c, cf->path, cf->error, 0, cf->buffer, cf->data); 173 } 174 175 /* Can this file be printed to? */ 176 int 177 file_can_print(struct client *c) 178 { 179 if (c == NULL) 180 return (0); 181 if (c->session != NULL && (~c->flags & CLIENT_CONTROL)) 182 return (0); 183 return (1); 184 } 185 186 /* Print a message to a file. */ 187 void 188 file_print(struct client *c, const char *fmt, ...) 189 { 190 va_list ap; 191 192 va_start(ap, fmt); 193 file_vprint(c, fmt, ap); 194 va_end(ap); 195 } 196 197 /* Print a message to a file. */ 198 void 199 file_vprint(struct client *c, const char *fmt, va_list ap) 200 { 201 struct client_file find, *cf; 202 struct msg_write_open msg; 203 204 if (!file_can_print(c)) 205 return; 206 207 find.stream = 1; 208 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { 209 cf = file_create_with_client(c, 1, NULL, NULL); 210 cf->path = xstrdup("-"); 211 212 evbuffer_add_vprintf(cf->buffer, fmt, ap); 213 214 msg.stream = 1; 215 msg.fd = STDOUT_FILENO; 216 msg.flags = 0; 217 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg); 218 } else { 219 evbuffer_add_vprintf(cf->buffer, fmt, ap); 220 file_push(cf); 221 } 222 } 223 224 /* Print a buffer to a file. */ 225 void 226 file_print_buffer(struct client *c, void *data, size_t size) 227 { 228 struct client_file find, *cf; 229 struct msg_write_open msg; 230 231 if (!file_can_print(c)) 232 return; 233 234 find.stream = 1; 235 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { 236 cf = file_create_with_client(c, 1, NULL, NULL); 237 cf->path = xstrdup("-"); 238 239 evbuffer_add(cf->buffer, data, size); 240 241 msg.stream = 1; 242 msg.fd = STDOUT_FILENO; 243 msg.flags = 0; 244 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg); 245 } else { 246 evbuffer_add(cf->buffer, data, size); 247 file_push(cf); 248 } 249 } 250 251 /* Report an error to a file. */ 252 void 253 file_error(struct client *c, const char *fmt, ...) 254 { 255 struct client_file find, *cf; 256 struct msg_write_open msg; 257 va_list ap; 258 259 if (!file_can_print(c)) 260 return; 261 262 va_start(ap, fmt); 263 264 find.stream = 2; 265 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { 266 cf = file_create_with_client(c, 2, NULL, NULL); 267 cf->path = xstrdup("-"); 268 269 evbuffer_add_vprintf(cf->buffer, fmt, ap); 270 271 msg.stream = 2; 272 msg.fd = STDERR_FILENO; 273 msg.flags = 0; 274 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg); 275 } else { 276 evbuffer_add_vprintf(cf->buffer, fmt, ap); 277 file_push(cf); 278 } 279 280 va_end(ap); 281 } 282 283 /* Write data to a file. */ 284 void 285 file_write(struct client *c, const char *path, int flags, const void *bdata, 286 size_t bsize, client_file_cb cb, void *cbdata) 287 { 288 struct client_file *cf; 289 struct msg_write_open *msg; 290 size_t msglen; 291 int fd = -1; 292 u_int stream = file_next_stream++; 293 FILE *f; 294 const char *mode; 295 296 if (strcmp(path, "-") == 0) { 297 cf = file_create_with_client(c, stream, cb, cbdata); 298 cf->path = xstrdup("-"); 299 300 fd = STDOUT_FILENO; 301 if (c == NULL || 302 (c->flags & CLIENT_ATTACHED) || 303 (c->flags & CLIENT_CONTROL)) { 304 cf->error = EBADF; 305 goto done; 306 } 307 goto skip; 308 } 309 310 cf = file_create_with_client(c, stream, cb, cbdata); 311 cf->path = file_get_path(c, path); 312 313 if (c == NULL || c->flags & CLIENT_ATTACHED) { 314 if (flags & O_APPEND) 315 mode = "ab"; 316 else 317 mode = "wb"; 318 f = fopen(cf->path, mode); 319 if (f == NULL) { 320 cf->error = errno; 321 goto done; 322 } 323 if (fwrite(bdata, 1, bsize, f) != bsize) { 324 fclose(f); 325 cf->error = EIO; 326 goto done; 327 } 328 fclose(f); 329 goto done; 330 } 331 332 skip: 333 evbuffer_add(cf->buffer, bdata, bsize); 334 335 msglen = strlen(cf->path) + 1 + sizeof *msg; 336 if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { 337 cf->error = E2BIG; 338 goto done; 339 } 340 msg = xmalloc(msglen); 341 msg->stream = cf->stream; 342 msg->fd = fd; 343 msg->flags = flags; 344 memcpy(msg + 1, cf->path, msglen - sizeof *msg); 345 if (proc_send(cf->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) { 346 free(msg); 347 cf->error = EINVAL; 348 goto done; 349 } 350 free(msg); 351 return; 352 353 done: 354 file_fire_done(cf); 355 } 356 357 /* Read a file. */ 358 void 359 file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata) 360 { 361 struct client_file *cf; 362 struct msg_read_open *msg; 363 size_t msglen; 364 int fd = -1; 365 u_int stream = file_next_stream++; 366 FILE *f; 367 size_t size; 368 char buffer[BUFSIZ]; 369 370 if (strcmp(path, "-") == 0) { 371 cf = file_create_with_client(c, stream, cb, cbdata); 372 cf->path = xstrdup("-"); 373 374 fd = STDIN_FILENO; 375 if (c == NULL || 376 (c->flags & CLIENT_ATTACHED) || 377 (c->flags & CLIENT_CONTROL)) { 378 cf->error = EBADF; 379 goto done; 380 } 381 goto skip; 382 } 383 384 cf = file_create_with_client(c, stream, cb, cbdata); 385 cf->path = file_get_path(c, path); 386 387 if (c == NULL || c->flags & CLIENT_ATTACHED) { 388 f = fopen(cf->path, "rb"); 389 if (f == NULL) { 390 cf->error = errno; 391 goto done; 392 } 393 for (;;) { 394 size = fread(buffer, 1, sizeof buffer, f); 395 if (evbuffer_add(cf->buffer, buffer, size) != 0) { 396 cf->error = ENOMEM; 397 goto done; 398 } 399 if (size != sizeof buffer) 400 break; 401 } 402 if (ferror(f)) { 403 cf->error = EIO; 404 goto done; 405 } 406 fclose(f); 407 goto done; 408 } 409 410 skip: 411 msglen = strlen(cf->path) + 1 + sizeof *msg; 412 if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { 413 cf->error = E2BIG; 414 goto done; 415 } 416 msg = xmalloc(msglen); 417 msg->stream = cf->stream; 418 msg->fd = fd; 419 memcpy(msg + 1, cf->path, msglen - sizeof *msg); 420 if (proc_send(cf->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) { 421 free(msg); 422 cf->error = EINVAL; 423 goto done; 424 } 425 free(msg); 426 return; 427 428 done: 429 file_fire_done(cf); 430 } 431 432 /* Push event, fired if there is more writing to be done. */ 433 static void 434 file_push_cb(__unused int fd, __unused short events, void *arg) 435 { 436 struct client_file *cf = arg; 437 438 if (cf->c == NULL || ~cf->c->flags & CLIENT_DEAD) 439 file_push(cf); 440 file_free(cf); 441 } 442 443 /* Push uwritten data to the client for a file, if it will accept it. */ 444 void 445 file_push(struct client_file *cf) 446 { 447 struct msg_write_data *msg; 448 size_t msglen, sent, left; 449 struct msg_write_close close; 450 451 msg = xmalloc(sizeof *msg); 452 left = EVBUFFER_LENGTH(cf->buffer); 453 while (left != 0) { 454 sent = left; 455 if (sent > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg) 456 sent = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg; 457 458 msglen = (sizeof *msg) + sent; 459 msg = xrealloc(msg, msglen); 460 msg->stream = cf->stream; 461 memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent); 462 if (proc_send(cf->peer, MSG_WRITE, -1, msg, msglen) != 0) 463 break; 464 evbuffer_drain(cf->buffer, sent); 465 466 left = EVBUFFER_LENGTH(cf->buffer); 467 log_debug("file %d sent %zu, left %zu", cf->stream, sent, left); 468 } 469 if (left != 0) { 470 cf->references++; 471 event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL); 472 } else if (cf->stream > 2) { 473 close.stream = cf->stream; 474 proc_send(cf->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close); 475 file_fire_done(cf); 476 } 477 free(msg); 478 } 479 480 /* Client file write error callback. */ 481 static void 482 file_write_error_callback(__unused struct bufferevent *bev, __unused short what, 483 void *arg) 484 { 485 struct client_file *cf = arg; 486 487 log_debug("write error file %d", cf->stream); 488 489 if (cf->cb != NULL) 490 cf->cb(NULL, NULL, 0, -1, NULL, cf->data); 491 492 bufferevent_free(cf->event); 493 cf->event = NULL; 494 495 close(cf->fd); 496 cf->fd = -1; 497 } 498 499 /* Client file write callback. */ 500 static void 501 file_write_callback(__unused struct bufferevent *bev, void *arg) 502 { 503 struct client_file *cf = arg; 504 505 log_debug("write check file %d", cf->stream); 506 507 if (cf->cb != NULL) 508 cf->cb(NULL, NULL, 0, -1, NULL, cf->data); 509 510 if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) { 511 bufferevent_free(cf->event); 512 close(cf->fd); 513 RB_REMOVE(client_files, cf->tree, cf); 514 file_free(cf); 515 } 516 } 517 518 /* Handle a file write open message (client). */ 519 void 520 file_write_open(struct client_files *files, struct tmuxpeer *peer, 521 struct imsg *imsg, int allow_streams, int close_received, 522 client_file_cb cb, void *cbdata) 523 { 524 struct msg_write_open *msg = imsg->data; 525 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 526 const char *path; 527 struct msg_write_ready reply; 528 struct client_file find, *cf; 529 const int flags = O_NONBLOCK|O_WRONLY|O_CREAT; 530 int error = 0; 531 532 if (msglen < sizeof *msg) 533 fatalx("bad MSG_WRITE_OPEN size"); 534 if (msglen == sizeof *msg) 535 path = "-"; 536 else 537 path = (const char *)(msg + 1); 538 log_debug("open write file %d %s", msg->stream, path); 539 540 find.stream = msg->stream; 541 if ((cf = RB_FIND(client_files, files, &find)) != NULL) { 542 error = EBADF; 543 goto reply; 544 } 545 cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata); 546 if (cf->closed) { 547 error = EBADF; 548 goto reply; 549 } 550 551 cf->fd = -1; 552 if (msg->fd == -1) 553 cf->fd = open(path, msg->flags|flags, 0644); 554 else if (allow_streams) { 555 if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO) 556 errno = EBADF; 557 else { 558 cf->fd = dup(msg->fd); 559 if (close_received) 560 close(msg->fd); /* can only be used once */ 561 } 562 } else 563 errno = EBADF; 564 if (cf->fd == -1) { 565 error = errno; 566 goto reply; 567 } 568 569 cf->event = bufferevent_new(cf->fd, NULL, file_write_callback, 570 file_write_error_callback, cf); 571 bufferevent_enable(cf->event, EV_WRITE); 572 goto reply; 573 574 reply: 575 reply.stream = msg->stream; 576 reply.error = error; 577 proc_send(peer, MSG_WRITE_READY, -1, &reply, sizeof reply); 578 } 579 580 /* Handle a file write data message (client). */ 581 void 582 file_write_data(struct client_files *files, struct imsg *imsg) 583 { 584 struct msg_write_data *msg = imsg->data; 585 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 586 struct client_file find, *cf; 587 size_t size = msglen - sizeof *msg; 588 589 if (msglen < sizeof *msg) 590 fatalx("bad MSG_WRITE size"); 591 find.stream = msg->stream; 592 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 593 fatalx("unknown stream number"); 594 log_debug("write %zu to file %d", size, cf->stream); 595 596 if (cf->event != NULL) 597 bufferevent_write(cf->event, msg + 1, size); 598 } 599 600 /* Handle a file write close message (client). */ 601 void 602 file_write_close(struct client_files *files, struct imsg *imsg) 603 { 604 struct msg_write_close *msg = imsg->data; 605 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 606 struct client_file find, *cf; 607 608 if (msglen != sizeof *msg) 609 fatalx("bad MSG_WRITE_CLOSE size"); 610 find.stream = msg->stream; 611 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 612 fatalx("unknown stream number"); 613 log_debug("close file %d", cf->stream); 614 615 if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) { 616 if (cf->event != NULL) 617 bufferevent_free(cf->event); 618 if (cf->fd != -1) 619 close(cf->fd); 620 RB_REMOVE(client_files, files, cf); 621 file_free(cf); 622 } 623 } 624 625 /* Client file read error callback. */ 626 static void 627 file_read_error_callback(__unused struct bufferevent *bev, __unused short what, 628 void *arg) 629 { 630 struct client_file *cf = arg; 631 struct msg_read_done msg; 632 633 log_debug("read error file %d", cf->stream); 634 635 msg.stream = cf->stream; 636 msg.error = 0; 637 proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg); 638 639 bufferevent_free(cf->event); 640 close(cf->fd); 641 RB_REMOVE(client_files, cf->tree, cf); 642 file_free(cf); 643 } 644 645 /* Client file read callback. */ 646 static void 647 file_read_callback(__unused struct bufferevent *bev, void *arg) 648 { 649 struct client_file *cf = arg; 650 void *bdata; 651 size_t bsize; 652 struct msg_read_data *msg; 653 size_t msglen; 654 655 msg = xmalloc(sizeof *msg); 656 for (;;) { 657 bdata = EVBUFFER_DATA(cf->event->input); 658 bsize = EVBUFFER_LENGTH(cf->event->input); 659 660 if (bsize == 0) 661 break; 662 if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg) 663 bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg; 664 log_debug("read %zu from file %d", bsize, cf->stream); 665 666 msglen = (sizeof *msg) + bsize; 667 msg = xrealloc(msg, msglen); 668 msg->stream = cf->stream; 669 memcpy(msg + 1, bdata, bsize); 670 proc_send(cf->peer, MSG_READ, -1, msg, msglen); 671 672 evbuffer_drain(cf->event->input, bsize); 673 } 674 free(msg); 675 } 676 677 /* Handle a file read open message (client). */ 678 void 679 file_read_open(struct client_files *files, struct tmuxpeer *peer, 680 struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb, 681 void *cbdata) 682 { 683 struct msg_read_open *msg = imsg->data; 684 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 685 const char *path; 686 struct msg_read_done reply; 687 struct client_file find, *cf; 688 const int flags = O_NONBLOCK|O_RDONLY; 689 int error; 690 691 if (msglen < sizeof *msg) 692 fatalx("bad MSG_READ_OPEN size"); 693 if (msglen == sizeof *msg) 694 path = "-"; 695 else 696 path = (const char *)(msg + 1); 697 log_debug("open read file %d %s", msg->stream, path); 698 699 find.stream = msg->stream; 700 if ((cf = RB_FIND(client_files, files, &find)) != NULL) { 701 error = EBADF; 702 goto reply; 703 } 704 cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata); 705 if (cf->closed) { 706 error = EBADF; 707 goto reply; 708 } 709 710 cf->fd = -1; 711 if (msg->fd == -1) 712 cf->fd = open(path, flags); 713 else if (allow_streams) { 714 if (msg->fd != STDIN_FILENO) 715 errno = EBADF; 716 else { 717 cf->fd = dup(msg->fd); 718 if (close_received) 719 close(msg->fd); /* can only be used once */ 720 } 721 } else 722 errno = EBADF; 723 if (cf->fd == -1) { 724 error = errno; 725 goto reply; 726 } 727 728 cf->event = bufferevent_new(cf->fd, file_read_callback, NULL, 729 file_read_error_callback, cf); 730 bufferevent_enable(cf->event, EV_READ); 731 return; 732 733 reply: 734 reply.stream = msg->stream; 735 reply.error = error; 736 proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply); 737 } 738 739 /* Handle a write ready message (server). */ 740 void 741 file_write_ready(struct client_files *files, struct imsg *imsg) 742 { 743 struct msg_write_ready *msg = imsg->data; 744 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 745 struct client_file find, *cf; 746 747 if (msglen != sizeof *msg) 748 fatalx("bad MSG_WRITE_READY size"); 749 find.stream = msg->stream; 750 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 751 return; 752 if (msg->error != 0) { 753 cf->error = msg->error; 754 file_fire_done(cf); 755 } else 756 file_push(cf); 757 } 758 759 /* Handle read data message (server). */ 760 void 761 file_read_data(struct client_files *files, struct imsg *imsg) 762 { 763 struct msg_read_data *msg = imsg->data; 764 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 765 struct client_file find, *cf; 766 void *bdata = msg + 1; 767 size_t bsize = msglen - sizeof *msg; 768 769 if (msglen < sizeof *msg) 770 fatalx("bad MSG_READ_DATA size"); 771 find.stream = msg->stream; 772 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 773 return; 774 775 log_debug("file %d read %zu bytes", cf->stream, bsize); 776 if (cf->error == 0) { 777 if (evbuffer_add(cf->buffer, bdata, bsize) != 0) { 778 cf->error = ENOMEM; 779 file_fire_done(cf); 780 } else 781 file_fire_read(cf); 782 } 783 } 784 785 /* Handle a read done message (server). */ 786 void 787 file_read_done(struct client_files *files, struct imsg *imsg) 788 { 789 struct msg_read_done *msg = imsg->data; 790 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 791 struct client_file find, *cf; 792 793 if (msglen != sizeof *msg) 794 fatalx("bad MSG_READ_DONE size"); 795 find.stream = msg->stream; 796 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 797 return; 798 799 log_debug("file %d read done", cf->stream); 800 cf->error = msg->error; 801 file_fire_done(cf); 802 } 803