xref: /openbsd-src/usr.bin/tmux/file.c (revision d0fc3bb68efd6c434b4053cd7adb29023cbec341)
1 /* $OpenBSD: file.c,v 1.11 2021/06/10 07:51:43 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 /* 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 
488 	RB_FOREACH(cf, client_files, files) {
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);
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;
514 
515 	if (cf->cb != NULL)
516 		cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
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);
822 }
823