tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

file.c
Go to the documentation of this file.
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 
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 *
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 *
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
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
160 {
161  event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL);
162 }
163 
164 /* Fire the read callback. */
165 void
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
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
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
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  bufferevent_free(cf->event);
507  cf->event = NULL;
508 
509  close(cf->fd);
510  cf->fd = -1;
511 
512  if (cf->cb != NULL)
513  cf->cb(NULL, NULL, 0, -1, NULL, cf->data);
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,
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,
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 }
static struct client_files client_files
Definition: client.c:58
#define __unused
Definition: compat.h:60
static void file_read_callback(struct bufferevent *bev, void *arg)
Definition: file.c:664
void file_write_ready(struct client_files *files, struct imsg *imsg)
Definition: file.c:758
int file_can_print(struct client *c)
Definition: file.c:174
static int file_next_stream
Definition: file.c:36
void file_read_open(struct client_files *files, struct tmuxpeer *peer, struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb, void *cbdata)
Definition: file.c:696
void file_error(struct client *c, const char *fmt,...)
Definition: file.c:250
struct client_file * file_create_with_peer(struct tmuxpeer *peer, struct client_files *files, int stream, client_file_cb cb, void *cbdata)
Definition: file.c:71
void file_write_data(struct client_files *files, struct imsg *imsg)
Definition: file.c:599
void file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
Definition: file.c:356
void file_read_done(struct client_files *files, struct imsg *imsg)
Definition: file.c:804
static void file_read_error_callback(struct bufferevent *bev, short what, void *arg)
Definition: file.c:644
struct client_file * file_create_with_client(struct client *c, int stream, client_file_cb cb, void *cbdata)
Definition: file.c:97
static char * file_get_path(struct client *c, const char *file)
Definition: file.c:42
void file_write_close(struct client_files *files, struct imsg *imsg)
Definition: file.c:619
int file_write_left(struct client_files *files)
Definition: file.c:479
static void file_write_callback(struct bufferevent *bev, void *arg)
Definition: file.c:518
static void file_fire_done_cb(int fd, short events, void *arg)
Definition: file.c:147
int file_cmp(struct client_file *cf1, struct client_file *cf2)
Definition: file.c:55
void file_vprint(struct client *c, const char *fmt, va_list ap)
Definition: file.c:196
void file_free(struct client_file *cf)
Definition: file.c:129
void file_print(struct client *c, const char *fmt,...)
Definition: file.c:185
static void file_write_error_callback(struct bufferevent *bev, short what, void *arg)
Definition: file.c:499
void file_fire_read(struct client_file *cf)
Definition: file.c:166
void file_write(struct client *c, const char *path, int flags, const void *bdata, size_t bsize, client_file_cb cb, void *cbdata)
Definition: file.c:282
RB_GENERATE(client_files, client_file, entry, file_cmp)
void file_write_open(struct client_files *files, struct tmuxpeer *peer, struct imsg *imsg, int allow_streams, int close_received, client_file_cb cb, void *cbdata)
Definition: file.c:537
static void file_push_cb(int fd, short events, void *arg)
Definition: file.c:431
void file_push(struct client_file *cf)
Definition: file.c:442
void file_print_buffer(struct client *c, void *data, size_t size)
Definition: file.c:223
void file_read_data(struct client_files *files, struct imsg *imsg)
Definition: file.c:778
void file_fire_done(struct client_file *cf)
Definition: file.c:159
void fatalx(const char *msg,...)
Definition: log.c:159
void log_debug(const char *msg,...)
Definition: log.c:130
int proc_send(struct tmuxpeer *peer, enum msgtype type, int fd, const void *buf, size_t len)
Definition: proc.c:162
void server_client_unref(struct client *c)
const char * server_client_get_cwd(struct client *c, struct session *s)
int stream
Definition: tmux.h:1575
client_file_cb cb
Definition: tmux.h:1585
struct tmuxpeer * peer
Definition: tmux.h:1572
struct evbuffer * buffer
Definition: tmux.h:1578
void * data
Definition: tmux.h:1586
int references
Definition: tmux.h:1574
int error
Definition: tmux.h:1582
int fd
Definition: tmux.h:1581
struct client_files * tree
Definition: tmux.h:1573
int closed
Definition: tmux.h:1583
struct client * c
Definition: tmux.h:1571
struct bufferevent * event
Definition: tmux.h:1579
char * path
Definition: tmux.h:1577
Definition: tmux.h:1608
struct client_files files
Definition: tmux.h:1760
int references
Definition: tmux.h:1746
struct session * session
Definition: tmux.h:1743
uint64_t flags
Definition: tmux.h:1703
struct tmuxpeer * peer
Definition: tmux.h:1610
int stream
Definition: tmux.h:566
int stream
Definition: tmux.h:570
int error
Definition: tmux.h:571
int stream
Definition: tmux.h:561
int fd
Definition: tmux.h:562
int stream
Definition: tmux.h:590
int stream
Definition: tmux.h:581
int stream
Definition: tmux.h:575
int flags
Definition: tmux.h:577
int stream
Definition: tmux.h:585
Definition: proc.c:54
@ MSG_WRITE_OPEN
Definition: tmux.h:545
@ MSG_READ
Definition: tmux.h:543
@ MSG_WRITE
Definition: tmux.h:546
@ MSG_READ_OPEN
Definition: tmux.h:542
@ MSG_WRITE_CLOSE
Definition: tmux.h:548
@ MSG_READ_DONE
Definition: tmux.h:544
@ MSG_WRITE_READY
Definition: tmux.h:547
void(* client_file_cb)(struct client *, const char *, int, int, struct evbuffer *, void *)
Definition: tmux.h:1568
#define CLIENT_ATTACHED
Definition: tmux.h:1661
#define CLIENT_CONTROL
Definition: tmux.h:1667
#define CLIENT_DEAD
Definition: tmux.h:1663
enum window_copy_cmd_action(* f)(struct window_copy_cmd_state *)
Definition: window-copy.c:2248
void * xmalloc(size_t size)
Definition: xmalloc.c:27
void * xrealloc(void *ptr, size_t size)
Definition: xmalloc.c:55
int xasprintf(char **ret, const char *fmt,...)
Definition: xmalloc.c:109
void * xcalloc(size_t nmemb, size_t size)
Definition: xmalloc.c:41
char * xstrdup(const char *str)
Definition: xmalloc.c:89