summaryrefslogtreecommitdiff
path: root/source3/smbd/reply.c
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-10-30 16:22:24 -0700
committerJeremy Allison <jra@samba.org>2007-10-30 16:22:24 -0700
commitc3250149e12338fac5093991b385ad2807c92d1f (patch)
treefa1e5387fb10d02b1f09da59fc20d7a8520e65fc /source3/smbd/reply.c
parent4367f4b4d4ce075f3fe8e88e68dbda47e2252349 (diff)
downloadsamba-c3250149e12338fac5093991b385ad2807c92d1f.tar.gz
samba-c3250149e12338fac5093991b385ad2807c92d1f.tar.bz2
samba-c3250149e12338fac5093991b385ad2807c92d1f.zip
Add new parameter, "min receivefile size" (by default set
to zero). If non-zero, writeX calls greater than this value will be left in the socket buffer for later handling with recvfile (or userspace equivalent). Definition of recvfile for your system is left as an exercise for the reader (I'm working on getting splice working :-). Jeremy. (This used to be commit 11c03b75ddbcb6e36b231bb40a1773d1c550621c)
Diffstat (limited to 'source3/smbd/reply.c')
-rw-r--r--source3/smbd/reply.c95
1 files changed, 81 insertions, 14 deletions
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 38ce797eeb..4c1ed56d4f 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -3494,7 +3494,7 @@ void reply_writebraw(connection_struct *conn, struct smb_request *req)
}
if (numtowrite>0) {
- nwritten = write_file(fsp,data,startpos,numtowrite);
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
}
DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
@@ -3572,7 +3572,7 @@ void reply_writebraw(connection_struct *conn, struct smb_request *req)
exit_server_cleanly("secondary writebraw failed");
}
- nwritten = write_file(fsp,buf+4,startpos+nwritten,numtowrite);
+ nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
if (nwritten == -1) {
TALLOC_FREE(buf);
reply_unixerror(req, ERRHRD, ERRdiskfull);
@@ -3686,7 +3686,7 @@ void reply_writeunlock(connection_struct *conn, struct smb_request *req)
if(numtowrite == 0) {
nwritten = 0;
} else {
- nwritten = write_file(fsp,data,startpos,numtowrite);
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
}
status = sync_file(conn, fsp, False /* write through */);
@@ -3808,7 +3808,7 @@ void reply_write(connection_struct *conn, struct smb_request *req)
return;
}
} else
- nwritten = write_file(fsp,data,startpos,numtowrite);
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
status = sync_file(conn, fsp, False);
if (!NT_STATUS_IS_OK(status)) {
@@ -3841,6 +3841,64 @@ void reply_write(connection_struct *conn, struct smb_request *req)
}
/****************************************************************************
+ Ensure a buffer is a valid writeX for recvfile purposes.
+****************************************************************************/
+
+#define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
+ (2*14) + /* word count (including bcc) */ \
+ 1 /* pad byte */)
+
+bool is_valid_writeX_buffer(char *inbuf)
+{
+ size_t numtowrite;
+ connection_struct *conn = NULL;
+ unsigned int doff = 0;
+ size_t len = smb_len(inbuf);
+
+ if (CVAL(inbuf,smb_com) != SMBwriteX ||
+ CVAL(inbuf,smb_vwv0) != 0xFF ||
+ CVAL(inbuf,smb_wct) != 14) {
+ return false;
+ }
+ conn = conn_find(SVAL(inbuf, smb_tid));
+ if (conn == NULL) {
+ return false;
+ }
+ if (IS_IPC(conn)) {
+ return false;
+ }
+ numtowrite = SVAL(inbuf,smb_vwv10);
+ numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16);
+ if (numtowrite == 0) {
+ return false;
+ }
+ /* Ensure the sizes match up. */
+ doff = SVAL(inbuf,smb_vwv11);
+
+ if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
+ /* no pad byte...old smbclient :-( */
+ return false;
+ }
+
+ if (len - doff != numtowrite) {
+ DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
+ "len = %u, doff = %u, numtowrite = %u\n",
+ (unsigned int)len,
+ (unsigned int)doff,
+ (unsigned int)numtowrite ));
+ return false;
+ }
+
+ DEBUG(10,("is_valid_writeX_buffer: true "
+ "len = %u, doff = %u, numtowrite = %u\n",
+ (unsigned int)len,
+ (unsigned int)doff,
+ (unsigned int)numtowrite ));
+
+ return true;
+}
+
+/****************************************************************************
Reply to a write and X.
****************************************************************************/
@@ -3875,10 +3933,18 @@ void reply_write_and_X(connection_struct *conn, struct smb_request *req)
numtowrite |= ((((size_t)SVAL(req->inbuf,smb_vwv9)) & 1 )<<16);
}
- if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
- reply_doserror(req, ERRDOS, ERRbadmem);
- END_PROFILE(SMBwriteX);
- return;
+ if (req->unread_bytes) {
+ if (numtowrite != req->unread_bytes) {
+ reply_doserror(req, ERRDOS, ERRbadmem);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
+ } else {
+ if (smb_doff > smblen || smb_doff + numtowrite > smblen) {
+ reply_doserror(req, ERRDOS, ERRbadmem);
+ END_PROFILE(SMBwriteX);
+ return;
+ }
}
/* If it's an IPC, pass off the pipe handler. */
@@ -3947,15 +4013,16 @@ void reply_write_and_X(connection_struct *conn, struct smb_request *req)
nwritten = 0;
} else {
- if (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)) {
END_PROFILE(SMBwriteX);
return;
}
- nwritten = write_file(fsp,data,startpos,numtowrite);
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
}
-
+
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
reply_unixerror(req, ERRHRD, ERRdiskfull);
END_PROFILE(SMBwriteX);
@@ -4264,7 +4331,7 @@ void reply_writeclose(connection_struct *conn, struct smb_request *req)
return;
}
- nwritten = write_file(fsp,data,startpos,numtowrite);
+ nwritten = write_file(req,fsp,data,startpos,numtowrite);
set_filetime(conn, fsp->fsp_name, mtime);
@@ -4726,7 +4793,7 @@ void reply_printwrite(connection_struct *conn, struct smb_request *req)
data = smb_buf(req->inbuf) + 3;
- if (write_file(fsp,data,-1,numtowrite) != numtowrite) {
+ if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) {
reply_unixerror(req, ERRHRD, ERRdiskfull);
END_PROFILE(SMBsplwr);
return;