+ LOG(log_debug, logtype_dsi, "from_buf(read: %u, unread:%u , space left: %u): returning %u",
+ dsi->start - dsi->buffer, dsi->eof - dsi->start, dsi->end - dsi->eof, nbe);
+
+ return nbe;
+}
+
+/*
+ * Get bytes from buffer dsi->buffer or read from socket
+ *
+ * 1. Check if there are bytes in the the dsi->buffer buffer.
+ * 2. Return bytes from (1) if yes.
+ * Note: this may return fewer bytes then requested in count !!
+ * 3. If the buffer was empty, read from the socket.
+ */
+static ssize_t buf_read(DSI *dsi, u_int8_t *buf, size_t count)
+{
+ ssize_t len;
+
+ LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes)", count);
+
+ if (!count)
+ return 0;
+
+ len = from_buf(dsi, buf, count); /* 1. */
+ if (len)
+ return len; /* 2. */
+
+ len = readt(dsi->socket, buf, count, 0, 1); /* 3. */
+
+ LOG(log_maxdebug, logtype_dsi, "buf_read(%u bytes): got: %d", count, len);
+
+ return len;
+}
+
+/*
+ * Get "length" bytes from buffer and/or socket. In order to avoid frequent small reads
+ * this tries to read larger chunks (8192 bytes) into a buffer.
+ */
+static size_t dsi_buffered_stream_read(DSI *dsi, u_int8_t *data, const size_t length)
+{
+ size_t len;
+ size_t buflen;
+
+ LOG(log_maxdebug, logtype_dsi, "dsi_buffered_stream_read: %u bytes", length);
+
+ len = from_buf(dsi, data, length); /* read from buffer dsi->buffer */
+ dsi->read_count += len;
+ if (len == length) { /* got enough bytes from there ? */
+ return len; /* yes */
+ }
+
+ /* fill the buffer with 8192 bytes or until buffer is full */
+ buflen = min(8192, dsi->end - dsi->eof);
+ if (buflen > 0) {
+ ssize_t ret;
+ ret = read(dsi->socket, dsi->eof, buflen);
+ if (ret > 0)
+ dsi->eof += ret;
+ }
+
+ /* now get the remaining data */
+ if ((buflen = dsi_stream_read(dsi, data + len, length - len)) != length - len)
+ return 0;
+ len += buflen;
+
+ return len;
+}
+
+/* ---------------------------------------
+*/
+static void block_sig(DSI *dsi)
+{
+ dsi->in_write++;
+}
+
+/* ---------------------------------------
+*/
+static void unblock_sig(DSI *dsi)
+{
+ dsi->in_write--;
+}
+
+/*********************************************************************************
+ * Public functions
+ *********************************************************************************/
+
+/*!
+ * Communication error with the client, enter disconnected state
+ *
+ * 1. close the socket
+ * 2. set the DSI_DISCONNECTED flag
+ *
+ * @returns 0 if successfully entered disconnected state
+ * -1 if ppid is 1 which means afpd master died
+ * or euid == 0 ie where still running as root (unauthenticated session)
+ */
+int dsi_disconnect(DSI *dsi)
+{
+ dsi->proto_close(dsi); /* 1 */
+ dsi->flags |= DSI_DISCONNECTED; /* 2 */
+ if (geteuid() == 0)
+ return -1;