Beispiel #1
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;
	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;
}