+ if (FD_ISSET(fd, &e_fds)) {
+ rsyserr(FINFO, errno,
+ "select exception on fd %d", fd);
+ }
+ continue;
+ }
+ if (cnt != 1)
+ break;
+ if (nulls? !ch : (ch == '\r' || ch == '\n')) {
+ /* Skip empty lines if reading locally. */
+ if (!reading_remotely && s == fname)
+ continue;
+ break;
+ }
+ if (s < eob)
+ *s++ = ch;
+ }
+ *s = '\0';
+
+ /* Dump comments. */
+ if (*fname == '#' || *fname == ';')
+ goto start;
+
+ return s - fname;
+}
+
+int io_start_buffering_out(int f_out)
+{
+ if (iobuf_out) {
+ assert(f_out == iobuf_f_out);
+ return 0;
+ }
+ if (!(iobuf_out = new_array(char, IO_BUFFER_SIZE)))
+ out_of_memory("io_start_buffering_out");
+ iobuf_out_cnt = 0;
+ iobuf_f_out = f_out;
+ return 1;
+}
+
+int io_start_buffering_in(int f_in)
+{
+ if (iobuf_in) {
+ assert(f_in == iobuf_f_in);
+ return 0;
+ }
+ iobuf_in_siz = 2 * IO_BUFFER_SIZE;
+ if (!(iobuf_in = new_array(char, iobuf_in_siz)))
+ out_of_memory("io_start_buffering_in");
+ iobuf_f_in = f_in;
+ return 1;
+}
+
+void io_end_buffering_in(void)
+{
+ if (!iobuf_in)
+ return;
+ free(iobuf_in);
+ iobuf_in = NULL;
+ iobuf_in_ndx = 0;
+ iobuf_in_remaining = 0;
+ iobuf_f_in = -1;
+}
+
+void io_end_buffering_out(void)
+{
+ if (!iobuf_out)
+ return;
+ io_flush(FULL_FLUSH);
+ free(iobuf_out);
+ iobuf_out = NULL;
+ iobuf_f_out = -1;
+}
+
+void maybe_flush_socket(void)
+{
+ if (iobuf_out && iobuf_out_cnt && time(NULL) - last_io_out >= 5)
+ io_flush(NORMAL_FLUSH);
+}
+
+void maybe_send_keepalive(void)
+{
+ if (time(NULL) - last_io_out >= allowed_lull) {
+ if (!iobuf_out || !iobuf_out_cnt) {
+ if (protocol_version < 29)
+ return; /* there's nothing we can do */
+ if (protocol_version >= 30)
+ send_msg(MSG_NOOP, "", 0);
+ else {
+ write_int(sock_f_out, cur_flist->count);
+ write_shortint(sock_f_out, ITEM_IS_NEW);
+ }
+ }
+ if (iobuf_out)
+ io_flush(NORMAL_FLUSH);
+ }
+}
+
+void start_flist_forward(int f_in)
+{
+ assert(iobuf_out != NULL);
+ assert(iobuf_f_out == msg_fd_out);
+ flist_forward_from = f_in;
+}
+
+void stop_flist_forward()
+{
+ flist_forward_from = -1;
+ io_flush(FULL_FLUSH);
+}
+
+/**
+ * Continue trying to read len bytes - don't return until len has been
+ * read.
+ **/
+static void read_loop(int fd, char *buf, size_t len)
+{
+ while (len) {
+ int n = read_timeout(fd, buf, len);
+
+ buf += n;
+ len -= n;
+ }
+}
+
+/**
+ * Read from the file descriptor handling multiplexing - return number
+ * of bytes read.
+ *
+ * Never returns <= 0.
+ */
+static int readfd_unbuffered(int fd, char *buf, size_t len)
+{
+ size_t msg_bytes;
+ int tag, cnt = 0;
+ char line[BIGPATHBUFLEN];
+
+ if (!iobuf_in || fd != iobuf_f_in)
+ return read_timeout(fd, buf, len);
+
+ if (!io_multiplexing_in && iobuf_in_remaining == 0) {
+ iobuf_in_remaining = read_timeout(fd, iobuf_in, iobuf_in_siz);
+ iobuf_in_ndx = 0;
+ }
+
+ while (cnt == 0) {
+ if (iobuf_in_remaining) {
+ len = MIN(len, iobuf_in_remaining);
+ memcpy(buf, iobuf_in + iobuf_in_ndx, len);
+ iobuf_in_ndx += len;
+ iobuf_in_remaining -= len;
+ cnt = len;
+ break;
+ }
+
+ read_loop(fd, line, 4);
+ tag = IVAL(line, 0);
+
+ msg_bytes = tag & 0xFFFFFF;
+ tag = (tag >> 24) - MPLEX_BASE;
+
+ switch (tag) {
+ case MSG_DATA:
+ if (msg_bytes > iobuf_in_siz) {
+ if (!(iobuf_in = realloc_array(iobuf_in, char,
+ msg_bytes)))
+ out_of_memory("readfd_unbuffered");
+ iobuf_in_siz = msg_bytes;
+ }
+ read_loop(fd, iobuf_in, msg_bytes);
+ iobuf_in_remaining = msg_bytes;
+ iobuf_in_ndx = 0;
+ break;
+ case MSG_NOOP:
+ if (am_sender)
+ maybe_send_keepalive();
+ break;
+ case MSG_IO_ERROR:
+ if (msg_bytes != 4)
+ goto invalid_msg;
+ read_loop(fd, line, msg_bytes);
+ io_error |= IVAL(line, 0);
+ break;
+ case MSG_DELETED:
+ if (msg_bytes >= sizeof line)
+ goto overflow;
+ read_loop(fd, line, msg_bytes);
+ /* A directory name was sent with the trailing null */
+ if (msg_bytes > 0 && !line[msg_bytes-1])
+ log_delete(line, S_IFDIR);
+ else {
+ line[msg_bytes] = '\0';
+ log_delete(line, S_IFREG);
+ }
+ break;
+ case MSG_SUCCESS:
+ if (msg_bytes != 4) {
+ invalid_msg:
+ rprintf(FERROR, "invalid multi-message %d:%ld [%s]\n",
+ tag, (long)msg_bytes, who_am_i());
+ exit_cleanup(RERR_STREAMIO);
+ }
+ read_loop(fd, line, msg_bytes);
+ successful_send(IVAL(line, 0));
+ break;
+ case MSG_NO_SEND:
+ if (msg_bytes != 4)
+ goto invalid_msg;
+ read_loop(fd, line, msg_bytes);
+ send_msg_int(MSG_NO_SEND, IVAL(line, 0));
+ break;
+ case MSG_INFO:
+ case MSG_ERROR:
+ if (msg_bytes >= sizeof line) {
+ overflow:
+ rprintf(FERROR,
+ "multiplexing overflow %d:%ld [%s]\n",
+ tag, (long)msg_bytes, who_am_i());
+ exit_cleanup(RERR_STREAMIO);