s4 torture: Add lockread_supported based off of CAP_LOCK_AND_READ
[samba.git] / source4 / torture / raw / read.c
index 5fba3f1b31ba182ff08d94e4ff5461baace3b7b7..efdd04045196a05d0d174f0329f9b0d5c4646bd7 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,
    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"
+#include "libcli/raw/libcliraw.h"
+#include "system/time.h"
+#include "system/filesys.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
 
 #define CHECK_STATUS(status, correct) do { \
        if (!NT_STATUS_EQUAL(status, correct)) { \
-               printf("(%d) Incorrect status %s - should be %s\n", \
-                      __LINE__, nt_errstr(status), nt_errstr(correct)); \
-               ret = False; \
+               printf("(%s) Incorrect status %s - should be %s\n", \
+                      __location__, nt_errstr(status), nt_errstr(correct)); \
+               ret = false; \
                goto done; \
        }} while (0)
 
 #define CHECK_VALUE(v, correct) do { \
        if ((v) != (correct)) { \
-               printf("(%d) Incorrect value %s=%d - should be %d\n", \
-                      __LINE__, #v, v, correct); \
-               ret = False; \
+               printf("(%s) Incorrect value %s=%ld - should be %ld\n", \
+                      __location__, #v, (long)v, (long)correct); \
+               ret = false; \
                goto done; \
        }} while (0)
 
 #define CHECK_BUFFER(buf, seed, len) do { \
        if (!check_buffer(buf, seed, len, __LINE__)) { \
-               ret = False; \
+               ret = false; \
                goto done; \
        }} while (0)
 
@@ -48,7 +52,7 @@
 /*
   setup a random buffer based on a seed
 */
-static void setup_buffer(char *buf, uint_t seed, int len)
+static void setup_buffer(uint8_t *buf, uint_t seed, int len)
 {
        int i;
        srandom(seed);
@@ -58,56 +62,59 @@ static void setup_buffer(char *buf, uint_t seed, int len)
 /*
   check a random buffer based on a seed
 */
-static BOOL check_buffer(char *buf, uint_t seed, int len, int line)
+static bool check_buffer(uint8_t *buf, uint_t seed, int len, int line)
 {
        int i;
        srandom(seed);
        for (i=0;i<len;i++) {
-               char v = random();
+               uint8_t v = random();
                if (buf[i] != v) {
                        printf("Buffer incorrect at line %d! ofs=%d v1=0x%x v2=0x%x\n", 
                               line, i, buf[i], v);
-                       return False;
+                       return false;
                }
        }
-       return True;
+       return true;
 }
 
 /*
   test read ops
 */
-static BOOL test_read(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_read(struct torture_context *tctx, struct smbcli_state *cli)
 {
        union smb_read io;
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum;
-       char *buf;
+       uint8_t *buf;
        const int maxsize = 90000;
        const char *fname = BASEDIR "\\test.txt";
        const char *test_data = "TEST DATA";
        uint_t seed = time(NULL);
 
-       buf = talloc_zero(mem_ctx, maxsize);
+       buf = talloc_zero_array(tctx, uint8_t, maxsize);
 
-       if (cli_deltree(cli->tree, BASEDIR) == -1 ||
-           NT_STATUS_IS_ERR(cli_mkdir(cli->tree, BASEDIR))) {
-               printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli->tree));
-               return False;
+       if (!torture_setting_bool(tctx, "read_support", true)) {
+               printf("server refuses to support READ\n");
+               return true;
+       }
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
        }
 
        printf("Testing RAW_READ_READ\n");
        io.generic.level = RAW_READ_READ;
-       
-       fnum = cli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+
+       fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
-               printf("Failed to create %s - %s\n", fname, cli_errstr(cli->tree));
-               ret = False;
+               printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+               ret = false;
                goto done;
        }
 
        printf("Trying empty file read\n");
-       io.read.in.fnum = fnum;
+       io.read.in.file.fnum = fnum;
        io.read.in.count = 1;
        io.read.in.offset = 0;
        io.read.in.remaining = 0;
@@ -124,15 +131,15 @@ static BOOL test_read(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_VALUE(io.read.out.nread, 0);
 
        printf("Trying bad fnum\n");
-       io.read.in.fnum = fnum+1;
+       io.read.in.file.fnum = fnum+1;
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
-       io.read.in.fnum = fnum;
+       io.read.in.file.fnum = fnum;
 
-       cli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
+       smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
 
        printf("Trying small read\n");
-       io.read.in.fnum = fnum;
+       io.read.in.file.fnum = fnum;
        io.read.in.offset = 0;
        io.read.in.remaining = 0;
        io.read.in.count = strlen(test_data);
@@ -140,7 +147,7 @@ static BOOL test_read(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(io.read.out.nread, strlen(test_data));
        if (memcmp(buf, test_data, strlen(test_data)) != 0) {
-               ret = False;
+               ret = false;
                printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
                goto done;
        }
@@ -152,20 +159,22 @@ static BOOL test_read(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(io.read.out.nread, strlen(test_data)-1);
        if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
-               ret = False;
+               ret = false;
                printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
                goto done;
        }
 
-       printf("Trying max offset\n");
-       io.read.in.offset = ~0;
-       io.read.in.count = strlen(test_data);
-       status = smb_raw_read(cli->tree, &io);
-       CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_VALUE(io.read.out.nread, 0);
+       if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+               printf("Trying max offset\n");
+               io.read.in.offset = ~0;
+               io.read.in.count = strlen(test_data);
+               status = smb_raw_read(cli->tree, &io);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               CHECK_VALUE(io.read.out.nread, 0);
+       }
 
        setup_buffer(buf, seed, maxsize);
-       cli_write(cli->tree, fnum, 0, buf, 0, maxsize);
+       smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
        memset(buf, 0, maxsize);
 
        printf("Trying large read\n");
@@ -178,9 +187,9 @@ static BOOL test_read(struct cli_state *cli, TALLOC_CTX *mem_ctx)
 
        printf("Trying locked region\n");
        cli->session->pid++;
-       if (NT_STATUS_IS_ERR(cli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
+       if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
                printf("Failed to lock file at %d\n", __LINE__);
-               ret = False;
+               ret = false;
                goto done;
        }
        cli->session->pid--;
@@ -192,9 +201,9 @@ static BOOL test_read(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        
 
 done:
-       cli_close(cli->tree, fnum);
+       smbcli_close(cli->tree, fnum);
        smb_raw_exit(cli->session);
-       cli_deltree(cli->tree, BASEDIR);
+       smbcli_deltree(cli->tree, BASEDIR);
        return ret;
 }
 
@@ -202,40 +211,44 @@ done:
 /*
   test lockread ops
 */
-static BOOL test_lockread(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_lockread(struct torture_context *tctx, 
+                                                 struct smbcli_state *cli)
 {
        union smb_read io;
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum;
-       char *buf;
+       uint8_t *buf;
        const int maxsize = 90000;
        const char *fname = BASEDIR "\\test.txt";
        const char *test_data = "TEST DATA";
        uint_t seed = time(NULL);
 
-       buf = talloc_zero(mem_ctx, maxsize);
+       if (!cli->transport->negotiate.lockread_supported) {
+               printf("Server does not support lockread - skipping\n");
+               return true;
+       }
+
+       buf = talloc_zero_array(tctx, uint8_t, maxsize);
 
-       if (cli_deltree(cli->tree, BASEDIR) == -1 ||
-           NT_STATUS_IS_ERR(cli_mkdir(cli->tree, BASEDIR))) {
-               printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli->tree));
-               return False;
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
        }
 
        printf("Testing RAW_READ_LOCKREAD\n");
        io.generic.level = RAW_READ_LOCKREAD;
        
-       fnum = cli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
-               printf("Failed to create %s - %s\n", fname, cli_errstr(cli->tree));
-               ret = False;
+               printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+               ret = false;
                goto done;
        }
 
        printf("Trying empty file read\n");
-       io.lockread.in.fnum = fnum;
+       io.lockread.in.file.fnum = fnum;
        io.lockread.in.count = 1;
-       io.lockread.in.offset = 0;
+       io.lockread.in.offset = 1;
        io.lockread.in.remaining = 0;
        io.lockread.out.data = buf;
        status = smb_raw_read(cli->tree, &io);
@@ -252,31 +265,33 @@ static BOOL test_lockread(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        printf("Trying zero file read\n");
        io.lockread.in.count = 0;
        status = smb_raw_read(cli->tree, &io);
-       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       smbcli_unlock(cli->tree, fnum, 1, 1);
 
        printf("Trying bad fnum\n");
-       io.lockread.in.fnum = fnum+1;
+       io.lockread.in.file.fnum = fnum+1;
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
-       io.lockread.in.fnum = fnum;
+       io.lockread.in.file.fnum = fnum;
 
-       cli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
+       smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
 
        printf("Trying small read\n");
-       io.lockread.in.fnum = fnum;
+       io.lockread.in.file.fnum = fnum;
        io.lockread.in.offset = 0;
        io.lockread.in.remaining = 0;
        io.lockread.in.count = strlen(test_data);
        status = smb_raw_read(cli->tree, &io);
-       CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);
+       CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
 
-       cli_unlock(cli->tree, fnum, 0, 1);
+       smbcli_unlock(cli->tree, fnum, 1, 0);
 
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(io.lockread.out.nread, strlen(test_data));
        if (memcmp(buf, test_data, strlen(test_data)) != 0) {
-               ret = False;
+               ret = false;
                printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
                goto done;
        }
@@ -286,26 +301,28 @@ static BOOL test_lockread(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        io.lockread.in.count = strlen(test_data);
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
-       cli_unlock(cli->tree, fnum, 0, strlen(test_data));
+       smbcli_unlock(cli->tree, fnum, 0, strlen(test_data));
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
 
        CHECK_VALUE(io.lockread.out.nread, strlen(test_data)-1);
        if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
-               ret = False;
+               ret = false;
                printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
                goto done;
        }
 
-       printf("Trying max offset\n");
-       io.lockread.in.offset = ~0;
-       io.lockread.in.count = strlen(test_data);
-       status = smb_raw_read(cli->tree, &io);
-       CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_VALUE(io.lockread.out.nread, 0);
+       if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+               printf("Trying max offset\n");
+               io.lockread.in.offset = ~0;
+               io.lockread.in.count = strlen(test_data);
+               status = smb_raw_read(cli->tree, &io);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               CHECK_VALUE(io.lockread.out.nread, 0);
+       }
 
        setup_buffer(buf, seed, maxsize);
-       cli_write(cli->tree, fnum, 0, buf, 0, maxsize);
+       smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
        memset(buf, 0, maxsize);
 
        printf("Trying large read\n");
@@ -313,18 +330,18 @@ static BOOL test_lockread(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        io.lockread.in.count = ~0;
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_LOCK_NOT_GRANTED);
-       cli_unlock(cli->tree, fnum, 1, strlen(test_data));
+       smbcli_unlock(cli->tree, fnum, 1, strlen(test_data));
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_BUFFER(buf, seed, io.lockread.out.nread);
-       cli_unlock(cli->tree, fnum, 0, 0xFFFF);
+       smbcli_unlock(cli->tree, fnum, 0, 0xFFFF);
 
 
        printf("Trying locked region\n");
        cli->session->pid++;
-       if (NT_STATUS_IS_ERR(cli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
+       if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
                printf("Failed to lock file at %d\n", __LINE__);
-               ret = False;
+               ret = false;
                goto done;
        }
        cli->session->pid--;
@@ -336,8 +353,8 @@ static BOOL test_lockread(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        
 
 done:
-       cli_close(cli->tree, fnum);
-       cli_deltree(cli->tree, BASEDIR);
+       smbcli_close(cli->tree, fnum);
+       smbcli_deltree(cli->tree, BASEDIR);
        return ret;
 }
 
@@ -345,42 +362,41 @@ done:
 /*
   test readx ops
 */
-static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_readx(struct torture_context *tctx, struct smbcli_state *cli)
 {
        union smb_read io;
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum;
-       char *buf;
+       uint8_t *buf;
        const int maxsize = 90000;
        const char *fname = BASEDIR "\\test.txt";
        const char *test_data = "TEST DATA";
        uint_t seed = time(NULL);
 
-       buf = talloc_zero(mem_ctx, maxsize);
+       buf = talloc_zero_array(tctx, uint8_t, maxsize);
 
-       if (cli_deltree(cli->tree, BASEDIR) == -1 ||
-           NT_STATUS_IS_ERR(cli_mkdir(cli->tree, BASEDIR))) {
-               printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli->tree));
-               return False;
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
        }
 
        printf("Testing RAW_READ_READX\n");
        
-       fnum = cli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
-               printf("Failed to create %s - %s\n", fname, cli_errstr(cli->tree));
-               ret = False;
+               printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+               ret = false;
                goto done;
        }
 
        printf("Trying empty file read\n");
        io.generic.level = RAW_READ_READX;
-       io.readx.in.fnum = fnum;
+       io.readx.in.file.fnum = fnum;
        io.readx.in.mincnt = 1;
        io.readx.in.maxcnt = 1;
        io.readx.in.offset = 0;
        io.readx.in.remaining = 0;
+       io.readx.in.read_for_execute = false;
        io.readx.out.data = buf;
        status = smb_raw_read(cli->tree, &io);
 
@@ -399,17 +415,18 @@ static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_VALUE(io.readx.out.compaction_mode, 0);
 
        printf("Trying bad fnum\n");
-       io.readx.in.fnum = fnum+1;
+       io.readx.in.file.fnum = fnum+1;
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_INVALID_HANDLE);
-       io.readx.in.fnum = fnum;
+       io.readx.in.file.fnum = fnum;
 
-       cli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
+       smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
 
        printf("Trying small read\n");
-       io.readx.in.fnum = fnum;
+       io.readx.in.file.fnum = fnum;
        io.readx.in.offset = 0;
        io.readx.in.remaining = 0;
+       io.readx.in.read_for_execute = false;
        io.readx.in.mincnt = strlen(test_data);
        io.readx.in.maxcnt = strlen(test_data);
        status = smb_raw_read(cli->tree, &io);
@@ -418,7 +435,7 @@ static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
        CHECK_VALUE(io.readx.out.compaction_mode, 0);
        if (memcmp(buf, test_data, strlen(test_data)) != 0) {
-               ret = False;
+               ret = false;
                printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
                goto done;
        }
@@ -433,29 +450,70 @@ static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
        CHECK_VALUE(io.readx.out.compaction_mode, 0);
        if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
-               ret = False;
+               ret = false;
                printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
                goto done;
        }
 
-       printf("Trying max offset\n");
-       io.readx.in.offset = 0xffffffff;
-       io.readx.in.mincnt = strlen(test_data);
-       io.readx.in.maxcnt = strlen(test_data);
+       if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+               printf("Trying max offset\n");
+               io.readx.in.offset = 0xffffffff;
+               io.readx.in.mincnt = strlen(test_data);
+               io.readx.in.maxcnt = strlen(test_data);
+               status = smb_raw_read(cli->tree, &io);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               CHECK_VALUE(io.readx.out.nread, 0);
+               CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+               CHECK_VALUE(io.readx.out.compaction_mode, 0);
+       }
+
+       printf("Trying mincnt past EOF\n");
+       memset(buf, 0, maxsize);
+       io.readx.in.offset = 0;
+       io.readx.in.mincnt = 100;
+       io.readx.in.maxcnt = 110;
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_VALUE(io.readx.out.nread, 0);
        CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
        CHECK_VALUE(io.readx.out.compaction_mode, 0);
+       CHECK_VALUE(io.readx.out.nread, strlen(test_data));
+       if (memcmp(buf, test_data, strlen(test_data)) != 0) {
+               ret = false;
+               printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
+               goto done;
+       }
+
 
        setup_buffer(buf, seed, maxsize);
-       cli_write(cli->tree, fnum, 0, buf, 0, maxsize);
+       smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
        memset(buf, 0, maxsize);
 
-       printf("Trying large read\n");
+       printf("Trying page sized read\n");
+       io.readx.in.offset = 0;
+       io.readx.in.mincnt = 0x1000;
+       io.readx.in.maxcnt = 0x1000;
+       status = smb_raw_read(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+       CHECK_VALUE(io.readx.out.compaction_mode, 0);
+       CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
+       CHECK_BUFFER(buf, seed, io.readx.out.nread);
+
+       printf("Trying page + 1 sized read (check alignment)\n");
+       io.readx.in.offset = 0;
+       io.readx.in.mincnt = 0x1001;
+       io.readx.in.maxcnt = 0x1001;
+       status = smb_raw_read(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+       CHECK_VALUE(io.readx.out.compaction_mode, 0);
+       CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
+       CHECK_BUFFER(buf, seed, io.readx.out.nread);
+
+       printf("Trying large read (UINT16_MAX)\n");
        io.readx.in.offset = 0;
-       io.readx.in.mincnt = ~0;
-       io.readx.in.maxcnt = ~0;
+       io.readx.in.mincnt = 0xFFFF;
+       io.readx.in.maxcnt = 0xFFFF;
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
@@ -463,6 +521,23 @@ static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
        CHECK_BUFFER(buf, seed, io.readx.out.nread);
 
+       printf("Trying extra large read\n");
+       io.readx.in.offset = 0;
+       io.readx.in.mincnt = 100;
+       io.readx.in.maxcnt = 80000;
+       status = smb_raw_read(cli->tree, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_VALUE(io.readx.out.remaining, 0xFFFF);
+       CHECK_VALUE(io.readx.out.compaction_mode, 0);
+       if (torture_setting_bool(tctx, "samba3", false) ||
+           torture_setting_bool(tctx, "samba4", false)) {
+               printf("SAMBA: large read extension\n");
+               CHECK_VALUE(io.readx.out.nread, 80000);
+       } else {
+               CHECK_VALUE(io.readx.out.nread, 0);
+       }
+       CHECK_BUFFER(buf, seed, io.readx.out.nread);
+
        printf("Trying mincnt > maxcnt\n");
        memset(buf, 0, maxsize);
        io.readx.in.offset = 0;
@@ -487,11 +562,45 @@ static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_VALUE(io.readx.out.nread, io.readx.in.maxcnt);
        CHECK_BUFFER(buf, seed, io.readx.out.nread);
 
+       if (cli->transport->negotiate.capabilities & CAP_LARGE_READX) {
+               printf("Trying large readx\n");
+               io.readx.in.offset = 0;
+               io.readx.in.mincnt = 0;
+               io.readx.in.maxcnt = 0x10000 - 1;
+               status = smb_raw_read(cli->tree, &io);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               CHECK_VALUE(io.readx.out.nread, 0xFFFF);
+
+               io.readx.in.maxcnt = 0x10000;
+               status = smb_raw_read(cli->tree, &io);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               if (torture_setting_bool(tctx, "samba3", false) || 
+                   torture_setting_bool(tctx, "samba4", false)) {
+                       printf("SAMBA: large read extension\n");
+                       CHECK_VALUE(io.readx.out.nread, 0x10000);
+               } else {
+                       CHECK_VALUE(io.readx.out.nread, 0);
+               }
+
+               io.readx.in.maxcnt = 0x10001;
+               status = smb_raw_read(cli->tree, &io);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               if (torture_setting_bool(tctx, "samba3", false) ||
+                   torture_setting_bool(tctx, "samba4", false)) {
+                       printf("SAMBA: large read extension\n");
+                       CHECK_VALUE(io.readx.out.nread, 0x10001);
+               } else {
+                       CHECK_VALUE(io.readx.out.nread, 0);
+               }
+       } else {
+               printf("Server does not support the CAP_LARGE_READX extension\n");
+       }
+
        printf("Trying locked region\n");
        cli->session->pid++;
-       if (NT_STATUS_IS_ERR(cli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
+       if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
                printf("Failed to lock file at %d\n", __LINE__);
-               ret = False;
+               ret = false;
                goto done;
        }
        cli->session->pid--;
@@ -502,6 +611,11 @@ static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_FILE_LOCK_CONFLICT);     
 
+       if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+               printf("skipping large file tests - CAP_LARGE_FILES not set\n");
+               goto done;
+       }
+
        printf("Trying large offset read\n");
        io.readx.in.offset = ((uint64_t)0x2) << 32;
        io.readx.in.mincnt = 10;
@@ -510,9 +624,9 @@ static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(io.readx.out.nread, 0);
 
-       if (NT_STATUS_IS_ERR(cli_lock64(cli->tree, fnum, io.readx.in.offset, 1, 0, WRITE_LOCK))) {
+       if (NT_STATUS_IS_ERR(smbcli_lock64(cli->tree, fnum, io.readx.in.offset, 1, 0, WRITE_LOCK))) {
                printf("Failed to lock file at %d\n", __LINE__);
-               ret = False;
+               ret = false;
                goto done;
        }
 
@@ -521,8 +635,8 @@ static BOOL test_readx(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_VALUE(io.readx.out.nread, 0);
 
 done:
-       cli_close(cli->tree, fnum);
-       cli_deltree(cli->tree, BASEDIR);
+       smbcli_close(cli->tree, fnum);
+       smbcli_deltree(cli->tree, BASEDIR);
        return ret;
 }
 
@@ -530,38 +644,42 @@ done:
 /*
   test readbraw ops
 */
-static BOOL test_readbraw(struct cli_state *cli, TALLOC_CTX *mem_ctx)
+static bool test_readbraw(struct torture_context *tctx, 
+                                                 struct smbcli_state *cli)
 {
        union smb_read io;
        NTSTATUS status;
-       BOOL ret = True;
+       bool ret = true;
        int fnum;
-       char *buf;
+       uint8_t *buf;
        const int maxsize = 90000;
        const char *fname = BASEDIR "\\test.txt";
        const char *test_data = "TEST DATA";
        uint_t seed = time(NULL);
 
-       buf = talloc_zero(mem_ctx, maxsize);
+       if (!cli->transport->negotiate.readbraw_supported) {
+               printf("Server does not support readbraw - skipping\n");
+               return true;
+       }
 
-       if (cli_deltree(cli->tree, BASEDIR) == -1 ||
-           NT_STATUS_IS_ERR(cli_mkdir(cli->tree, BASEDIR))) {
-               printf("Unable to setup %s - %s\n", BASEDIR, cli_errstr(cli->tree));
-               return False;
+       buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
        }
 
        printf("Testing RAW_READ_READBRAW\n");
        
-       fnum = cli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
-               printf("Failed to create %s - %s\n", fname, cli_errstr(cli->tree));
-               ret = False;
+               printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
+               ret = false;
                goto done;
        }
 
        printf("Trying empty file read\n");
        io.generic.level = RAW_READ_READBRAW;
-       io.readbraw.in.fnum = fnum;
+       io.readbraw.in.file.fnum = fnum;
        io.readbraw.in.mincnt = 1;
        io.readbraw.in.maxcnt = 1;
        io.readbraw.in.offset = 0;
@@ -580,16 +698,16 @@ static BOOL test_readbraw(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_VALUE(io.readbraw.out.nread, 0);
 
        printf("Trying bad fnum\n");
-       io.readbraw.in.fnum = fnum+1;
+       io.readbraw.in.file.fnum = fnum+1;
        status = smb_raw_read(cli->tree, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(io.readbraw.out.nread, 0);
-       io.readbraw.in.fnum = fnum;
+       io.readbraw.in.file.fnum = fnum;
 
-       cli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
+       smbcli_write(cli->tree, fnum, 0, test_data, 0, strlen(test_data));
 
        printf("Trying small read\n");
-       io.readbraw.in.fnum = fnum;
+       io.readbraw.in.file.fnum = fnum;
        io.readbraw.in.offset = 0;
        io.readbraw.in.mincnt = strlen(test_data);
        io.readbraw.in.maxcnt = strlen(test_data);
@@ -597,7 +715,7 @@ static BOOL test_readbraw(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(io.readbraw.out.nread, strlen(test_data));
        if (memcmp(buf, test_data, strlen(test_data)) != 0) {
-               ret = False;
+               ret = false;
                printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data, buf);
                goto done;
        }
@@ -610,21 +728,23 @@ static BOOL test_readbraw(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(io.readbraw.out.nread, strlen(test_data)-1);
        if (memcmp(buf, test_data+1, strlen(test_data)-1) != 0) {
-               ret = False;
+               ret = false;
                printf("incorrect data at %d!? (%s:%s)\n", __LINE__, test_data+1, buf);
                goto done;
        }
 
-       printf("Trying max offset\n");
-       io.readbraw.in.offset = ~0;
-       io.readbraw.in.mincnt = strlen(test_data);
-       io.readbraw.in.maxcnt = strlen(test_data);
-       status = smb_raw_read(cli->tree, &io);
-       CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_VALUE(io.readbraw.out.nread, 0);
+       if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+               printf("Trying max offset\n");
+               io.readbraw.in.offset = ~0;
+               io.readbraw.in.mincnt = strlen(test_data);
+               io.readbraw.in.maxcnt = strlen(test_data);
+               status = smb_raw_read(cli->tree, &io);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               CHECK_VALUE(io.readbraw.out.nread, 0);
+       }
 
        setup_buffer(buf, seed, maxsize);
-       cli_write(cli->tree, fnum, 0, buf, 0, maxsize);
+       smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
        memset(buf, 0, maxsize);
 
        printf("Trying large read\n");
@@ -658,9 +778,9 @@ static BOOL test_readbraw(struct cli_state *cli, TALLOC_CTX *mem_ctx)
 
        printf("Trying locked region\n");
        cli->session->pid++;
-       if (NT_STATUS_IS_ERR(cli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
+       if (NT_STATUS_IS_ERR(smbcli_lock(cli->tree, fnum, 103, 1, 0, WRITE_LOCK))) {
                printf("Failed to lock file at %d\n", __LINE__);
-               ret = False;
+               ret = false;
                goto done;
        }
        cli->session->pid--;
@@ -682,54 +802,192 @@ static BOOL test_readbraw(struct cli_state *cli, TALLOC_CTX *mem_ctx)
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VALUE(io.readbraw.out.nread, 0);
 
-       printf("Trying large offset read\n");
-       io.readbraw.in.offset = ((uint64_t)0x2) << 32;
-       io.readbraw.in.mincnt = 10;
-       io.readbraw.in.maxcnt = 10;
-       io.readbraw.in.timeout = 0;
-       status = smb_raw_read(cli->tree, &io);
-       CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_VALUE(io.readbraw.out.nread, 0);
+       if (cli->transport->negotiate.capabilities & CAP_LARGE_FILES) {
+               printf("Trying large offset read\n");
+               io.readbraw.in.offset = ((uint64_t)0x2) << 32;
+               io.readbraw.in.mincnt = 10;
+               io.readbraw.in.maxcnt = 10;
+               io.readbraw.in.timeout = 0;
+               status = smb_raw_read(cli->tree, &io);
+               CHECK_STATUS(status, NT_STATUS_OK);
+               CHECK_VALUE(io.readbraw.out.nread, 0);
+       }
 
 done:
-       cli_close(cli->tree, fnum);
-       cli_deltree(cli->tree, BASEDIR);
+       smbcli_close(cli->tree, fnum);
+       smbcli_deltree(cli->tree, BASEDIR);
        return ret;
 }
 
-
-/* 
-   basic testing of read calls
+/*
+  test read for execute
 */
-BOOL torture_raw_read(int dummy)
+static bool test_read_for_execute(struct torture_context *tctx, 
+                                                                 struct smbcli_state *cli)
 {
-       struct cli_state *cli;
-       BOOL ret = True;
-       TALLOC_CTX *mem_ctx;
+       union smb_open op;
+       union smb_write wr;
+       union smb_read rd;
+       NTSTATUS status;
+       bool ret = true;
+       int fnum=0;
+       uint8_t *buf;
+       const int maxsize = 900;
+       const char *fname = BASEDIR "\\test.txt";
+       const uint8_t data[] = "TEST DATA";
 
-       if (!torture_open_connection(&cli)) {
-               return False;
+       buf = talloc_zero_array(tctx, uint8_t, maxsize);
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
        }
 
-       mem_ctx = talloc_init("torture_raw_read");
+       printf("Testing RAW_READ_READX with read_for_execute\n");
+
+       op.generic.level = RAW_OPEN_NTCREATEX;
+       op.ntcreatex.in.root_fid.fnum = 0;
+       op.ntcreatex.in.flags = 0;
+       op.ntcreatex.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+       op.ntcreatex.in.create_options = 0;
+       op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+       op.ntcreatex.in.alloc_size = 0;
+       op.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+       op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       op.ntcreatex.in.security_flags = 0;
+       op.ntcreatex.in.fname = fname;
+       status = smb_raw_open(cli->tree, tctx, &op);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       fnum = op.ntcreatex.out.file.fnum;
+
+       wr.generic.level = RAW_WRITE_WRITEX;
+       wr.writex.in.file.fnum = fnum;
+       wr.writex.in.offset = 0;
+       wr.writex.in.wmode = 0;
+       wr.writex.in.remaining = 0;
+       wr.writex.in.count = ARRAY_SIZE(data);
+       wr.writex.in.data = data;
+       status = smb_raw_write(cli->tree, &wr);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_VALUE(wr.writex.out.nwritten, ARRAY_SIZE(data));
+
+       status = smbcli_close(cli->tree, fnum);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       printf("open file with SEC_FILE_EXECUTE\n");
+       op.generic.level = RAW_OPEN_NTCREATEX;
+       op.ntcreatex.in.root_fid.fnum = 0;
+       op.ntcreatex.in.flags = 0;
+       op.ntcreatex.in.access_mask = SEC_FILE_EXECUTE;
+       op.ntcreatex.in.create_options = 0;
+       op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+       op.ntcreatex.in.alloc_size = 0;
+       op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+       op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       op.ntcreatex.in.security_flags = 0;
+       op.ntcreatex.in.fname = fname;
+       status = smb_raw_open(cli->tree, tctx, &op);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       fnum = op.ntcreatex.out.file.fnum;
+
+       printf("read with FLAGS2_READ_PERMIT_EXECUTE\n");
+       rd.generic.level = RAW_READ_READX;
+       rd.readx.in.file.fnum = fnum;
+       rd.readx.in.mincnt = 0;
+       rd.readx.in.maxcnt = maxsize;
+       rd.readx.in.offset = 0;
+       rd.readx.in.remaining = 0;
+       rd.readx.in.read_for_execute = true;
+       rd.readx.out.data = buf;
+       status = smb_raw_read(cli->tree, &rd);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
+       CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
+       CHECK_VALUE(rd.readx.out.compaction_mode, 0);
+
+       printf("read without FLAGS2_READ_PERMIT_EXECUTE (should fail)\n");
+       rd.generic.level = RAW_READ_READX;
+       rd.readx.in.file.fnum = fnum;
+       rd.readx.in.mincnt = 0;
+       rd.readx.in.maxcnt = maxsize;
+       rd.readx.in.offset = 0;
+       rd.readx.in.remaining = 0;
+       rd.readx.in.read_for_execute = false;
+       rd.readx.out.data = buf;
+       status = smb_raw_read(cli->tree, &rd);
+       CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED);
+
+       status = smbcli_close(cli->tree, fnum);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       printf("open file with SEC_FILE_READ_DATA\n");
+       op.generic.level = RAW_OPEN_NTCREATEX;
+       op.ntcreatex.in.root_fid.fnum = 0;
+       op.ntcreatex.in.flags = 0;
+       op.ntcreatex.in.access_mask = SEC_FILE_READ_DATA;
+       op.ntcreatex.in.create_options = 0;
+       op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+       op.ntcreatex.in.alloc_size = 0;
+       op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+       op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       op.ntcreatex.in.security_flags = 0;
+       op.ntcreatex.in.fname = fname;
+       status = smb_raw_open(cli->tree, tctx, &op);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       fnum = op.ntcreatex.out.file.fnum;
+
+       printf("read with FLAGS2_READ_PERMIT_EXECUTE\n");
+       rd.generic.level = RAW_READ_READX;
+       rd.readx.in.file.fnum = fnum;
+       rd.readx.in.mincnt = 0;
+       rd.readx.in.maxcnt = maxsize;
+       rd.readx.in.offset = 0;
+       rd.readx.in.remaining = 0;
+       rd.readx.in.read_for_execute = true;
+       rd.readx.out.data = buf;
+       status = smb_raw_read(cli->tree, &rd);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
+       CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
+       CHECK_VALUE(rd.readx.out.compaction_mode, 0);
+
+       printf("read without FLAGS2_READ_PERMIT_EXECUTE\n");
+       rd.generic.level = RAW_READ_READX;
+       rd.readx.in.file.fnum = fnum;
+       rd.readx.in.mincnt = 0;
+       rd.readx.in.maxcnt = maxsize;
+       rd.readx.in.offset = 0;
+       rd.readx.in.remaining = 0;
+       rd.readx.in.read_for_execute = false;
+       rd.readx.out.data = buf;
+       status = smb_raw_read(cli->tree, &rd);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_VALUE(rd.readx.out.nread, ARRAY_SIZE(data));
+       CHECK_VALUE(rd.readx.out.remaining, 0xFFFF);
+       CHECK_VALUE(rd.readx.out.compaction_mode, 0);
 
-       if (!test_read(cli, mem_ctx)) {
-               ret = False;
-       }
+done:
+       smbcli_close(cli->tree, fnum);
+       smbcli_deltree(cli->tree, BASEDIR);
+       return ret;
+}
 
-       if (!test_readx(cli, mem_ctx)) {
-               ret = False;
-       }
 
-       if (!test_lockread(cli, mem_ctx)) {
-               ret = False;
-       }
+/* 
+   basic testing of read calls
+*/
+struct torture_suite *torture_raw_read(TALLOC_CTX *mem_ctx)
+{
+       struct torture_suite *suite = torture_suite_create(mem_ctx, "READ");
 
-       if (!test_readbraw(cli, mem_ctx)) {
-               ret = False;
-       }
+       torture_suite_add_1smb_test(suite, "read", test_read);
+       torture_suite_add_1smb_test(suite, "readx", test_readx);
+       torture_suite_add_1smb_test(suite, "lockread", test_lockread);
+       torture_suite_add_1smb_test(suite, "readbraw", test_readbraw);
+       torture_suite_add_1smb_test(suite, "read for execute", 
+                                                               test_read_for_execute);
 
-       torture_close_connection(cli);
-       talloc_destroy(mem_ctx);
-       return ret;
+       return suite;
 }