summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/blocking.c195
-rw-r--r--source3/smbd/open.c22
-rw-r--r--source3/smbd/pysmbd.c58
-rw-r--r--source3/smbd/server.c16
-rw-r--r--source3/smbd/smb2_create.c9
-rw-r--r--source3/smbd/smb2_lock.c69
-rw-r--r--source3/smbd/smb2_read.c69
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,