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