"Fossies" - the Fresh Open Source Software Archive

Member "tmux-3.2a/file.c" (10 Jun 2021, 19159 Bytes) of package /linux/misc/tmux-3.2a.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "file.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.2_vs_3.2a.

    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 
   38 RB_GENERATE(client_files, client_file, entry, file_cmp);
   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 *
   71 file_create_with_peer(struct tmuxpeer *peer, struct client_files *files,
   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 *
   97 file_create_with_client(struct client *c, int stream, client_file_cb cb,
   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
  129 file_free(struct client_file *cf)
  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
  159 file_fire_done(struct client_file *cf)
  160 {
  161     event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL);
  162 }
  163 
  164 /* Fire the read callback. */
  165 void
  166 file_fire_read(struct client_file *cf)
  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
  174 file_can_print(struct client *c)
  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
  442 file_push(struct client_file *cf)
  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
  479 file_write_left(struct client_files *files)
  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,
  587         file_write_error_callback, cf);
  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,
  746         file_read_error_callback, cf);
  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 }