svn commit: samba r3933 - in trunk/source/smbd: .

jra at samba.org jra at samba.org
Wed Nov 24 03:41:55 GMT 2004


Author: jra
Date: 2004-11-24 03:41:54 +0000 (Wed, 24 Nov 2004)
New Revision: 3933

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=3933

Log:
Correctly check for the top length bit in LARGE_READX.
Jeremy.

Modified:
   trunk/source/smbd/reply.c


Changeset:
Modified: trunk/source/smbd/reply.c
===================================================================
--- trunk/source/smbd/reply.c	2004-11-24 01:03:26 UTC (rev 3932)
+++ trunk/source/smbd/reply.c	2004-11-24 03:41:54 UTC (rev 3933)
@@ -33,6 +33,7 @@
 extern char magic_char;
 extern int global_oplock_break;
 unsigned int smb_echo_count = 0;
+extern uint32 global_client_caps;
 
 extern BOOL global_encrypted_passwords_negotiated;
 
@@ -1716,7 +1717,7 @@
  Fail for readbraw.
 ****************************************************************************/
 
-void fail_readraw(void)
+static void fail_readraw(void)
 {
 	pstring errstr;
 	slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
@@ -1724,12 +1725,46 @@
 	exit_server(errstr);
 }
 
+#if defined(WITH_SENDFILE)
 /****************************************************************************
+ Fake (read/write) sendfile. Returns -1 on read or write fail.
+****************************************************************************/
+
+static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, int bufsize)
+{
+	ssize_t ret=0;
+
+	/* Paranioa check... */
+	if (nread > bufsize) {
+		fail_readraw();
+	}
+
+	if (nread > 0) {
+		ret = read_file(fsp,buf,startpos,nread);
+		if (ret == -1) {
+			return -1;
+		}
+	}
+
+	/* If we had a short read, fill with zeros. */
+	if (ret < nread) {
+		memset(outbuf, '\0', nread - ret);
+	}
+
+	if (write_data(smbd_server_fd(),buf,nread) != nread) {
+		return -1;
+	}	
+
+	return (ssize_t)nread;
+}
+#endif
+
+/****************************************************************************
  Use sendfile in readbraw.
 ****************************************************************************/
 
 void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread,
-		ssize_t mincount, char *outbuf)
+		ssize_t mincount, char *outbuf, int out_buffsize)
 {
 	ssize_t ret=0;
 
@@ -1751,12 +1786,21 @@
 
 		if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) {
 			/*
-			 * Special hack for broken Linux with no 64 bit clean sendfile. If we
-			 * return ENOSYS then pretend we just got a normal read.
+			 * 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.
 			 */
-			if (errno == ENOSYS) {
+			if (errno == EINTR) {
+				/* Ensure we don't do this again. */
 				set_use_sendfile(SNUM(conn), False);
-				goto normal_read;
+				DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
+
+				if (fake_sendfile(fsp, startpos, nread, outbuf + 4, out_buffsize - 4) == -1) {
+					DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n",
+						fsp->fsp_name, strerror(errno) ));
+					exit_server("send_file_readbraw fake_sendfile failed");
+				}
+				return;
 			}
 
 			DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
@@ -1766,7 +1810,6 @@
 
 	}
 
-  normal_read:
 #endif
 
 	if (nread > 0) {
@@ -1789,7 +1832,7 @@
  Reply to a readbraw (core+ protocol).
 ****************************************************************************/
 
-int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
+int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int out_buffsize)
 {
 	extern struct current_user current_user;
 	ssize_t maxcount,mincount;
@@ -1904,7 +1947,7 @@
 	DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos,
 				(int)maxcount, (int)mincount, (int)nread ) );
   
-	send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf);
+	send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf, out_buffsize);
 
 	DEBUG(5,("readbraw finished\n"));
 	END_PROFILE(SMBreadbraw);
@@ -2068,7 +2111,7 @@
  Reply to a read and X - possibly using sendfile.
 ****************************************************************************/
 
-int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, 
+int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, int len_outbuf,
 		files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
 {
 	ssize_t nread = -1;
@@ -2116,12 +2159,22 @@
 
 		if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) {
 			/*
-			 * Special hack for broken Linux with no 64 bit clean sendfile. If we
-			 * return ENOSYS then pretend we just got a normal read.
+			 * 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.
 			 */
-			if (errno == ENOSYS) {
+			if (errno == EINTR) {
+				/* Ensure we don't do this again. */
 				set_use_sendfile(SNUM(conn), False);
-				goto normal_read;
+				DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
+
+				if (fake_sendfile(fsp, startpos, smb_maxcnt, data,
+							len_outbuf - (data-outbuf)) == -1) {
+					DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
+						fsp->fsp_name, strerror(errno) ));
+					exit_server("send_file_readX: fake_sendfile failed");
+				}
+				return;
 			}
 
 			DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
@@ -2134,8 +2187,6 @@
 		return -1;
 	}
 
-  normal_read:
-
 #endif
 
 	nread = read_file(fsp,data,startpos,smb_maxcnt);
@@ -2183,6 +2234,10 @@
 
 	set_message(outbuf,12,0,True);
 
+	if (global_client_caps & CAP_LARGE_READX) {
+		smb_maxcnt |= ((((size_t)SVAL(inbuf,smb_vwv7)) & 1 )<<16);
+	}
+
 	if(CVAL(inbuf,smb_wct) == 12) {
 #ifdef LARGE_SMB_OFF_T
 		/*



More information about the samba-cvs mailing list