Merge branch 'obsd-master'
[tmux.git] / file.c
blob9bea51791fdeebf843e25ef27843f8b7f600f3e6
1 /* $OpenBSD$ */
3 /*
4 * Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
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.
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.
19 #include <sys/types.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
28 #include "tmux.h"
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.
36 static int file_next_stream = 3;
38 RB_GENERATE(client_files, client_file, entry, file_cmp);
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)
44 char *path;
46 if (*file == '/')
47 path = xstrdup(file);
48 else
49 xasprintf(&path, "%s/%s", server_client_get_cwd(c, NULL), file);
50 return (path);
53 /* Tree comparison function. */
54 int
55 file_cmp(struct client_file *cf1, struct client_file *cf2)
57 if (cf1->stream < cf2->stream)
58 return (-1);
59 if (cf1->stream > cf2->stream)
60 return (1);
61 return (0);
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).
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)
74 struct client_file *cf;
76 cf = xcalloc(1, sizeof *cf);
77 cf->c = NULL;
78 cf->references = 1;
79 cf->stream = stream;
81 cf->buffer = evbuffer_new();
82 if (cf->buffer == NULL)
83 fatalx("out of memory");
85 cf->cb = cb;
86 cf->data = cbdata;
88 cf->peer = peer;
89 cf->tree = files;
90 RB_INSERT(client_files, files, cf);
92 return (cf);
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)
100 struct client_file *cf;
102 if (c != NULL && (c->flags & CLIENT_ATTACHED))
103 c = NULL;
105 cf = xcalloc(1, sizeof *cf);
106 cf->c = c;
107 cf->references = 1;
108 cf->stream = stream;
110 cf->buffer = evbuffer_new();
111 if (cf->buffer == NULL)
112 fatalx("out of memory");
114 cf->cb = cb;
115 cf->data = cbdata;
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++;
124 return (cf);
127 /* Free a file. */
128 void
129 file_free(struct client_file *cf)
131 if (--cf->references != 0)
132 return;
134 evbuffer_free(cf->buffer);
135 free(cf->path);
137 if (cf->tree != NULL)
138 RB_REMOVE(client_files, cf->tree, cf);
139 if (cf->c != NULL)
140 server_client_unref(cf->c);
142 free(cf);
145 /* Event to fire the done callback. */
146 static void
147 file_fire_done_cb(__unused int fd, __unused short events, void *arg)
149 struct client_file *cf = arg;
150 struct client *c = cf->c;
152 if (cf->cb != NULL &&
153 (cf->closed || c == NULL || (~c->flags & CLIENT_DEAD)))
154 cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data);
155 file_free(cf);
158 /* Add an event to fire the done callback (used by the server). */
159 void
160 file_fire_done(struct client_file *cf)
162 event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL);
165 /* Fire the read callback. */
166 void
167 file_fire_read(struct client_file *cf)
169 if (cf->cb != NULL)
170 cf->cb(cf->c, cf->path, cf->error, 0, cf->buffer, cf->data);
173 /* Can this file be printed to? */
175 file_can_print(struct client *c)
177 if (c == NULL ||
178 (c->flags & CLIENT_ATTACHED) ||
179 (c->flags & CLIENT_CONTROL))
180 return (0);
181 return (1);
184 /* Print a message to a file. */
185 void
186 file_print(struct client *c, const char *fmt, ...)
188 va_list ap;
190 va_start(ap, fmt);
191 file_vprint(c, fmt, ap);
192 va_end(ap);
195 /* Print a message to a file. */
196 void
197 file_vprint(struct client *c, const char *fmt, va_list ap)
199 struct client_file find, *cf;
200 struct msg_write_open msg;
202 if (!file_can_print(c))
203 return;
205 find.stream = 1;
206 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
207 cf = file_create_with_client(c, 1, NULL, NULL);
208 cf->path = xstrdup("-");
210 evbuffer_add_vprintf(cf->buffer, fmt, ap);
212 msg.stream = 1;
213 msg.fd = STDOUT_FILENO;
214 msg.flags = 0;
215 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
216 } else {
217 evbuffer_add_vprintf(cf->buffer, fmt, ap);
218 file_push(cf);
222 /* Print a buffer to a file. */
223 void
224 file_print_buffer(struct client *c, void *data, size_t size)
226 struct client_file find, *cf;
227 struct msg_write_open msg;
229 if (!file_can_print(c))
230 return;
232 find.stream = 1;
233 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
234 cf = file_create_with_client(c, 1, NULL, NULL);
235 cf->path = xstrdup("-");
237 evbuffer_add(cf->buffer, data, size);
239 msg.stream = 1;
240 msg.fd = STDOUT_FILENO;
241 msg.flags = 0;
242 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
243 } else {
244 evbuffer_add(cf->buffer, data, size);
245 file_push(cf);
249 /* Report an error to a file. */
250 void
251 file_error(struct client *c, const char *fmt, ...)
253 struct client_file find, *cf;
254 struct msg_write_open msg;
255 va_list ap;
257 if (!file_can_print(c))
258 return;
260 va_start(ap, fmt);
262 find.stream = 2;
263 if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
264 cf = file_create_with_client(c, 2, NULL, NULL);
265 cf->path = xstrdup("-");
267 evbuffer_add_vprintf(cf->buffer, fmt, ap);
269 msg.stream = 2;
270 msg.fd = STDERR_FILENO;
271 msg.flags = 0;
272 proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
273 } else {
274 evbuffer_add_vprintf(cf->buffer, fmt, ap);
275 file_push(cf);
278 va_end(ap);
281 /* Write data to a file. */
282 void
283 file_write(struct client *c, const char *path, int flags, const void *bdata,
284 size_t bsize, client_file_cb cb, void *cbdata)
286 struct client_file *cf;
287 struct msg_write_open *msg;
288 size_t msglen;
289 int fd = -1;
290 u_int stream = file_next_stream++;
291 FILE *f;
292 const char *mode;
294 if (strcmp(path, "-") == 0) {
295 cf = file_create_with_client(c, stream, cb, cbdata);
296 cf->path = xstrdup("-");
298 fd = STDOUT_FILENO;
299 if (c == NULL ||
300 (c->flags & CLIENT_ATTACHED) ||
301 (c->flags & CLIENT_CONTROL)) {
302 cf->error = EBADF;
303 goto done;
305 goto skip;
308 cf = file_create_with_client(c, stream, cb, cbdata);
309 cf->path = file_get_path(c, path);
311 if (c == NULL || c->flags & CLIENT_ATTACHED) {
312 if (flags & O_APPEND)
313 mode = "ab";
314 else
315 mode = "wb";
316 f = fopen(cf->path, mode);
317 if (f == NULL) {
318 cf->error = errno;
319 goto done;
321 if (fwrite(bdata, 1, bsize, f) != bsize) {
322 fclose(f);
323 cf->error = EIO;
324 goto done;
326 fclose(f);
327 goto done;
330 skip:
331 evbuffer_add(cf->buffer, bdata, bsize);
333 msglen = strlen(cf->path) + 1 + sizeof *msg;
334 if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
335 cf->error = E2BIG;
336 goto done;
338 msg = xmalloc(msglen);
339 msg->stream = cf->stream;
340 msg->fd = fd;
341 msg->flags = flags;
342 memcpy(msg + 1, cf->path, msglen - sizeof *msg);
343 if (proc_send(cf->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) {
344 free(msg);
345 cf->error = EINVAL;
346 goto done;
348 free(msg);
349 return;
351 done:
352 file_fire_done(cf);
355 /* Read a file. */
356 struct client_file *
357 file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
359 struct client_file *cf;
360 struct msg_read_open *msg;
361 size_t msglen;
362 int fd = -1;
363 u_int stream = file_next_stream++;
364 FILE *f;
365 size_t size;
366 char buffer[BUFSIZ];
368 if (strcmp(path, "-") == 0) {
369 cf = file_create_with_client(c, stream, cb, cbdata);
370 cf->path = xstrdup("-");
372 fd = STDIN_FILENO;
373 if (c == NULL ||
374 (c->flags & CLIENT_ATTACHED) ||
375 (c->flags & CLIENT_CONTROL)) {
376 cf->error = EBADF;
377 goto done;
379 goto skip;
382 cf = file_create_with_client(c, stream, cb, cbdata);
383 cf->path = file_get_path(c, path);
385 if (c == NULL || c->flags & CLIENT_ATTACHED) {
386 f = fopen(cf->path, "rb");
387 if (f == NULL) {
388 cf->error = errno;
389 goto done;
391 for (;;) {
392 size = fread(buffer, 1, sizeof buffer, f);
393 if (evbuffer_add(cf->buffer, buffer, size) != 0) {
394 cf->error = ENOMEM;
395 goto done;
397 if (size != sizeof buffer)
398 break;
400 if (ferror(f)) {
401 cf->error = EIO;
402 goto done;
404 fclose(f);
405 goto done;
408 skip:
409 msglen = strlen(cf->path) + 1 + sizeof *msg;
410 if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
411 cf->error = E2BIG;
412 goto done;
414 msg = xmalloc(msglen);
415 msg->stream = cf->stream;
416 msg->fd = fd;
417 memcpy(msg + 1, cf->path, msglen - sizeof *msg);
418 if (proc_send(cf->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) {
419 free(msg);
420 cf->error = EINVAL;
421 goto done;
423 free(msg);
424 return cf;
426 done:
427 file_fire_done(cf);
428 return NULL;
431 /* Cancel a file read. */
432 void
433 file_cancel(struct client_file *cf)
435 struct msg_read_cancel msg;
437 log_debug("read cancel file %d", cf->stream);
439 if (cf->closed)
440 return;
441 cf->closed = 1;
443 msg.stream = cf->stream;
444 proc_send(cf->peer, MSG_READ_CANCEL, -1, &msg, sizeof msg);
447 /* Push event, fired if there is more writing to be done. */
448 static void
449 file_push_cb(__unused int fd, __unused short events, void *arg)
451 struct client_file *cf = arg;
453 if (cf->c == NULL || ~cf->c->flags & CLIENT_DEAD)
454 file_push(cf);
455 file_free(cf);
458 /* Push uwritten data to the client for a file, if it will accept it. */
459 void
460 file_push(struct client_file *cf)
462 struct msg_write_data *msg;
463 size_t msglen, sent, left;
464 struct msg_write_close close;
466 msg = xmalloc(sizeof *msg);
467 left = EVBUFFER_LENGTH(cf->buffer);
468 while (left != 0) {
469 sent = left;
470 if (sent > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
471 sent = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
473 msglen = (sizeof *msg) + sent;
474 msg = xrealloc(msg, msglen);
475 msg->stream = cf->stream;
476 memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent);
477 if (proc_send(cf->peer, MSG_WRITE, -1, msg, msglen) != 0)
478 break;
479 evbuffer_drain(cf->buffer, sent);
481 left = EVBUFFER_LENGTH(cf->buffer);
482 log_debug("file %d sent %zu, left %zu", cf->stream, sent, left);
484 if (left != 0) {
485 cf->references++;
486 event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL);
487 } else if (cf->stream > 2) {
488 close.stream = cf->stream;
489 proc_send(cf->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close);
490 file_fire_done(cf);
492 free(msg);
495 /* Check if any files have data left to write. */
497 file_write_left(struct client_files *files)
499 struct client_file *cf;
500 size_t left;
501 int waiting = 0;
503 RB_FOREACH(cf, client_files, files) {
504 if (cf->event == NULL)
505 continue;
506 left = EVBUFFER_LENGTH(cf->event->output);
507 if (left != 0) {
508 waiting++;
509 log_debug("file %u %zu bytes left", cf->stream, left);
512 return (waiting != 0);
515 /* Client file write error callback. */
516 static void
517 file_write_error_callback(__unused struct bufferevent *bev, __unused short what,
518 void *arg)
520 struct client_file *cf = arg;
522 log_debug("write error file %d", cf->stream);
524 bufferevent_free(cf->event);
525 cf->event = NULL;
527 close(cf->fd);
528 cf->fd = -1;
530 if (cf->cb != NULL)
531 cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
534 /* Client file write callback. */
535 static void
536 file_write_callback(__unused struct bufferevent *bev, void *arg)
538 struct client_file *cf = arg;
540 log_debug("write check file %d", cf->stream);
542 if (cf->cb != NULL)
543 cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
545 if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) {
546 bufferevent_free(cf->event);
547 close(cf->fd);
548 RB_REMOVE(client_files, cf->tree, cf);
549 file_free(cf);
553 /* Handle a file write open message (client). */
554 void
555 file_write_open(struct client_files *files, struct tmuxpeer *peer,
556 struct imsg *imsg, int allow_streams, int close_received,
557 client_file_cb cb, void *cbdata)
559 struct msg_write_open *msg = imsg->data;
560 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
561 const char *path;
562 struct msg_write_ready reply;
563 struct client_file find, *cf;
564 const int flags = O_NONBLOCK|O_WRONLY|O_CREAT;
565 int error = 0;
567 if (msglen < sizeof *msg)
568 fatalx("bad MSG_WRITE_OPEN size");
569 if (msglen == sizeof *msg)
570 path = "-";
571 else
572 path = (const char *)(msg + 1);
573 log_debug("open write file %d %s", msg->stream, path);
575 find.stream = msg->stream;
576 if (RB_FIND(client_files, files, &find) != NULL) {
577 error = EBADF;
578 goto reply;
580 cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
581 if (cf->closed) {
582 error = EBADF;
583 goto reply;
586 cf->fd = -1;
587 if (msg->fd == -1)
588 cf->fd = open(path, msg->flags|flags, 0644);
589 else if (allow_streams) {
590 if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO)
591 errno = EBADF;
592 else {
593 cf->fd = dup(msg->fd);
594 if (close_received)
595 close(msg->fd); /* can only be used once */
597 } else
598 errno = EBADF;
599 if (cf->fd == -1) {
600 error = errno;
601 goto reply;
604 cf->event = bufferevent_new(cf->fd, NULL, file_write_callback,
605 file_write_error_callback, cf);
606 if (cf->event == NULL)
607 fatalx("out of memory");
608 bufferevent_enable(cf->event, EV_WRITE);
609 goto reply;
611 reply:
612 reply.stream = msg->stream;
613 reply.error = error;
614 proc_send(peer, MSG_WRITE_READY, -1, &reply, sizeof reply);
617 /* Handle a file write data message (client). */
618 void
619 file_write_data(struct client_files *files, struct imsg *imsg)
621 struct msg_write_data *msg = imsg->data;
622 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
623 struct client_file find, *cf;
624 size_t size = msglen - sizeof *msg;
626 if (msglen < sizeof *msg)
627 fatalx("bad MSG_WRITE size");
628 find.stream = msg->stream;
629 if ((cf = RB_FIND(client_files, files, &find)) == NULL)
630 fatalx("unknown stream number");
631 log_debug("write %zu to file %d", size, cf->stream);
633 if (cf->event != NULL)
634 bufferevent_write(cf->event, msg + 1, size);
637 /* Handle a file write close message (client). */
638 void
639 file_write_close(struct client_files *files, struct imsg *imsg)
641 struct msg_write_close *msg = imsg->data;
642 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
643 struct client_file find, *cf;
645 if (msglen != sizeof *msg)
646 fatalx("bad MSG_WRITE_CLOSE size");
647 find.stream = msg->stream;
648 if ((cf = RB_FIND(client_files, files, &find)) == NULL)
649 fatalx("unknown stream number");
650 log_debug("close file %d", cf->stream);
652 if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) {
653 if (cf->event != NULL)
654 bufferevent_free(cf->event);
655 if (cf->fd != -1)
656 close(cf->fd);
657 RB_REMOVE(client_files, files, cf);
658 file_free(cf);
662 /* Client file read error callback. */
663 static void
664 file_read_error_callback(__unused struct bufferevent *bev, __unused short what,
665 void *arg)
667 struct client_file *cf = arg;
668 struct msg_read_done msg;
670 log_debug("read error file %d", cf->stream);
672 msg.stream = cf->stream;
673 msg.error = 0;
674 proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg);
676 bufferevent_free(cf->event);
677 close(cf->fd);
678 RB_REMOVE(client_files, cf->tree, cf);
679 file_free(cf);
682 /* Client file read callback. */
683 static void
684 file_read_callback(__unused struct bufferevent *bev, void *arg)
686 struct client_file *cf = arg;
687 void *bdata;
688 size_t bsize;
689 struct msg_read_data *msg;
690 size_t msglen;
692 msg = xmalloc(sizeof *msg);
693 for (;;) {
694 bdata = EVBUFFER_DATA(cf->event->input);
695 bsize = EVBUFFER_LENGTH(cf->event->input);
697 if (bsize == 0)
698 break;
699 if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
700 bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
701 log_debug("read %zu from file %d", bsize, cf->stream);
703 msglen = (sizeof *msg) + bsize;
704 msg = xrealloc(msg, msglen);
705 msg->stream = cf->stream;
706 memcpy(msg + 1, bdata, bsize);
707 proc_send(cf->peer, MSG_READ, -1, msg, msglen);
709 evbuffer_drain(cf->event->input, bsize);
711 free(msg);
714 /* Handle a file read open message (client). */
715 void
716 file_read_open(struct client_files *files, struct tmuxpeer *peer,
717 struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb,
718 void *cbdata)
720 struct msg_read_open *msg = imsg->data;
721 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
722 const char *path;
723 struct msg_read_done reply;
724 struct client_file find, *cf;
725 const int flags = O_NONBLOCK|O_RDONLY;
726 int error;
728 if (msglen < sizeof *msg)
729 fatalx("bad MSG_READ_OPEN size");
730 if (msglen == sizeof *msg)
731 path = "-";
732 else
733 path = (const char *)(msg + 1);
734 log_debug("open read file %d %s", msg->stream, path);
736 find.stream = msg->stream;
737 if (RB_FIND(client_files, files, &find) != NULL) {
738 error = EBADF;
739 goto reply;
741 cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
742 if (cf->closed) {
743 error = EBADF;
744 goto reply;
747 cf->fd = -1;
748 if (msg->fd == -1)
749 cf->fd = open(path, flags);
750 else if (allow_streams) {
751 if (msg->fd != STDIN_FILENO)
752 errno = EBADF;
753 else {
754 cf->fd = dup(msg->fd);
755 if (close_received)
756 close(msg->fd); /* can only be used once */
758 } else
759 errno = EBADF;
760 if (cf->fd == -1) {
761 error = errno;
762 goto reply;
765 cf->event = bufferevent_new(cf->fd, file_read_callback, NULL,
766 file_read_error_callback, cf);
767 if (cf->event == NULL)
768 fatalx("out of memory");
769 bufferevent_enable(cf->event, EV_READ);
770 return;
772 reply:
773 reply.stream = msg->stream;
774 reply.error = error;
775 proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply);
778 /* Handle a read cancel message (client). */
779 void
780 file_read_cancel(struct client_files *files, struct imsg *imsg)
782 struct msg_read_cancel *msg = imsg->data;
783 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
784 struct client_file find, *cf;
786 if (msglen != sizeof *msg)
787 fatalx("bad MSG_READ_CANCEL size");
788 find.stream = msg->stream;
789 if ((cf = RB_FIND(client_files, files, &find)) == NULL)
790 fatalx("unknown stream number");
791 log_debug("cancel file %d", cf->stream);
793 file_read_error_callback(NULL, 0, cf);
796 /* Handle a write ready message (server). */
797 void
798 file_write_ready(struct client_files *files, struct imsg *imsg)
800 struct msg_write_ready *msg = imsg->data;
801 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
802 struct client_file find, *cf;
804 if (msglen != sizeof *msg)
805 fatalx("bad MSG_WRITE_READY size");
806 find.stream = msg->stream;
807 if ((cf = RB_FIND(client_files, files, &find)) == NULL)
808 return;
809 if (msg->error != 0) {
810 cf->error = msg->error;
811 file_fire_done(cf);
812 } else
813 file_push(cf);
816 /* Handle read data message (server). */
817 void
818 file_read_data(struct client_files *files, struct imsg *imsg)
820 struct msg_read_data *msg = imsg->data;
821 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
822 struct client_file find, *cf;
823 void *bdata = msg + 1;
824 size_t bsize = msglen - sizeof *msg;
826 if (msglen < sizeof *msg)
827 fatalx("bad MSG_READ_DATA size");
828 find.stream = msg->stream;
829 if ((cf = RB_FIND(client_files, files, &find)) == NULL)
830 return;
832 log_debug("file %d read %zu bytes", cf->stream, bsize);
833 if (cf->error == 0 && !cf->closed) {
834 if (evbuffer_add(cf->buffer, bdata, bsize) != 0) {
835 cf->error = ENOMEM;
836 file_fire_done(cf);
837 } else
838 file_fire_read(cf);
842 /* Handle a read done message (server). */
843 void
844 file_read_done(struct client_files *files, struct imsg *imsg)
846 struct msg_read_done *msg = imsg->data;
847 size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
848 struct client_file find, *cf;
850 if (msglen != sizeof *msg)
851 fatalx("bad MSG_READ_DONE size");
852 find.stream = msg->stream;
853 if ((cf = RB_FIND(client_files, files, &find)) == NULL)
854 return;
856 log_debug("file %d read done", cf->stream);
857 cf->error = msg->error;
858 file_fire_done(cf);