/* struct smbd_smb2_read_state destructor. Send the SMB2_READ data. */ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state) { struct lock_struct lock; uint32_t in_length = state->in_length; uint64_t in_offset = state->in_offset; files_struct *fsp = state->fsp; ssize_t nread; nread = SMB_VFS_SENDFILE(fsp->conn->sconn->sock, fsp, NULL, in_offset, in_length); DEBUG(10,("smb2_sendfile_send_data: SMB_VFS_SENDFILE returned %d on file %s\n", (int)nread, fsp_str_dbg(fsp) )); if (nread == -1) { if (errno == ENOSYS || errno == EINTR) { /* * Special hack for broken systems with no working * sendfile. Fake this up by doing read/write calls. */ set_use_sendfile(SNUM(fsp->conn), false); nread = fake_sendfile(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"); } 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"); } else if (nread == 0) { /* * Some sendfile implementations return 0 to indicate * that there was a short read, but nothing was * actually written to the socket. In this case, * fallback to the normal read path so the header gets * the correct byte count. */ DEBUG(3, ("send_file_readX: sendfile sent zero bytes " "falling back to the normal read: %s\n", fsp_str_dbg(fsp))); nread = fake_sendfile(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"); } } out: if (nread < in_length) { sendfile_short_send(fsp, nread, 0, in_length); } init_strict_lock_struct(fsp, state->in_file_id_volatile, in_offset, in_length, READ_LOCK, &lock); SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &lock); return 0; }
/* struct smbd_smb2_read_state destructor. Send the SMB2_READ data. */ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state) { struct lock_struct lock; uint32_t in_length = state->in_length; 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(xconn->transport.sock, fsp, hdr, in_offset, in_length); DEBUG(10,("smb2_sendfile_send_data: SMB_VFS_SENDFILE returned %d on file %s\n", (int)nread, 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. */ if (errno == ENOSYS) { goto normal_read; } if (errno == EINTR) { /* * Special hack for broken Linux with no working sendfile. If we * return EINTR we sent the header but not the rest of the data. * Fake this up by doing read/write calls. */ set_use_sendfile(SNUM(fsp->conn), false); nread = fake_sendfile(xconn, fsp, in_offset, in_length); if (nread == -1) { 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) 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 * that there was a short read, but nothing was * actually written to the socket. In this case, * fallback to the normal read path so the header gets * the correct byte count. */ DEBUG(3, ("send_file_readX: sendfile sent zero bytes " "falling back to the normal read: %s\n", fsp_str_dbg(fsp))); goto normal_read; } /* * We got a short read */ goto out; normal_read: /* Send out the header. */ ret = write_data(xconn->transport.sock, (const char *)hdr->data, hdr->length); if (ret != hdr->length) { saved_errno = errno; DEBUG(0,("smb2_sendfile_send_data: write_data 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; } nread = fake_sendfile(xconn, fsp, in_offset, in_length); if (nread == -1) { 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) { 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, fsp->op->global->open_persistent_id, in_offset, in_length, READ_LOCK, &lock); SMB_VFS_STRICT_UNLOCK(fsp->conn, fsp, &lock); *pstatus = NT_STATUS_OK; return 0; }