1 /* $OpenBSD: file.c,v 1.15 2023/04/17 17:58:35 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 && 156 (cf->closed || c == NULL || (~c->flags & CLIENT_DEAD))) 157 cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data); 158 file_free(cf); 159 } 160 161 /* Add an event to fire the done callback (used by the server). */ 162 void 163 file_fire_done(struct client_file *cf) 164 { 165 event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL); 166 } 167 168 /* Fire the read callback. */ 169 void 170 file_fire_read(struct client_file *cf) 171 { 172 if (cf->cb != NULL) 173 cf->cb(cf->c, cf->path, cf->error, 0, cf->buffer, cf->data); 174 } 175 176 /* Can this file be printed to? */ 177 int 178 file_can_print(struct client *c) 179 { 180 if (c == NULL || 181 (c->flags & CLIENT_ATTACHED) || 182 (c->flags & CLIENT_CONTROL)) 183 return (0); 184 return (1); 185 } 186 187 /* Print a message to a file. */ 188 void 189 file_print(struct client *c, const char *fmt, ...) 190 { 191 va_list ap; 192 193 va_start(ap, fmt); 194 file_vprint(c, fmt, ap); 195 va_end(ap); 196 } 197 198 /* Print a message to a file. */ 199 void 200 file_vprint(struct client *c, const char *fmt, va_list ap) 201 { 202 struct client_file find, *cf; 203 struct msg_write_open msg; 204 205 if (!file_can_print(c)) 206 return; 207 208 find.stream = 1; 209 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { 210 cf = file_create_with_client(c, 1, NULL, NULL); 211 cf->path = xstrdup("-"); 212 213 evbuffer_add_vprintf(cf->buffer, fmt, ap); 214 215 msg.stream = 1; 216 msg.fd = STDOUT_FILENO; 217 msg.flags = 0; 218 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg); 219 } else { 220 evbuffer_add_vprintf(cf->buffer, fmt, ap); 221 file_push(cf); 222 } 223 } 224 225 /* Print a buffer to a file. */ 226 void 227 file_print_buffer(struct client *c, void *data, size_t size) 228 { 229 struct client_file find, *cf; 230 struct msg_write_open msg; 231 232 if (!file_can_print(c)) 233 return; 234 235 find.stream = 1; 236 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { 237 cf = file_create_with_client(c, 1, NULL, NULL); 238 cf->path = xstrdup("-"); 239 240 evbuffer_add(cf->buffer, data, size); 241 242 msg.stream = 1; 243 msg.fd = STDOUT_FILENO; 244 msg.flags = 0; 245 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg); 246 } else { 247 evbuffer_add(cf->buffer, data, size); 248 file_push(cf); 249 } 250 } 251 252 /* Report an error to a file. */ 253 void 254 file_error(struct client *c, const char *fmt, ...) 255 { 256 struct client_file find, *cf; 257 struct msg_write_open msg; 258 va_list ap; 259 260 if (!file_can_print(c)) 261 return; 262 263 va_start(ap, fmt); 264 265 find.stream = 2; 266 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) { 267 cf = file_create_with_client(c, 2, NULL, NULL); 268 cf->path = xstrdup("-"); 269 270 evbuffer_add_vprintf(cf->buffer, fmt, ap); 271 272 msg.stream = 2; 273 msg.fd = STDERR_FILENO; 274 msg.flags = 0; 275 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg); 276 } else { 277 evbuffer_add_vprintf(cf->buffer, fmt, ap); 278 file_push(cf); 279 } 280 281 va_end(ap); 282 } 283 284 /* Write data to a file. */ 285 void 286 file_write(struct client *c, const char *path, int flags, const void *bdata, 287 size_t bsize, client_file_cb cb, void *cbdata) 288 { 289 struct client_file *cf; 290 struct msg_write_open *msg; 291 size_t msglen; 292 int fd = -1; 293 u_int stream = file_next_stream++; 294 FILE *f; 295 const char *mode; 296 297 if (strcmp(path, "-") == 0) { 298 cf = file_create_with_client(c, stream, cb, cbdata); 299 cf->path = xstrdup("-"); 300 301 fd = STDOUT_FILENO; 302 if (c == NULL || 303 (c->flags & CLIENT_ATTACHED) || 304 (c->flags & CLIENT_CONTROL)) { 305 cf->error = EBADF; 306 goto done; 307 } 308 goto skip; 309 } 310 311 cf = file_create_with_client(c, stream, cb, cbdata); 312 cf->path = file_get_path(c, path); 313 314 if (c == NULL || c->flags & CLIENT_ATTACHED) { 315 if (flags & O_APPEND) 316 mode = "ab"; 317 else 318 mode = "wb"; 319 f = fopen(cf->path, mode); 320 if (f == NULL) { 321 cf->error = errno; 322 goto done; 323 } 324 if (fwrite(bdata, 1, bsize, f) != bsize) { 325 fclose(f); 326 cf->error = EIO; 327 goto done; 328 } 329 fclose(f); 330 goto done; 331 } 332 333 skip: 334 evbuffer_add(cf->buffer, bdata, bsize); 335 336 msglen = strlen(cf->path) + 1 + sizeof *msg; 337 if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { 338 cf->error = E2BIG; 339 goto done; 340 } 341 msg = xmalloc(msglen); 342 msg->stream = cf->stream; 343 msg->fd = fd; 344 msg->flags = flags; 345 memcpy(msg + 1, cf->path, msglen - sizeof *msg); 346 if (proc_send(cf->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) { 347 free(msg); 348 cf->error = EINVAL; 349 goto done; 350 } 351 free(msg); 352 return; 353 354 done: 355 file_fire_done(cf); 356 } 357 358 /* Read a file. */ 359 struct client_file * 360 file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata) 361 { 362 struct client_file *cf; 363 struct msg_read_open *msg; 364 size_t msglen; 365 int fd = -1; 366 u_int stream = file_next_stream++; 367 FILE *f; 368 size_t size; 369 char buffer[BUFSIZ]; 370 371 if (strcmp(path, "-") == 0) { 372 cf = file_create_with_client(c, stream, cb, cbdata); 373 cf->path = xstrdup("-"); 374 375 fd = STDIN_FILENO; 376 if (c == NULL || 377 (c->flags & CLIENT_ATTACHED) || 378 (c->flags & CLIENT_CONTROL)) { 379 cf->error = EBADF; 380 goto done; 381 } 382 goto skip; 383 } 384 385 cf = file_create_with_client(c, stream, cb, cbdata); 386 cf->path = file_get_path(c, path); 387 388 if (c == NULL || c->flags & CLIENT_ATTACHED) { 389 f = fopen(cf->path, "rb"); 390 if (f == NULL) { 391 cf->error = errno; 392 goto done; 393 } 394 for (;;) { 395 size = fread(buffer, 1, sizeof buffer, f); 396 if (evbuffer_add(cf->buffer, buffer, size) != 0) { 397 cf->error = ENOMEM; 398 goto done; 399 } 400 if (size != sizeof buffer) 401 break; 402 } 403 if (ferror(f)) { 404 cf->error = EIO; 405 goto done; 406 } 407 fclose(f); 408 goto done; 409 } 410 411 skip: 412 msglen = strlen(cf->path) + 1 + sizeof *msg; 413 if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) { 414 cf->error = E2BIG; 415 goto done; 416 } 417 msg = xmalloc(msglen); 418 msg->stream = cf->stream; 419 msg->fd = fd; 420 memcpy(msg + 1, cf->path, msglen - sizeof *msg); 421 if (proc_send(cf->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) { 422 free(msg); 423 cf->error = EINVAL; 424 goto done; 425 } 426 free(msg); 427 return cf; 428 429 done: 430 file_fire_done(cf); 431 return NULL; 432 } 433 434 /* Cancel a file read. */ 435 void 436 file_cancel(struct client_file *cf) 437 { 438 struct msg_read_cancel msg; 439 440 log_debug("read cancel file %d", cf->stream); 441 442 if (cf->closed) 443 return; 444 cf->closed = 1; 445 446 msg.stream = cf->stream; 447 proc_send(cf->peer, MSG_READ_CANCEL, -1, &msg, sizeof msg); 448 } 449 450 /* Push event, fired if there is more writing to be done. */ 451 static void 452 file_push_cb(__unused int fd, __unused short events, void *arg) 453 { 454 struct client_file *cf = arg; 455 456 if (cf->c == NULL || ~cf->c->flags & CLIENT_DEAD) 457 file_push(cf); 458 file_free(cf); 459 } 460 461 /* Push uwritten data to the client for a file, if it will accept it. */ 462 void 463 file_push(struct client_file *cf) 464 { 465 struct msg_write_data *msg; 466 size_t msglen, sent, left; 467 struct msg_write_close close; 468 469 msg = xmalloc(sizeof *msg); 470 left = EVBUFFER_LENGTH(cf->buffer); 471 while (left != 0) { 472 sent = left; 473 if (sent > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg) 474 sent = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg; 475 476 msglen = (sizeof *msg) + sent; 477 msg = xrealloc(msg, msglen); 478 msg->stream = cf->stream; 479 memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent); 480 if (proc_send(cf->peer, MSG_WRITE, -1, msg, msglen) != 0) 481 break; 482 evbuffer_drain(cf->buffer, sent); 483 484 left = EVBUFFER_LENGTH(cf->buffer); 485 log_debug("file %d sent %zu, left %zu", cf->stream, sent, left); 486 } 487 if (left != 0) { 488 cf->references++; 489 event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL); 490 } else if (cf->stream > 2) { 491 close.stream = cf->stream; 492 proc_send(cf->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close); 493 file_fire_done(cf); 494 } 495 free(msg); 496 } 497 498 /* Check if any files have data left to write. */ 499 int 500 file_write_left(struct client_files *files) 501 { 502 struct client_file *cf; 503 size_t left; 504 int waiting = 0; 505 506 RB_FOREACH(cf, client_files, files) { 507 if (cf->event == NULL) 508 continue; 509 left = EVBUFFER_LENGTH(cf->event->output); 510 if (left != 0) { 511 waiting++; 512 log_debug("file %u %zu bytes left", cf->stream, left); 513 } 514 } 515 return (waiting != 0); 516 } 517 518 /* Client file write error callback. */ 519 static void 520 file_write_error_callback(__unused struct bufferevent *bev, __unused short what, 521 void *arg) 522 { 523 struct client_file *cf = arg; 524 525 log_debug("write error file %d", cf->stream); 526 527 bufferevent_free(cf->event); 528 cf->event = NULL; 529 530 close(cf->fd); 531 cf->fd = -1; 532 533 if (cf->cb != NULL) 534 cf->cb(NULL, NULL, 0, -1, NULL, cf->data); 535 } 536 537 /* Client file write callback. */ 538 static void 539 file_write_callback(__unused struct bufferevent *bev, void *arg) 540 { 541 struct client_file *cf = arg; 542 543 log_debug("write check file %d", cf->stream); 544 545 if (cf->cb != NULL) 546 cf->cb(NULL, NULL, 0, -1, NULL, cf->data); 547 548 if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) { 549 bufferevent_free(cf->event); 550 close(cf->fd); 551 RB_REMOVE(client_files, cf->tree, cf); 552 file_free(cf); 553 } 554 } 555 556 /* Handle a file write open message (client). */ 557 void 558 file_write_open(struct client_files *files, struct tmuxpeer *peer, 559 struct imsg *imsg, int allow_streams, int close_received, 560 client_file_cb cb, void *cbdata) 561 { 562 struct msg_write_open *msg = imsg->data; 563 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 564 const char *path; 565 struct msg_write_ready reply; 566 struct client_file find, *cf; 567 const int flags = O_NONBLOCK|O_WRONLY|O_CREAT; 568 int error = 0; 569 570 if (msglen < sizeof *msg) 571 fatalx("bad MSG_WRITE_OPEN size"); 572 if (msglen == sizeof *msg) 573 path = "-"; 574 else 575 path = (const char *)(msg + 1); 576 log_debug("open write file %d %s", msg->stream, path); 577 578 find.stream = msg->stream; 579 if (RB_FIND(client_files, files, &find) != NULL) { 580 error = EBADF; 581 goto reply; 582 } 583 cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata); 584 if (cf->closed) { 585 error = EBADF; 586 goto reply; 587 } 588 589 cf->fd = -1; 590 if (msg->fd == -1) 591 cf->fd = open(path, msg->flags|flags, 0644); 592 else if (allow_streams) { 593 if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO) 594 errno = EBADF; 595 else { 596 cf->fd = dup(msg->fd); 597 if (close_received) 598 close(msg->fd); /* can only be used once */ 599 } 600 } else 601 errno = EBADF; 602 if (cf->fd == -1) { 603 error = errno; 604 goto reply; 605 } 606 607 cf->event = bufferevent_new(cf->fd, NULL, file_write_callback, 608 file_write_error_callback, cf); 609 if (cf->event == NULL) 610 fatalx("out of memory"); 611 bufferevent_enable(cf->event, EV_WRITE); 612 goto reply; 613 614 reply: 615 reply.stream = msg->stream; 616 reply.error = error; 617 proc_send(peer, MSG_WRITE_READY, -1, &reply, sizeof reply); 618 } 619 620 /* Handle a file write data message (client). */ 621 void 622 file_write_data(struct client_files *files, struct imsg *imsg) 623 { 624 struct msg_write_data *msg = imsg->data; 625 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 626 struct client_file find, *cf; 627 size_t size = msglen - sizeof *msg; 628 629 if (msglen < sizeof *msg) 630 fatalx("bad MSG_WRITE size"); 631 find.stream = msg->stream; 632 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 633 fatalx("unknown stream number"); 634 log_debug("write %zu to file %d", size, cf->stream); 635 636 if (cf->event != NULL) 637 bufferevent_write(cf->event, msg + 1, size); 638 } 639 640 /* Handle a file write close message (client). */ 641 void 642 file_write_close(struct client_files *files, struct imsg *imsg) 643 { 644 struct msg_write_close *msg = imsg->data; 645 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 646 struct client_file find, *cf; 647 648 if (msglen != sizeof *msg) 649 fatalx("bad MSG_WRITE_CLOSE size"); 650 find.stream = msg->stream; 651 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 652 fatalx("unknown stream number"); 653 log_debug("close file %d", cf->stream); 654 655 if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) { 656 if (cf->event != NULL) 657 bufferevent_free(cf->event); 658 if (cf->fd != -1) 659 close(cf->fd); 660 RB_REMOVE(client_files, files, cf); 661 file_free(cf); 662 } 663 } 664 665 /* Client file read error callback. */ 666 static void 667 file_read_error_callback(__unused struct bufferevent *bev, __unused short what, 668 void *arg) 669 { 670 struct client_file *cf = arg; 671 struct msg_read_done msg; 672 673 log_debug("read error file %d", cf->stream); 674 675 msg.stream = cf->stream; 676 msg.error = 0; 677 proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg); 678 679 bufferevent_free(cf->event); 680 close(cf->fd); 681 RB_REMOVE(client_files, cf->tree, cf); 682 file_free(cf); 683 } 684 685 /* Client file read callback. */ 686 static void 687 file_read_callback(__unused struct bufferevent *bev, void *arg) 688 { 689 struct client_file *cf = arg; 690 void *bdata; 691 size_t bsize; 692 struct msg_read_data *msg; 693 size_t msglen; 694 695 msg = xmalloc(sizeof *msg); 696 for (;;) { 697 bdata = EVBUFFER_DATA(cf->event->input); 698 bsize = EVBUFFER_LENGTH(cf->event->input); 699 700 if (bsize == 0) 701 break; 702 if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg) 703 bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg; 704 log_debug("read %zu from file %d", bsize, cf->stream); 705 706 msglen = (sizeof *msg) + bsize; 707 msg = xrealloc(msg, msglen); 708 msg->stream = cf->stream; 709 memcpy(msg + 1, bdata, bsize); 710 proc_send(cf->peer, MSG_READ, -1, msg, msglen); 711 712 evbuffer_drain(cf->event->input, bsize); 713 } 714 free(msg); 715 } 716 717 /* Handle a file read open message (client). */ 718 void 719 file_read_open(struct client_files *files, struct tmuxpeer *peer, 720 struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb, 721 void *cbdata) 722 { 723 struct msg_read_open *msg = imsg->data; 724 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 725 const char *path; 726 struct msg_read_done reply; 727 struct client_file find, *cf; 728 const int flags = O_NONBLOCK|O_RDONLY; 729 int error; 730 731 if (msglen < sizeof *msg) 732 fatalx("bad MSG_READ_OPEN size"); 733 if (msglen == sizeof *msg) 734 path = "-"; 735 else 736 path = (const char *)(msg + 1); 737 log_debug("open read file %d %s", msg->stream, path); 738 739 find.stream = msg->stream; 740 if (RB_FIND(client_files, files, &find) != NULL) { 741 error = EBADF; 742 goto reply; 743 } 744 cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata); 745 if (cf->closed) { 746 error = EBADF; 747 goto reply; 748 } 749 750 cf->fd = -1; 751 if (msg->fd == -1) 752 cf->fd = open(path, flags); 753 else if (allow_streams) { 754 if (msg->fd != STDIN_FILENO) 755 errno = EBADF; 756 else { 757 cf->fd = dup(msg->fd); 758 if (close_received) 759 close(msg->fd); /* can only be used once */ 760 } 761 } else 762 errno = EBADF; 763 if (cf->fd == -1) { 764 error = errno; 765 goto reply; 766 } 767 768 cf->event = bufferevent_new(cf->fd, file_read_callback, NULL, 769 file_read_error_callback, cf); 770 if (cf->event == NULL) 771 fatalx("out of memory"); 772 bufferevent_enable(cf->event, EV_READ); 773 return; 774 775 reply: 776 reply.stream = msg->stream; 777 reply.error = error; 778 proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply); 779 } 780 781 /* Handle a read cancel message (client). */ 782 void 783 file_read_cancel(struct client_files *files, struct imsg *imsg) 784 { 785 struct msg_read_cancel *msg = imsg->data; 786 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 787 struct client_file find, *cf; 788 789 if (msglen != sizeof *msg) 790 fatalx("bad MSG_READ_CANCEL size"); 791 find.stream = msg->stream; 792 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 793 fatalx("unknown stream number"); 794 log_debug("cancel file %d", cf->stream); 795 796 file_read_error_callback(NULL, 0, cf); 797 } 798 799 /* Handle a write ready message (server). */ 800 void 801 file_write_ready(struct client_files *files, struct imsg *imsg) 802 { 803 struct msg_write_ready *msg = imsg->data; 804 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 805 struct client_file find, *cf; 806 807 if (msglen != sizeof *msg) 808 fatalx("bad MSG_WRITE_READY size"); 809 find.stream = msg->stream; 810 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 811 return; 812 if (msg->error != 0) { 813 cf->error = msg->error; 814 file_fire_done(cf); 815 } else 816 file_push(cf); 817 } 818 819 /* Handle read data message (server). */ 820 void 821 file_read_data(struct client_files *files, struct imsg *imsg) 822 { 823 struct msg_read_data *msg = imsg->data; 824 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 825 struct client_file find, *cf; 826 void *bdata = msg + 1; 827 size_t bsize = msglen - sizeof *msg; 828 829 if (msglen < sizeof *msg) 830 fatalx("bad MSG_READ_DATA size"); 831 find.stream = msg->stream; 832 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 833 return; 834 835 log_debug("file %d read %zu bytes", cf->stream, bsize); 836 if (cf->error == 0 && !cf->closed) { 837 if (evbuffer_add(cf->buffer, bdata, bsize) != 0) { 838 cf->error = ENOMEM; 839 file_fire_done(cf); 840 } else 841 file_fire_read(cf); 842 } 843 } 844 845 /* Handle a read done message (server). */ 846 void 847 file_read_done(struct client_files *files, struct imsg *imsg) 848 { 849 struct msg_read_done *msg = imsg->data; 850 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE; 851 struct client_file find, *cf; 852 853 if (msglen != sizeof *msg) 854 fatalx("bad MSG_READ_DONE size"); 855 find.stream = msg->stream; 856 if ((cf = RB_FIND(client_files, files, &find)) == NULL) 857 return; 858 859 log_debug("file %d read done", cf->stream); 860 cf->error = msg->error; 861 file_fire_done(cf); 862 } 863