lib: Split out write_data[_iov]
[obnox/samba/samba-obnox.git] / source3 / smbd / smb2_read.c
index 603c4a0c2784e6b1748d70f2758fbb9e1b1259b6..4e974a2eee1c5ac0f258338a6068e552c8f36935 100644 (file)
@@ -26,6 +26,7 @@
 #include "libcli/security/security.h"
 #include "../lib/util/tevent_ntstatus.h"
 #include "rpc_server/srv_pipe_hnd.h"
+#include "lib/sys_rw_data.h"
 
 static struct tevent_req *smbd_smb2_read_send(TALLOC_CTX *mem_ctx,
                                              struct tevent_context *ev,
@@ -43,6 +44,7 @@ static NTSTATUS smbd_smb2_read_recv(struct tevent_req *req,
 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
 NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req)
 {
+       struct smbXsrv_connection *xconn = req->xconn;
        NTSTATUS status;
        const uint8_t *inbody;
        uint32_t in_length;
@@ -68,10 +70,10 @@ NTSTATUS smbd_smb2_request_process_read(struct smbd_smb2_request *req)
        in_remaining_bytes      = IVAL(inbody, 0x28);
 
        /* check the max read size */
-       if (in_length > req->sconn->smb2.max_read) {
+       if (in_length > xconn->smb2.server.max_read) {
                DEBUG(2,("smbd_smb2_request_process_read: "
                         "client ignored max read: %s: 0x%08X: 0x%08X\n",
-                       __location__, in_length, req->sconn->smb2.max_read));
+                       __location__, in_length, xconn->smb2.server.max_read));
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
        }
 
@@ -119,7 +121,7 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq)
        if (!NT_STATUS_IS_OK(status)) {
                error = smbd_smb2_request_error(req, status);
                if (!NT_STATUS_IS_OK(error)) {
-                       smbd_server_connection_terminate(req->sconn,
+                       smbd_server_connection_terminate(req->xconn,
                                                         nt_errstr(error));
                        return;
                }
@@ -132,7 +134,7 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq)
        if (outbody.data == NULL) {
                error = smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
                if (!NT_STATUS_IS_OK(error)) {
-                       smbd_server_connection_terminate(req->sconn,
+                       smbd_server_connection_terminate(req->xconn,
                                                         nt_errstr(error));
                        return;
                }
@@ -153,7 +155,7 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq)
 
        error = smbd_smb2_request_done(req, outbody, &outdyn);
        if (!NT_STATUS_IS_OK(error)) {
-               smbd_server_connection_terminate(req->sconn,
+               smbd_server_connection_terminate(req->xconn,
                                                 nt_errstr(error));
                return;
        }
@@ -185,10 +187,13 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state)
        uint64_t in_offset = state->in_offset;
        files_struct *fsp = state->fsp;
        const DATA_BLOB *hdr = state->smb2req->queue_entry.sendfile_header;
+       NTSTATUS *pstatus = state->smb2req->queue_entry.sendfile_status;
+       struct smbXsrv_connection *xconn = state->smb2req->xconn;
        ssize_t nread;
        ssize_t ret;
+       int saved_errno;
 
-       nread = SMB_VFS_SENDFILE(fsp->conn->sconn->sock,
+       nread = SMB_VFS_SENDFILE(xconn->transport.sock,
                                 fsp,
                                 hdr,
                                 in_offset,
@@ -198,6 +203,8 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state)
                fsp_str_dbg(fsp) ));
 
        if (nread == -1) {
+               saved_errno = errno;
+
                /*
                 * Returning ENOSYS means no data at all was sent.
                   Do this as a normal read. */
@@ -212,24 +219,26 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state)
                         * Fake this up by doing read/write calls.
                         */
                        set_use_sendfile(SNUM(fsp->conn), false);
-                       nread = fake_sendfile(fsp, in_offset, in_length);
+                       nread = fake_sendfile(xconn, fsp, in_offset, in_length);
                        if (nread == -1) {
-                               DEBUG(0,("smb2_sendfile_send_data: "
-                                       "fake_sendfile failed for "
-                                       "file %s (%s).\n",
-                                       fsp_str_dbg(fsp),
-                                       strerror(errno)));
-                               exit_server_cleanly("smb2_sendfile_send_data: "
-                                       "fake_sendfile failed");
+                               saved_errno = errno;
+                               DEBUG(0,("smb2_sendfile_send_data: fake_sendfile "
+                                        "failed for file %s (%s) for client %s. "
+                                        "Terminating\n",
+                                        fsp_str_dbg(fsp), strerror(saved_errno),
+                                        smbXsrv_connection_dbg(xconn)));
+                               *pstatus = map_nt_error_from_unix_common(saved_errno);
+                               return 0;
                        }
                        goto out;
                }
 
                DEBUG(0,("smb2_sendfile_send_data: sendfile failed for file "
-                       "%s (%s). Terminating\n",
-                       fsp_str_dbg(fsp),
-                       strerror(errno)));
-               exit_server_cleanly("smb2_sendfile_send_data: sendfile failed");
+                        "%s (%s) for client %s. Terminating\n",
+                        fsp_str_dbg(fsp), strerror(saved_errno),
+                        smbXsrv_connection_dbg(xconn)));
+               *pstatus = map_nt_error_from_unix_common(saved_errno);
+               return 0;
        } else if (nread == 0) {
                /*
                 * Some sendfile implementations return 0 to indicate
@@ -251,40 +260,45 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state)
 
 normal_read:
        /* Send out the header. */
-       ret = write_data(fsp->conn->sconn->sock,
+       ret = write_data(xconn->transport.sock,
                         (const char *)hdr->data, hdr->length);
        if (ret != hdr->length) {
-               char addr[INET6_ADDRSTRLEN];
-               /*
-                * Try and give an error message saying what
-                * client failed.
-                */
-               DEBUG(0, ("smb2_sendfile_send_data: write_data failed "
-                         "for client %s. Error %s\n",
-                         get_peer_addr(fsp->conn->sconn->sock, addr,
-                                       sizeof(addr)),
-                         strerror(errno)));
-
+               saved_errno = errno;
                DEBUG(0,("smb2_sendfile_send_data: write_data failed for file "
-                        "%s (%s). Terminating\n", fsp_str_dbg(fsp),
-                        strerror(errno)));
-               exit_server_cleanly("smb2_sendfile_send_data: write_data failed");
+                        "%s (%s) for client %s. Terminating\n",
+                        fsp_str_dbg(fsp), strerror(saved_errno),
+                        smbXsrv_connection_dbg(xconn)));
+               *pstatus = map_nt_error_from_unix_common(saved_errno);
+               return 0;
        }
-       nread = fake_sendfile(fsp, in_offset, in_length);
+       nread = fake_sendfile(xconn, fsp, in_offset, in_length);
        if (nread == -1) {
-               DEBUG(0,("smb2_sendfile_send_data: "
-                       "fake_sendfile failed for file "
-                       "%s (%s). Terminating\n",
-                       fsp_str_dbg(fsp),
-                       strerror(errno)));
-               exit_server_cleanly("smb2_sendfile_send_data: "
-                       "fake_sendfile failed");
+               saved_errno = errno;
+               DEBUG(0,("smb2_sendfile_send_data: fake_sendfile "
+                        "failed for file %s (%s) for client %s. "
+                        "Terminating\n",
+                        fsp_str_dbg(fsp), strerror(saved_errno),
+                        smbXsrv_connection_dbg(xconn)));
+               *pstatus = map_nt_error_from_unix_common(saved_errno);
+               return 0;
        }
 
   out:
 
        if (nread < in_length) {
-               sendfile_short_send(fsp, nread, hdr->length, in_length);
+               ret = sendfile_short_send(xconn, fsp, nread,
+                                         hdr->length, in_length);
+               if (ret == -1) {
+                       saved_errno = errno;
+                       DEBUG(0,("%s: sendfile_short_send "
+                                "failed for file %s (%s) for client %s. "
+                                "Terminating\n",
+                                __func__,
+                                fsp_str_dbg(fsp), strerror(saved_errno),
+                                smbXsrv_connection_dbg(xconn)));
+                       *pstatus = map_nt_error_from_unix_common(saved_errno);
+                       return 0;
+               }
        }
 
        init_strict_lock_struct(fsp,
@@ -295,6 +309,8 @@ normal_read:
                                &lock);
 
        SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &lock);
+
+       *pstatus = NT_STATUS_OK;
        return 0;
 }