summaryrefslogtreecommitdiff
path: root/source3/smbd/reply.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd/reply.c')
-rw-r--r--source3/smbd/reply.c78
1 files changed, 52 insertions, 26 deletions
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index e2aca3793a..0355cb7083 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3698,9 +3698,23 @@ void reply_read_and_X(struct smb_request *req)
}
- if (!big_readX &&
- schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
- goto out;
+ if (!big_readX) {
+ NTSTATUS status = schedule_aio_read_and_X(conn,
+ req,
+ fsp,
+ startpos,
+ smb_maxcnt);
+ if (NT_STATUS_IS_OK(status)) {
+ /* Read scheduled - we're done. */
+ goto out;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
+ /* Real error - report to client. */
+ END_PROFILE(SMBreadX);
+ reply_nterror(req, status);
+ return;
+ }
+ /* NT_STATUS_RETRY - fall back to sync read. */
}
smbd_lock_socket(smbd_server_conn);
@@ -4320,6 +4334,7 @@ void reply_write_and_X(struct smb_request *req)
unsigned int smblen;
char *data;
NTSTATUS status;
+ int saved_errno = 0;
START_PROFILE(SMBwriteX);
@@ -4414,16 +4429,6 @@ void reply_write_and_X(struct smb_request *req)
#endif /* LARGE_SMB_OFF_T */
}
- init_strict_lock_struct(fsp, (uint32)req->smbpid,
- (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
- &lock);
-
- if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
- reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
- END_PROFILE(SMBwriteX);
- return;
- }
-
/* X/Open SMB protocol says that, unlike SMBwrite
if the length is zero then NO truncation is
done, just a write of zero. To truncate a file,
@@ -4432,24 +4437,49 @@ void reply_write_and_X(struct smb_request *req)
if(numtowrite == 0) {
nwritten = 0;
} else {
+ if (req->unread_bytes == 0) {
+ status = schedule_aio_write_and_X(conn,
+ req,
+ fsp,
+ data,
+ startpos,
+ numtowrite);
- if ((req->unread_bytes == 0) &&
- schedule_aio_write_and_X(conn, req, fsp, data, startpos,
- numtowrite)) {
- goto strict_unlock;
+ if (NT_STATUS_IS_OK(status)) {
+ /* write scheduled - we're done. */
+ goto out;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
+ /* Real error - report to client. */
+ reply_nterror(req, status);
+ goto out;
+ }
+ /* NT_STATUS_RETRY - fall through to sync write. */
+ }
+
+ init_strict_lock_struct(fsp, (uint32)req->smbpid,
+ (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
+ &lock);
+
+ if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
+ reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
+ goto out;
}
nwritten = write_file(req,fsp,data,startpos,numtowrite);
+ saved_errno = errno;
+
+ SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
}
if(nwritten < 0) {
- reply_nterror(req, map_nt_error_from_unix(errno));
- goto strict_unlock;
+ reply_nterror(req, map_nt_error_from_unix(saved_errno));
+ goto out;
}
if((nwritten == 0) && (numtowrite != 0)) {
reply_nterror(req, NT_STATUS_DISK_FULL);
- goto strict_unlock;
+ goto out;
}
reply_outbuf(req, 6, 0);
@@ -4469,18 +4499,14 @@ void reply_write_and_X(struct smb_request *req)
DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
fsp_str_dbg(fsp), nt_errstr(status)));
reply_nterror(req, status);
- goto strict_unlock;
+ goto out;
}
- SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-
END_PROFILE(SMBwriteX);
chain_reply(req);
return;
-strict_unlock:
- SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-
+out:
END_PROFILE(SMBwriteX);
return;
}