diff options
Diffstat (limited to 'source3/smbd')
-rw-r--r-- | source3/smbd/blocking.c | 195 | ||||
-rw-r--r-- | source3/smbd/open.c | 22 | ||||
-rw-r--r-- | source3/smbd/pysmbd.c | 58 | ||||
-rw-r--r-- | source3/smbd/server.c | 16 | ||||
-rw-r--r-- | source3/smbd/smb2_create.c | 9 | ||||
-rw-r--r-- | source3/smbd/smb2_lock.c | 69 | ||||
-rw-r--r-- | source3/smbd/smb2_read.c | 69 |
7 files changed, 274 insertions, 164 deletions
diff --git a/source3/smbd/blocking.c b/source3/smbd/blocking.c index 5f6dda318e6..d5b8347469a 100644 --- a/source3/smbd/blocking.c +++ b/source3/smbd/blocking.c @@ -430,6 +430,25 @@ static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS } /**************************************************************************** + Utility function that returns true if a lock timed out. +*****************************************************************************/ + +static bool lock_timed_out(const struct blocking_lock_record *blr) +{ + struct timeval tv_curr; + + if (timeval_is_zero(&blr->expire_time)) { + return false; /* Never times out. */ + } + + tv_curr = timeval_current(); + if (timeval_compare(&blr->expire_time, &tv_curr) <= 0) { + return true; + } + return false; +} + +/**************************************************************************** Attempt to finish off getting all pending blocking locks for a lockingX call. Returns True if we want to be removed from the list. *****************************************************************************/ @@ -440,11 +459,10 @@ static bool process_lockingX(struct blocking_lock_record *blr) files_struct *fsp = blr->fsp; uint16 num_ulocks = SVAL(blr->req->vwv+6, 0); uint16 num_locks = SVAL(blr->req->vwv+7, 0); - uint64_t count = (uint64_t)0, offset = (uint64_t)0; - uint64_t smblctx; bool large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES); uint8_t *data; NTSTATUS status = NT_STATUS_OK; + bool lock_timeout = lock_timed_out(blr); data = discard_const_p(uint8_t, blr->req->buf) + ((large_file_format ? 20 : 10)*num_ulocks); @@ -458,9 +476,14 @@ static bool process_lockingX(struct blocking_lock_record *blr) struct byte_range_lock *br_lck = NULL; bool err; - smblctx = get_lock_pid( data, blr->lock_num, large_file_format); - count = get_lock_count( data, blr->lock_num, large_file_format); - offset = get_lock_offset( data, blr->lock_num, large_file_format, &err); + /* + * Ensure the blr record gets updated with + * any lock we might end up blocked on. + */ + + blr->smblctx = get_lock_pid( data, blr->lock_num, large_file_format); + blr->count = get_lock_count( data, blr->lock_num, large_file_format); + blr->offset = get_lock_offset( data, blr->lock_num, large_file_format, &err); /* * We know err cannot be set as if it was the lock @@ -469,9 +492,9 @@ static bool process_lockingX(struct blocking_lock_record *blr) errno = 0; br_lck = do_lock(fsp->conn->sconn->msg_ctx, fsp, - smblctx, - count, - offset, + blr->smblctx, + blr->count, + blr->offset, ((locktype & LOCKING_ANDX_SHARED_LOCK) ? READ_LOCK : WRITE_LOCK), WINDOWS_LOCK, @@ -480,6 +503,34 @@ static bool process_lockingX(struct blocking_lock_record *blr) &blr->blocking_smblctx, blr); + if (ERROR_WAS_LOCK_DENIED(status) && !lock_timeout) { + /* + * If we didn't timeout, but still need to wait, + * re-add the pending lock entry whilst holding + * the brlock db lock. + */ + NTSTATUS status1 = + brl_lock(blr->fsp->conn->sconn->msg_ctx, + br_lck, + blr->smblctx, + messaging_server_id( + blr->fsp->conn->sconn->msg_ctx), + blr->offset, + blr->count, + blr->lock_type == READ_LOCK ? + PENDING_READ_LOCK : + PENDING_WRITE_LOCK, + blr->lock_flav, + true, /* Blocking lock. */ + NULL, + blr); + + if (!NT_STATUS_IS_OK(status1)) { + DEBUG(0,("failed to add PENDING_LOCK " + "record.\n")); + } + } + TALLOC_FREE(br_lck); if (NT_STATUS_IS_ERR(status)) { @@ -500,8 +551,7 @@ static bool process_lockingX(struct blocking_lock_record *blr) return True; } - if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) && - !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) { + if (!ERROR_WAS_LOCK_DENIED(status)) { /* * We have other than a "can't get lock" * error. Free any locks we had and return an error. @@ -512,6 +562,14 @@ static bool process_lockingX(struct blocking_lock_record *blr) } /* + * Return an error to the client if we timed out. + */ + if (lock_timeout) { + blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); + return true; + } + + /* * Still can't get all the locks - keep waiting. */ @@ -532,6 +590,8 @@ static bool process_trans2(struct blocking_lock_record *blr) { char params[2]; NTSTATUS status; + bool lock_timeout = lock_timed_out(blr); + struct byte_range_lock *br_lck = do_lock( blr->fsp->conn->sconn->msg_ctx, blr->fsp, @@ -544,10 +604,46 @@ static bool process_trans2(struct blocking_lock_record *blr) &status, &blr->blocking_smblctx, blr); + if (ERROR_WAS_LOCK_DENIED(status) && !lock_timeout) { + /* + * If we didn't timeout, but still need to wait, + * re-add the pending lock entry whilst holding + * the brlock db lock. + */ + NTSTATUS status1 = + brl_lock(blr->fsp->conn->sconn->msg_ctx, + br_lck, + blr->smblctx, + messaging_server_id( + blr->fsp->conn->sconn->msg_ctx), + blr->offset, + blr->count, + blr->lock_type == READ_LOCK ? + PENDING_READ_LOCK : + PENDING_WRITE_LOCK, + blr->lock_flav, + true, /* Blocking lock. */ + NULL, + blr); + + if (!NT_STATUS_IS_OK(status1)) { + DEBUG(0,("failed to add PENDING_LOCK record.\n")); + } + } + TALLOC_FREE(br_lck); if (!NT_STATUS_IS_OK(status)) { if (ERROR_WAS_LOCK_DENIED(status)) { + if (lock_timeout) { + /* + * Return an error if we timed out + * and return true to get dequeued. + */ + blocking_lock_reply_error(blr, + NT_STATUS_FILE_LOCK_CONFLICT); + return true; + } /* Still can't get the lock, just keep waiting. */ return False; } @@ -735,11 +831,10 @@ static void received_unlock_msg(struct messaging_context *msg, void process_blocking_lock_queue(struct smbd_server_connection *sconn) { - struct timeval tv_curr = timeval_current(); struct blocking_lock_record *blr, *next = NULL; if (sconn->using_smb2) { - process_blocking_lock_queue_smb2(sconn, tv_curr); + process_blocking_lock_queue_smb2(sconn, timeval_current()); return; } @@ -748,6 +843,7 @@ void process_blocking_lock_queue(struct smbd_server_connection *sconn) */ for (blr = sconn->smb1.locks.blocking_lock_queue; blr; blr = next) { + struct byte_range_lock *br_lck = NULL; next = blr->next; @@ -767,65 +863,34 @@ void process_blocking_lock_queue(struct smbd_server_connection *sconn) SVAL(blr->req->inbuf,smb_flg), false); - if(blocking_lock_record_process(blr)) { - struct byte_range_lock *br_lck = brl_get_locks( - talloc_tos(), blr->fsp); - - DEBUG(10, ("BLR_process returned true: cancelling and " - "removing lock. BLR = %p\n", blr)); - - if (br_lck) { - brl_lock_cancel(br_lck, - blr->smblctx, - messaging_server_id(sconn->msg_ctx), - blr->offset, - blr->count, - blr->lock_flav, - blr); - TALLOC_FREE(br_lck); - } - - DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr); - TALLOC_FREE(blr); - continue; - } - /* - * We couldn't get the locks for this record on the list. - * If the time has expired, return a lock error. + * Remove the pending lock we're waiting on. + * If we need to keep waiting blocking_lock_record_process() + * will re-add it. */ - if (!timeval_is_zero(&blr->expire_time) && timeval_compare(&blr->expire_time, &tv_curr) <= 0) { - struct byte_range_lock *br_lck = brl_get_locks( - talloc_tos(), blr->fsp); - - DEBUG(10, ("Lock timed out! BLR = %p\n", blr)); - - /* - * Lock expired - throw away all previously - * obtained locks and return lock error. - */ + br_lck = brl_get_locks(talloc_tos(), blr->fsp); + if (br_lck) { + brl_lock_cancel(br_lck, + blr->smblctx, + messaging_server_id(sconn->msg_ctx), + blr->offset, + blr->count, + blr->lock_flav, + blr); + } + TALLOC_FREE(br_lck); - if (br_lck) { - DEBUG(5,("process_blocking_lock_queue: " - "pending lock for %s, file %s " - "timed out.\n", fsp_fnum_dbg(blr->fsp), - fsp_str_dbg(blr->fsp))); + if(!blocking_lock_record_process(blr)) { + DEBUG(10, ("still waiting for lock. BLR = %p\n", blr)); + continue; + } - brl_lock_cancel(br_lck, - blr->smblctx, - messaging_server_id(sconn->msg_ctx), - blr->offset, - blr->count, - blr->lock_flav, - blr); - TALLOC_FREE(br_lck); - } + DEBUG(10, ("BLR_process returned true: removing BLR = %p\n", + blr)); - blocking_lock_reply_error(blr,NT_STATUS_FILE_LOCK_CONFLICT); - DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr); - TALLOC_FREE(blr); - } + DLIST_REMOVE(sconn->smb1.locks.blocking_lock_queue, blr); + TALLOC_FREE(blr); } recalc_brl_timeout(sconn); diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 5f7bff9a8d3..16d43077c5a 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -839,8 +839,11 @@ static NTSTATUS open_file(files_struct *fsp, } } - /* Actually do the open */ - status = fd_open_atomic(conn, fsp, local_flags, + /* + * Actually do the open - if O_TRUNC is needed handle it + * below under the share mode lock. + */ + status = fd_open_atomic(conn, fsp, local_flags & ~O_TRUNC, unx_mode, p_file_created); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " @@ -2646,6 +2649,21 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, return status; } + /* Should we atomically (to the client at least) truncate ? */ + if ((!new_file_created) && + (flags2 & O_TRUNC) && + (!S_ISFIFO(fsp->fsp_name->st.st_ex_mode))) { + int ret; + + ret = vfs_set_filelen(fsp, 0); + if (ret != 0) { + status = map_nt_error_from_unix(errno); + TALLOC_FREE(lck); + fd_close(fsp); + return status; + } + } + grant_fsp_oplock_type(fsp, oplock_request, got_level2_oplock, diff --git a/source3/smbd/pysmbd.c b/source3/smbd/pysmbd.c index 683c48ccf75..df0f43096e0 100644 --- a/source3/smbd/pysmbd.c +++ b/source3/smbd/pysmbd.c @@ -76,11 +76,10 @@ static connection_struct *get_conn(TALLOC_CTX *mem_ctx, const char *service) return conn; } -static NTSTATUS set_sys_acl_conn(const char *fname, +static int set_sys_acl_conn(const char *fname, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl, connection_struct *conn) { - NTSTATUS status = NT_STATUS_OK; int ret; mode_t saved_umask; @@ -91,16 +90,11 @@ static NTSTATUS set_sys_acl_conn(const char *fname, saved_umask = umask(0); ret = SMB_VFS_SYS_ACL_SET_FILE( conn, fname, acltype, theacl); - if (ret != 0) { - status = map_nt_error_from_unix_common(ret); - DEBUG(0,("set_sys_acl_conn: SMB_VFS_SYS_ACL_SET_FILE " - "returned zero.\n")); - } umask(saved_umask); TALLOC_FREE(frame); - return status; + return ret; } static NTSTATUS set_nt_acl_conn(const char *fname, @@ -319,8 +313,8 @@ static SMB_ACL_T make_simple_acl(gid_t gid, mode_t chmod_mode) static PyObject *py_smbd_set_simple_acl(PyObject *self, PyObject *args, PyObject *kwargs) { const char * const kwnames[] = { "fname", "mode", "gid", "service", NULL }; - NTSTATUS status; char *fname, *service = NULL; + int ret; int mode, gid = -1; SMB_ACL_T acl; TALLOC_CTX *frame; @@ -340,12 +334,16 @@ static PyObject *py_smbd_set_simple_acl(PyObject *self, PyObject *args, PyObject return NULL; } - status = set_sys_acl_conn(fname, SMB_ACL_TYPE_ACCESS, acl, conn); + ret = set_sys_acl_conn(fname, SMB_ACL_TYPE_ACCESS, acl, conn); TALLOC_FREE(acl); - TALLOC_FREE(frame); + if (ret != 0) { + TALLOC_FREE(frame); + errno = ret; + return PyErr_SetFromErrno(PyExc_OSError); + } - PyErr_NTSTATUS_IS_ERR_RAISE(status); + TALLOC_FREE(frame); Py_RETURN_NONE; } @@ -357,7 +355,6 @@ static PyObject *py_smbd_chown(PyObject *self, PyObject *args, PyObject *kwargs) { const char * const kwnames[] = { "fname", "uid", "gid", "service", NULL }; connection_struct *conn; - NTSTATUS status = NT_STATUS_OK; int ret; char *fname, *service = NULL; @@ -383,27 +380,26 @@ static PyObject *py_smbd_chown(PyObject *self, PyObject *args, PyObject *kwargs) ret = SMB_VFS_CHOWN( conn, fname, uid, gid); if (ret != 0) { - status = map_nt_error_from_unix_common(errno); - DEBUG(0,("chown returned failure: %s\n", strerror(errno))); + umask(saved_umask); + TALLOC_FREE(frame); + errno = ret; + return PyErr_SetFromErrno(PyExc_OSError); } umask(saved_umask); TALLOC_FREE(frame); - PyErr_NTSTATUS_IS_ERR_RAISE(status); - Py_RETURN_NONE; } /* - chown a file + unlink a file */ static PyObject *py_smbd_unlink(PyObject *self, PyObject *args, PyObject *kwargs) { const char * const kwnames[] = { "fname", "service", NULL }; connection_struct *conn; - NTSTATUS status = NT_STATUS_OK; int ret; struct smb_filename *smb_fname = NULL; char *fname, *service = NULL; @@ -427,19 +423,18 @@ static PyObject *py_smbd_unlink(PyObject *self, PyObject *args, PyObject *kwargs smb_fname = synthetic_smb_fname_split(frame, fname, NULL); if (smb_fname == NULL) { TALLOC_FREE(frame); - PyErr_NTSTATUS_IS_ERR_RAISE(NT_STATUS_NO_MEMORY); + return PyErr_NoMemory(); } ret = SMB_VFS_UNLINK(conn, smb_fname); if (ret != 0) { - status = map_nt_error_from_unix_common(errno); - DEBUG(0,("unlink returned failure: %s\n", strerror(errno))); + TALLOC_FREE(frame); + errno = ret; + return PyErr_SetFromErrno(PyExc_OSError); } TALLOC_FREE(frame); - PyErr_NTSTATUS_IS_ERR_RAISE(status); - Py_RETURN_NONE; } @@ -541,7 +536,7 @@ static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args, PyObject *k { const char * const kwnames[] = { "fname", "acl_type", "acl", "service", NULL }; TALLOC_CTX *frame = talloc_stackframe(); - NTSTATUS status; + int ret; char *fname, *service = NULL; PyObject *py_acl; struct smb_acl_t *acl; @@ -568,8 +563,12 @@ static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args, PyObject *k acl = pytalloc_get_type(py_acl, struct smb_acl_t); - status = set_sys_acl_conn(fname, acl_type, acl, conn); - PyErr_NTSTATUS_IS_ERR_RAISE(status); + ret = set_sys_acl_conn(fname, acl_type, acl, conn); + if (ret != 0) { + TALLOC_FREE(frame); + errno = ret; + return PyErr_SetFromErrno(PyExc_OSError); + } TALLOC_FREE(frame); Py_RETURN_NONE; @@ -588,7 +587,6 @@ static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args, PyObject *k TALLOC_CTX *frame = talloc_stackframe(); TALLOC_CTX *tmp_ctx = talloc_new(NULL); connection_struct *conn; - NTSTATUS status = NT_STATUS_OK; char *service = NULL; if (!tmp_ctx) { PyErr_NoMemory(); @@ -614,9 +612,7 @@ static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args, PyObject *k if (!acl) { TALLOC_FREE(frame); TALLOC_FREE(tmp_ctx); - status = map_nt_error_from_unix_common(errno); - DEBUG(0,("sys_acl_get_file returned NULL: %s\n", strerror(errno))); - PyErr_NTSTATUS_IS_ERR_RAISE(status); + return PyErr_SetFromErrno(PyExc_OSError); } py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl); diff --git a/source3/smbd/server.c b/source3/smbd/server.c index d539c5974ed..9e249d1a6b9 100644 --- a/source3/smbd/server.c +++ b/source3/smbd/server.c @@ -838,12 +838,16 @@ static bool open_sockets_smbd(struct smbd_parent_context *parent, continue; } - if (!smbd_open_one_socket(parent, - ev_ctx, - &ss, - port)) { - return false; - } + /* + * If we fail to open any sockets + * in this loop the parent-sockets == NULL + * case below will prevent us from starting. + */ + + (void)smbd_open_one_socket(parent, + ev_ctx, + &ss, + port); } } } diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c index 2c35559d215..e6f087cd448 100644 --- a/source3/smbd/smb2_create.c +++ b/source3/smbd/smb2_create.c @@ -1272,7 +1272,14 @@ bool schedule_deferred_open_message_smb2( DEBUG(10,("schedule_deferred_open_message_smb2: " "can't find mid %llu\n", (unsigned long long)mid )); - return false; + + /* + * Bug 10593: We have to ignore this as an error because the + * request might have been cancelled. The real fix is to + * discard the defer_open dbwrap_watcher at cancel + * time. Working on that.... :-) + */ + return true; } if (!smb2req->subreq) { return false; diff --git a/source3/smbd/smb2_lock.c b/source3/smbd/smb2_lock.c index 2ee7afa5d69..52698f3c4b9 100644 --- a/source3/smbd/smb2_lock.c +++ b/source3/smbd/smb2_lock.c @@ -664,19 +664,6 @@ static void remove_pending_lock(struct smbd_smb2_lock_state *state, blr); TALLOC_FREE(br_lck); } - - /* Remove the locks we already got. */ - - for(i = blr->lock_num - 1; i >= 0; i--) { - struct smbd_lock_element *e = &state->locks[i]; - - do_unlock(blr->fsp->conn->sconn->msg_ctx, - blr->fsp, - e->smblctx, - e->count, - e->offset, - WINDOWS_LOCK); - } } /**************************************************************** @@ -690,6 +677,8 @@ static void reprocess_blocked_smb2_lock(struct smbd_smb2_request *smb2req, NTSTATUS status = NT_STATUS_UNSUCCESSFUL; struct blocking_lock_record *blr = NULL; struct smbd_smb2_lock_state *state = NULL; + struct byte_range_lock *br_lck = NULL; + struct smbd_lock_element *e = NULL; files_struct *fsp = NULL; if (!smb2req->subreq) { @@ -703,34 +692,30 @@ static void reprocess_blocked_smb2_lock(struct smbd_smb2_request *smb2req, blr = state->blr; fsp = blr->fsp; - /* Try and finish off getting all the outstanding locks. */ - - for (; blr->lock_num < state->lock_count; blr->lock_num++) { - struct byte_range_lock *br_lck = NULL; - struct smbd_lock_element *e = &state->locks[blr->lock_num]; - - br_lck = do_lock(fsp->conn->sconn->msg_ctx, - fsp, - e->smblctx, - e->count, - e->offset, - e->brltype, - WINDOWS_LOCK, - true, - &status, - &blr->blocking_smblctx, - blr); + /* We can only have one blocked lock in SMB2. */ + SMB_ASSERT(state->lock_count == 1); + SMB_ASSERT(blr->lock_num == 0); - TALLOC_FREE(br_lck); + /* Try and get the outstanding lock. */ + e = &state->locks[blr->lock_num]; - if (NT_STATUS_IS_ERR(status)) { - break; - } - } + br_lck = do_lock(fsp->conn->sconn->msg_ctx, + fsp, + e->smblctx, + e->count, + e->offset, + e->brltype, + WINDOWS_LOCK, + true, + &status, + &blr->blocking_smblctx, + blr); + + TALLOC_FREE(br_lck); - if(blr->lock_num == state->lock_count) { + if (NT_STATUS_IS_OK(status)) { /* - * Success - we got all the locks. + * Success - we got the lock. */ DEBUG(3,("reprocess_blocked_smb2_lock SUCCESS file = %s, " @@ -739,6 +724,7 @@ static void reprocess_blocked_smb2_lock(struct smbd_smb2_request *smb2req, fsp_fnum_dbg(fsp), (int)state->lock_count)); + remove_pending_lock(state, blr); tevent_req_done(smb2req->subreq); return; } @@ -755,7 +741,7 @@ static void reprocess_blocked_smb2_lock(struct smbd_smb2_request *smb2req, } /* - * We couldn't get the locks for this record on the list. + * We couldn't get the lock for this record. * If the time has expired, return a lock error. */ @@ -767,18 +753,15 @@ static void reprocess_blocked_smb2_lock(struct smbd_smb2_request *smb2req, } /* - * Still can't get all the locks - keep waiting. + * Still can't get the lock - keep waiting. */ - DEBUG(10,("reprocess_blocked_smb2_lock: only got %d locks of %d needed " + DEBUG(10,("reprocess_blocked_smb2_lock: failed to get lock " "for file %s, %s. Still waiting....\n", - (int)blr->lock_num, - (int)state->lock_count, fsp_str_dbg(fsp), fsp_fnum_dbg(fsp))); return; - } /**************************************************************** diff --git a/source3/smbd/smb2_read.c b/source3/smbd/smb2_read.c index 6478326ac06..7b273f8c62b 100644 --- a/source3/smbd/smb2_read.c +++ b/source3/smbd/smb2_read.c @@ -178,11 +178,13 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state) 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; ssize_t nread; + ssize_t ret; nread = SMB_VFS_SENDFILE(fsp->conn->sconn->sock, fsp, - state->smb2req->queue_entry.sendfile_header, + hdr, in_offset, in_length); DEBUG(10,("smb2_sendfile_send_data: SMB_VFS_SENDFILE returned %d on file %s\n", @@ -190,11 +192,19 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state) fsp_str_dbg(fsp) )); if (nread == -1) { - if (errno == ENOSYS || errno == EINTR) { + /* + * 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 systems with no working - * sendfile. Fake this up by doing read/write calls. - */ + * 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(fsp, in_offset, in_length); if (nread == -1) { @@ -225,23 +235,50 @@ static int smb2_sendfile_send_data(struct smbd_smb2_read_state *state) DEBUG(3, ("send_file_readX: sendfile sent zero bytes " "falling back to the normal read: %s\n", fsp_str_dbg(fsp))); + goto normal_read; + } - 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"); - } + /* + * We got a short read + */ + goto out; + +normal_read: + /* Send out the header. */ + ret = write_data(fsp->conn->sconn->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))); + + 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"); + } + 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); + sendfile_short_send(fsp, nread, hdr->length, in_length); } init_strict_lock_struct(fsp, |