[GLUE] Rsync SAMBA_3_2_0 SVN r25598 in order to create the v3-2-test branch.
[samba.git] / source / libsmb / clireadwrite.c
index 1c72cb2942c386e635ef6364a891b03bb35ae2f2..ed80dfaf1a7f848b71622a507de610740d09567d 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
@@ -35,7 +34,7 @@ static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
        if ((SMB_BIG_UINT)offset >> 32) 
                bigoffset = True;
 
-       set_message(NULL,cli->outbuf,bigoffset ? 12 : 10,0,True);
+       set_message(cli->outbuf,bigoffset ? 12 : 10,0,True);
                
        SCVAL(cli->outbuf,smb_com,SMBreadX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -46,7 +45,7 @@ static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
        SIVAL(cli->outbuf,smb_vwv3,offset);
        SSVAL(cli->outbuf,smb_vwv5,size);
        SSVAL(cli->outbuf,smb_vwv6,size);
-       SSVAL(cli->outbuf,smb_vwv7,((size >> 16) & 1));
+       SSVAL(cli->outbuf,smb_vwv7,(size >> 16));
        SSVAL(cli->outbuf,smb_mid,cli->mid + i);
 
        if (bigoffset) {
@@ -63,9 +62,11 @@ static BOOL cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
 ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
 {
        char *p;
-       int size2;
-       int readsize;
+       size_t size2;
+       size_t readsize;
        ssize_t total = 0;
+       /* We can only do direct reads if not signing. */
+       BOOL direct_reads = !client_is_signing_on(cli);
 
        if (size == 0) 
                return 0;
@@ -75,7 +76,9 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
         * rounded down to a multiple of 1024.
         */
 
-       if (cli->capabilities & CAP_LARGE_READX) {
+       if (client_is_signing_on(cli) == False && (cli->posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) {
+               readsize = CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE;
+       } else if (cli->capabilities & CAP_LARGE_READX) {
                if (cli->is_samba) {
                        readsize = CLI_SAMBA_MAX_LARGE_READX_SIZE;
                } else {
@@ -93,8 +96,13 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
                if (!cli_issue_read(cli, fnum, offset, readsize, 0))
                        return -1;
 
-               if (!cli_receive_smb(cli))
-                       return -1;
+               if (direct_reads) {
+                       if (!cli_receive_smb_readX_header(cli))
+                               return -1;
+               } else {
+                       if (!cli_receive_smb(cli))
+                               return -1;
+               }
 
                /* Check for error.  Make sure to check for DOS and NT
                    errors. */
@@ -125,7 +133,7 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
                }
 
                size2 = SVAL(cli->inbuf, smb_vwv5);
-               size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7) & 1)) << 16);
+               size2 |= (((unsigned int)(SVAL(cli->inbuf, smb_vwv7))) << 16);
 
                if (size2 > readsize) {
                        DEBUG(5,("server returned more than we wanted!\n"));
@@ -135,10 +143,29 @@ ssize_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_
                        return -1;
                }
 
-               /* Copy data into buffer */
+               if (!direct_reads) {
+                       /* Copy data into buffer */
+                       p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
+                       memcpy(buf + total, p, size2);
+               } else {
+                       /* Ensure the remaining data matches the return size. */
+                       ssize_t toread = smb_len_large(cli->inbuf) - SVAL(cli->inbuf,smb_vwv6);
 
-               p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
-               memcpy(buf + total, p, size2);
+                       /* Ensure the size is correct. */
+                       if (toread != size2) {
+                               DEBUG(5,("direct read logic fail toread (%d) != size2 (%u)\n",
+                                       (int)toread, (unsigned int)size2 ));
+                               return -1;
+                       }
+
+                       /* Read data directly into buffer */
+                       toread = cli_receive_smb_data(cli,buf+total,size2);
+                       if (toread != size2) {
+                               DEBUG(5,("direct read read failure toread (%d) != size2 (%u)\n",
+                                       (int)toread, (unsigned int)size2 ));
+                               return -1;
+                       }
+               }
 
                total += size2;
                offset += size2;
@@ -176,7 +203,7 @@ static BOOL cli_issue_readraw(struct cli_state *cli, int fnum, off_t offset,
        memset(cli->outbuf,'\0',smb_size);
        memset(cli->inbuf,'\0',smb_size);
 
-       set_message(NULL,cli->outbuf,10,0,True);
+       set_message(cli->outbuf,10,0,True);
                
        SCVAL(cli->outbuf,smb_com,SMBreadbraw);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -285,9 +312,9 @@ static BOOL cli_issue_write(struct cli_state *cli, int fnum, off_t offset,
        }
 
        if (large_writex)
-               set_message(NULL,cli->outbuf,14,0,True);
+               set_message(cli->outbuf,14,0,True);
        else
-               set_message(NULL,cli->outbuf,12,0,True);
+               set_message(cli->outbuf,12,0,True);
        
        SCVAL(cli->outbuf,smb_com,SMBwriteX);
        SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -399,7 +426,7 @@ ssize_t cli_smbwrite(struct cli_state *cli,
                memset(cli->outbuf,'\0',smb_size);
                memset(cli->inbuf,'\0',smb_size);
 
-               set_message(NULL,cli->outbuf,5, 0,True);
+               set_message(cli->outbuf,5, 0,True);
 
                SCVAL(cli->outbuf,smb_com,SMBwrite);
                SSVAL(cli->outbuf,smb_tid,cli->cnum);
@@ -413,7 +440,7 @@ ssize_t cli_smbwrite(struct cli_state *cli,
                p = smb_buf(cli->outbuf);
                *p++ = 1;
                SSVAL(p, 0, size); p += 2;
-               memcpy(p, buf, size); p += size;
+               memcpy(p, buf + total, size); p += size;
 
                cli_setup_bcc(cli, p);