s4 torture: Add lockread_supported based off of CAP_LOCK_AND_READ
[samba.git] / source4 / torture / raw / read.c
index afec805cd497bb8b243b0d6c9bc559816d66245e..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 smbcli_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 (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
-           NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
-               printf("Unable to setup %s - %s\n", BASEDIR, smbcli_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 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
                printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
-               ret = False;
+               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 smbcli_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;
 
        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 smbcli_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,17 +159,19 @@ static BOOL test_read(struct smbcli_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);
        smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
@@ -180,7 +189,7 @@ static BOOL test_read(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        cli->session->pid++;
        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--;
@@ -202,24 +211,28 @@ done:
 /*
   test lockread ops
 */
-static BOOL test_lockread(struct smbcli_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 (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
-           NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
-               printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree));
-               return False;
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
        }
 
        printf("Testing RAW_READ_LOCKREAD\n");
@@ -228,14 +241,14 @@ static BOOL test_lockread(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
                printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
-               ret = False;
+               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 smbcli_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;
 
        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);
 
-       smbcli_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;
        }
@@ -292,17 +307,19 @@ static BOOL test_lockread(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        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);
        smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
@@ -324,7 +341,7 @@ static BOOL test_lockread(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        cli->session->pid++;
        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--;
@@ -345,24 +362,22 @@ done:
 /*
   test readx ops
 */
-static BOOL test_readx(struct smbcli_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 (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
-           NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
-               printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree));
-               return False;
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
        }
 
        printf("Testing RAW_READ_READX\n");
@@ -370,17 +385,18 @@ static BOOL test_readx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
                printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
-               ret = False;
+               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 smbcli_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;
 
        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 smbcli_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 smbcli_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);
        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 smbcli_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 smbcli_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(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 smbcli_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;
@@ -512,7 +626,7 @@ static BOOL test_readx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        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;
        }
 
@@ -530,24 +644,28 @@ done:
 /*
   test readbraw ops
 */
-static BOOL test_readbraw(struct smbcli_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;
+       }
+
+       buf = talloc_zero_array(tctx, uint8_t, maxsize);
 
-       if (smbcli_deltree(cli->tree, BASEDIR) == -1 ||
-           NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, BASEDIR))) {
-               printf("Unable to setup %s - %s\n", BASEDIR, smbcli_errstr(cli->tree));
-               return False;
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
        }
 
        printf("Testing RAW_READ_READBRAW\n");
@@ -555,13 +673,13 @@ static BOOL test_readbraw(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum == -1) {
                printf("Failed to create %s - %s\n", fname, smbcli_errstr(cli->tree));
-               ret = False;
+               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 smbcli_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;
 
        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 smbcli_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,18 +728,20 @@ static BOOL test_readbraw(struct smbcli_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);
        smbcli_write(cli->tree, fnum, 0, buf, 0, maxsize);
@@ -660,7 +780,7 @@ static BOOL test_readbraw(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        cli->session->pid++;
        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,14 +802,16 @@ static BOOL test_readbraw(struct smbcli_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:
        smbcli_close(cli->tree, fnum);
@@ -697,39 +819,175 @@ done:
        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 smbcli_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";
+
+       buf = talloc_zero_array(tctx, uint8_t, maxsize);
 
-       if (!torture_open_connection(&cli)) {
-               return False;
+       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;
 }