Annotation of src/usr.bin/tmux/file.c, Revision 1.11
1.11 ! nicm 1: /* $OpenBSD: file.c,v 1.10 2021/02/12 06:52:48 nicm Exp $ */
1.1 nicm 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>
1.3 nicm 20: #include <sys/queue.h>
1.6 nicm 21: #include <sys/uio.h>
1.1 nicm 22:
23: #include <errno.h>
24: #include <fcntl.h>
1.3 nicm 25: #include <imsg.h>
1.1 nicm 26: #include <stdio.h>
27: #include <stdlib.h>
28: #include <string.h>
29: #include <unistd.h>
30:
31: #include "tmux.h"
32:
1.8 nicm 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:
1.1 nicm 39: static int file_next_stream = 3;
40:
41: RB_GENERATE(client_files, client_file, entry, file_cmp);
42:
1.8 nicm 43: /* Get path for file, either as given or from working directory. */
1.5 nicm 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:
1.8 nicm 56: /* Tree comparison function. */
1.1 nicm 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:
1.8 nicm 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: */
1.1 nicm 73: struct client_file *
1.8 nicm 74: file_create_with_peer(struct tmuxpeer *peer, struct client_files *files,
75: int stream, client_file_cb cb, void *cbdata)
1.1 nicm 76: {
77: struct client_file *cf;
78:
79: cf = xcalloc(1, sizeof *cf);
1.8 nicm 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);
1.1 nicm 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) {
1.8 nicm 121: cf->peer = cf->c->peer;
122: cf->tree = &cf->c->files;
1.1 nicm 123: RB_INSERT(client_files, &cf->c->files, cf);
124: cf->c->references++;
125: }
126:
127: return (cf);
128: }
129:
1.8 nicm 130: /* Free a file. */
1.1 nicm 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:
1.8 nicm 140: if (cf->tree != NULL)
141: RB_REMOVE(client_files, cf->tree, cf);
142: if (cf->c != NULL)
1.1 nicm 143: server_client_unref(cf->c);
1.8 nicm 144:
1.1 nicm 145: free(cf);
146: }
147:
1.8 nicm 148: /* Event to fire the done callback. */
1.1 nicm 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:
1.2 nicm 155: if (cf->cb != NULL && (c == NULL || (~c->flags & CLIENT_DEAD)))
1.1 nicm 156: cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data);
157: file_free(cf);
158: }
159:
1.8 nicm 160: /* Add an event to fire the done callback (used by the server). */
1.1 nicm 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:
1.8 nicm 167: /* Fire the read callback. */
1.1 nicm 168: void
169: file_fire_read(struct client_file *cf)
170: {
171: if (cf->cb != NULL)
1.8 nicm 172: cf->cb(cf->c, cf->path, cf->error, 0, cf->buffer, cf->data);
1.1 nicm 173: }
174:
1.8 nicm 175: /* Can this file be printed to? */
1.1 nicm 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:
1.8 nicm 186: /* Print a message to a file. */
1.1 nicm 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:
1.8 nicm 197: /* Print a message to a file. */
1.1 nicm 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) {
1.8 nicm 209: cf = file_create_with_client(c, 1, NULL, NULL);
1.1 nicm 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:
1.8 nicm 224: /* Print a buffer to a file. */
1.1 nicm 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) {
1.8 nicm 236: cf = file_create_with_client(c, 1, NULL, NULL);
1.1 nicm 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:
1.8 nicm 251: /* Report an error to a file. */
1.1 nicm 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) {
1.8 nicm 266: cf = file_create_with_client(c, 2, NULL, NULL);
1.1 nicm 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:
1.8 nicm 283: /* Write data to a file. */
1.1 nicm 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;
1.3 nicm 289: struct msg_write_open *msg;
290: size_t msglen;
1.1 nicm 291: int fd = -1;
1.8 nicm 292: u_int stream = file_next_stream++;
293: FILE *f;
1.1 nicm 294: const char *mode;
295:
296: if (strcmp(path, "-") == 0) {
1.8 nicm 297: cf = file_create_with_client(c, stream, cb, cbdata);
1.1 nicm 298: cf->path = xstrdup("-");
299:
300: fd = STDOUT_FILENO;
1.7 nicm 301: if (c == NULL ||
302: (c->flags & CLIENT_ATTACHED) ||
303: (c->flags & CLIENT_CONTROL)) {
1.1 nicm 304: cf->error = EBADF;
305: goto done;
306: }
307: goto skip;
308: }
309:
1.8 nicm 310: cf = file_create_with_client(c, stream, cb, cbdata);
1.5 nicm 311: cf->path = file_get_path(c, path);
1.1 nicm 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:
1.3 nicm 335: msglen = strlen(cf->path) + 1 + sizeof *msg;
336: if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1.1 nicm 337: cf->error = E2BIG;
338: goto done;
339: }
1.3 nicm 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);
1.8 nicm 345: if (proc_send(cf->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) {
1.3 nicm 346: free(msg);
1.1 nicm 347: cf->error = EINVAL;
348: goto done;
349: }
1.3 nicm 350: free(msg);
1.1 nicm 351: return;
352:
353: done:
354: file_fire_done(cf);
355: }
356:
1.8 nicm 357: /* Read a file. */
1.1 nicm 358: void
359: file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
360: {
361: struct client_file *cf;
1.3 nicm 362: struct msg_read_open *msg;
1.8 nicm 363: size_t msglen;
1.1 nicm 364: int fd = -1;
1.8 nicm 365: u_int stream = file_next_stream++;
366: FILE *f;
367: size_t size;
1.1 nicm 368: char buffer[BUFSIZ];
369:
370: if (strcmp(path, "-") == 0) {
1.8 nicm 371: cf = file_create_with_client(c, stream, cb, cbdata);
1.1 nicm 372: cf->path = xstrdup("-");
373:
374: fd = STDIN_FILENO;
1.7 nicm 375: if (c == NULL ||
376: (c->flags & CLIENT_ATTACHED) ||
377: (c->flags & CLIENT_CONTROL)) {
1.1 nicm 378: cf->error = EBADF;
379: goto done;
380: }
381: goto skip;
382: }
383:
1.8 nicm 384: cf = file_create_with_client(c, stream, cb, cbdata);
1.5 nicm 385: cf->path = file_get_path(c, path);
1.1 nicm 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:
1.3 nicm 411: msglen = strlen(cf->path) + 1 + sizeof *msg;
412: if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
1.1 nicm 413: cf->error = E2BIG;
414: goto done;
415: }
1.3 nicm 416: msg = xmalloc(msglen);
417: msg->stream = cf->stream;
418: msg->fd = fd;
419: memcpy(msg + 1, cf->path, msglen - sizeof *msg);
1.8 nicm 420: if (proc_send(cf->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) {
1.3 nicm 421: free(msg);
1.1 nicm 422: cf->error = EINVAL;
423: goto done;
424: }
1.3 nicm 425: free(msg);
1.1 nicm 426: return;
427:
428: done:
429: file_fire_done(cf);
430: }
431:
1.8 nicm 432: /* Push event, fired if there is more writing to be done. */
1.1 nicm 433: static void
434: file_push_cb(__unused int fd, __unused short events, void *arg)
435: {
436: struct client_file *cf = arg;
437:
1.8 nicm 438: if (cf->c == NULL || ~cf->c->flags & CLIENT_DEAD)
1.1 nicm 439: file_push(cf);
440: file_free(cf);
441: }
442:
1.8 nicm 443: /* Push uwritten data to the client for a file, if it will accept it. */
1.1 nicm 444: void
445: file_push(struct client_file *cf)
446: {
1.3 nicm 447: struct msg_write_data *msg;
448: size_t msglen, sent, left;
1.1 nicm 449: struct msg_write_close close;
450:
1.3 nicm 451: msg = xmalloc(sizeof *msg);
1.1 nicm 452: left = EVBUFFER_LENGTH(cf->buffer);
453: while (left != 0) {
454: sent = left;
1.4 nicm 455: if (sent > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
456: sent = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
1.1 nicm 457:
1.3 nicm 458: msglen = (sizeof *msg) + sent;
459: msg = xrealloc(msg, msglen);
460: msg->stream = cf->stream;
461: memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent);
1.8 nicm 462: if (proc_send(cf->peer, MSG_WRITE, -1, msg, msglen) != 0)
1.1 nicm 463: break;
464: evbuffer_drain(cf->buffer, sent);
465:
466: left = EVBUFFER_LENGTH(cf->buffer);
1.8 nicm 467: log_debug("file %d sent %zu, left %zu", cf->stream, sent, left);
1.1 nicm 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;
1.8 nicm 474: proc_send(cf->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close);
1.1 nicm 475: file_fire_done(cf);
476: }
1.3 nicm 477: free(msg);
1.9 nicm 478: }
479:
480: /* Check if any files have data left to write. */
481: int
482: file_write_left(struct client_files *files)
483: {
484: struct client_file *cf;
485: size_t left;
486: int waiting = 0;
487:
1.10 nicm 488: RB_FOREACH(cf, client_files, files) {
1.9 nicm 489: if (cf->event == NULL)
490: continue;
491: left = EVBUFFER_LENGTH(cf->event->output);
492: if (left != 0) {
493: waiting++;
494: log_debug("file %u %zu bytes left", cf->stream, left);
495: }
496: }
497: return (waiting != 0);
1.8 nicm 498: }
499:
500: /* Client file write error callback. */
501: static void
502: file_write_error_callback(__unused struct bufferevent *bev, __unused short what,
503: void *arg)
504: {
505: struct client_file *cf = arg;
506:
507: log_debug("write error file %d", cf->stream);
508:
509: bufferevent_free(cf->event);
510: cf->event = NULL;
511:
512: close(cf->fd);
513: cf->fd = -1;
1.11 ! nicm 514:
! 515: if (cf->cb != NULL)
! 516: cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
1.8 nicm 517: }
518:
519: /* Client file write callback. */
520: static void
521: file_write_callback(__unused struct bufferevent *bev, void *arg)
522: {
523: struct client_file *cf = arg;
524:
525: log_debug("write check file %d", cf->stream);
526:
527: if (cf->cb != NULL)
528: cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
529:
530: if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) {
531: bufferevent_free(cf->event);
532: close(cf->fd);
533: RB_REMOVE(client_files, cf->tree, cf);
534: file_free(cf);
535: }
536: }
537:
538: /* Handle a file write open message (client). */
539: void
540: file_write_open(struct client_files *files, struct tmuxpeer *peer,
541: struct imsg *imsg, int allow_streams, int close_received,
542: client_file_cb cb, void *cbdata)
543: {
544: struct msg_write_open *msg = imsg->data;
545: size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
546: const char *path;
547: struct msg_write_ready reply;
548: struct client_file find, *cf;
549: const int flags = O_NONBLOCK|O_WRONLY|O_CREAT;
550: int error = 0;
551:
552: if (msglen < sizeof *msg)
553: fatalx("bad MSG_WRITE_OPEN size");
554: if (msglen == sizeof *msg)
555: path = "-";
556: else
557: path = (const char *)(msg + 1);
558: log_debug("open write file %d %s", msg->stream, path);
559:
560: find.stream = msg->stream;
561: if ((cf = RB_FIND(client_files, files, &find)) != NULL) {
562: error = EBADF;
563: goto reply;
564: }
565: cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
566: if (cf->closed) {
567: error = EBADF;
568: goto reply;
569: }
570:
571: cf->fd = -1;
572: if (msg->fd == -1)
573: cf->fd = open(path, msg->flags|flags, 0644);
574: else if (allow_streams) {
575: if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO)
576: errno = EBADF;
577: else {
578: cf->fd = dup(msg->fd);
579: if (close_received)
580: close(msg->fd); /* can only be used once */
581: }
582: } else
583: errno = EBADF;
584: if (cf->fd == -1) {
585: error = errno;
586: goto reply;
587: }
588:
589: cf->event = bufferevent_new(cf->fd, NULL, file_write_callback,
590: file_write_error_callback, cf);
591: bufferevent_enable(cf->event, EV_WRITE);
592: goto reply;
593:
594: reply:
595: reply.stream = msg->stream;
596: reply.error = error;
597: proc_send(peer, MSG_WRITE_READY, -1, &reply, sizeof reply);
598: }
599:
600: /* Handle a file write data message (client). */
601: void
602: file_write_data(struct client_files *files, struct imsg *imsg)
603: {
604: struct msg_write_data *msg = imsg->data;
605: size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
606: struct client_file find, *cf;
607: size_t size = msglen - sizeof *msg;
608:
609: if (msglen < sizeof *msg)
610: fatalx("bad MSG_WRITE size");
611: find.stream = msg->stream;
612: if ((cf = RB_FIND(client_files, files, &find)) == NULL)
613: fatalx("unknown stream number");
614: log_debug("write %zu to file %d", size, cf->stream);
615:
616: if (cf->event != NULL)
617: bufferevent_write(cf->event, msg + 1, size);
618: }
619:
620: /* Handle a file write close message (client). */
621: void
622: file_write_close(struct client_files *files, struct imsg *imsg)
623: {
624: struct msg_write_close *msg = imsg->data;
625: size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
626: struct client_file find, *cf;
627:
628: if (msglen != sizeof *msg)
629: fatalx("bad MSG_WRITE_CLOSE size");
630: find.stream = msg->stream;
631: if ((cf = RB_FIND(client_files, files, &find)) == NULL)
632: fatalx("unknown stream number");
633: log_debug("close file %d", cf->stream);
634:
635: if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) {
636: if (cf->event != NULL)
637: bufferevent_free(cf->event);
638: if (cf->fd != -1)
639: close(cf->fd);
640: RB_REMOVE(client_files, files, cf);
641: file_free(cf);
642: }
643: }
644:
645: /* Client file read error callback. */
646: static void
647: file_read_error_callback(__unused struct bufferevent *bev, __unused short what,
648: void *arg)
649: {
650: struct client_file *cf = arg;
651: struct msg_read_done msg;
652:
653: log_debug("read error file %d", cf->stream);
654:
655: msg.stream = cf->stream;
656: msg.error = 0;
657: proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg);
658:
659: bufferevent_free(cf->event);
660: close(cf->fd);
661: RB_REMOVE(client_files, cf->tree, cf);
662: file_free(cf);
663: }
664:
665: /* Client file read callback. */
666: static void
667: file_read_callback(__unused struct bufferevent *bev, void *arg)
668: {
669: struct client_file *cf = arg;
670: void *bdata;
671: size_t bsize;
672: struct msg_read_data *msg;
673: size_t msglen;
674:
675: msg = xmalloc(sizeof *msg);
676: for (;;) {
677: bdata = EVBUFFER_DATA(cf->event->input);
678: bsize = EVBUFFER_LENGTH(cf->event->input);
679:
680: if (bsize == 0)
681: break;
682: if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
683: bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
684: log_debug("read %zu from file %d", bsize, cf->stream);
685:
686: msglen = (sizeof *msg) + bsize;
687: msg = xrealloc(msg, msglen);
688: msg->stream = cf->stream;
689: memcpy(msg + 1, bdata, bsize);
690: proc_send(cf->peer, MSG_READ, -1, msg, msglen);
691:
692: evbuffer_drain(cf->event->input, bsize);
693: }
694: free(msg);
695: }
696:
697: /* Handle a file read open message (client). */
698: void
699: file_read_open(struct client_files *files, struct tmuxpeer *peer,
700: struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb,
701: void *cbdata)
702: {
703: struct msg_read_open *msg = imsg->data;
704: size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
705: const char *path;
706: struct msg_read_done reply;
707: struct client_file find, *cf;
708: const int flags = O_NONBLOCK|O_RDONLY;
709: int error;
710:
711: if (msglen < sizeof *msg)
712: fatalx("bad MSG_READ_OPEN size");
713: if (msglen == sizeof *msg)
714: path = "-";
715: else
716: path = (const char *)(msg + 1);
717: log_debug("open read file %d %s", msg->stream, path);
718:
719: find.stream = msg->stream;
720: if ((cf = RB_FIND(client_files, files, &find)) != NULL) {
721: error = EBADF;
722: goto reply;
723: }
724: cf = file_create_with_peer(peer, files, msg->stream, cb, cbdata);
725: if (cf->closed) {
726: error = EBADF;
727: goto reply;
728: }
729:
730: cf->fd = -1;
731: if (msg->fd == -1)
732: cf->fd = open(path, flags);
733: else if (allow_streams) {
734: if (msg->fd != STDIN_FILENO)
735: errno = EBADF;
736: else {
737: cf->fd = dup(msg->fd);
738: if (close_received)
739: close(msg->fd); /* can only be used once */
740: }
741: } else
742: errno = EBADF;
743: if (cf->fd == -1) {
744: error = errno;
745: goto reply;
746: }
747:
748: cf->event = bufferevent_new(cf->fd, file_read_callback, NULL,
749: file_read_error_callback, cf);
750: bufferevent_enable(cf->event, EV_READ);
751: return;
752:
753: reply:
754: reply.stream = msg->stream;
755: reply.error = error;
756: proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply);
757: }
758:
759: /* Handle a write ready message (server). */
760: void
761: file_write_ready(struct client_files *files, struct imsg *imsg)
762: {
763: struct msg_write_ready *msg = imsg->data;
764: size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
765: struct client_file find, *cf;
766:
767: if (msglen != sizeof *msg)
768: fatalx("bad MSG_WRITE_READY size");
769: find.stream = msg->stream;
770: if ((cf = RB_FIND(client_files, files, &find)) == NULL)
771: return;
772: if (msg->error != 0) {
773: cf->error = msg->error;
774: file_fire_done(cf);
775: } else
776: file_push(cf);
777: }
778:
779: /* Handle read data message (server). */
780: void
781: file_read_data(struct client_files *files, struct imsg *imsg)
782: {
783: struct msg_read_data *msg = imsg->data;
784: size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
785: struct client_file find, *cf;
786: void *bdata = msg + 1;
787: size_t bsize = msglen - sizeof *msg;
788:
789: if (msglen < sizeof *msg)
790: fatalx("bad MSG_READ_DATA size");
791: find.stream = msg->stream;
792: if ((cf = RB_FIND(client_files, files, &find)) == NULL)
793: return;
794:
795: log_debug("file %d read %zu bytes", cf->stream, bsize);
796: if (cf->error == 0) {
797: if (evbuffer_add(cf->buffer, bdata, bsize) != 0) {
798: cf->error = ENOMEM;
799: file_fire_done(cf);
800: } else
801: file_fire_read(cf);
802: }
803: }
804:
805: /* Handle a read done message (server). */
806: void
807: file_read_done(struct client_files *files, struct imsg *imsg)
808: {
809: struct msg_read_done *msg = imsg->data;
810: size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
811: struct client_file find, *cf;
812:
813: if (msglen != sizeof *msg)
814: fatalx("bad MSG_READ_DONE size");
815: find.stream = msg->stream;
816: if ((cf = RB_FIND(client_files, files, &find)) == NULL)
817: return;
818:
819: log_debug("file %d read done", cf->stream);
820: cf->error = msg->error;
821: file_fire_done(cf);
1.1 nicm 822: }