r25430: Add the loadparm context to all parametric options.
[jelmer/samba4-debian.git] / source / torture / raw / open.c
index 17a7f18505abc5b1d7722ab6b9c5e99ce9b90512..c75d8f6bfc18d0e04b791581164db6e4c6add5b7 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 "torture/torture.h"
 #include "libcli/raw/libcliraw.h"
 #include "system/time.h"
-#include "librpc/gen_ndr/ndr_security.h"
+#include "system/filesys.h"
+#include "librpc/gen_ndr/security.h"
+#include "lib/events/events.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "auth/credentials/credentials.h"
+#include "lib/cmdline/popt_common.h"
+#include "param/param.h"
 
 /* enum for whether reads/writes are possible on a file */
 enum rdwr_mode {RDWR_NONE, RDWR_RDONLY, RDWR_WRONLY, RDWR_RDWR};
@@ -83,12 +90,12 @@ static const char *rdwr_string(enum rdwr_mode m)
 #define CHECK_TIME(t, field) do { \
        time_t t1, t2; \
        finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
-       finfo.all_info.in.fname = fname; \
+       finfo.all_info.in.file.path = fname; \
        status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
        CHECK_STATUS(status, NT_STATUS_OK); \
        t1 = t & ~1; \
        t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
-       if (ABS(t1-t2) > 2) { \
+       if (abs(t1-t2) > 2) { \
                printf("(%s) wrong time for field %s  %s - %s\n", \
                       __location__, #field, \
                       timestring(mem_ctx, t1), \
@@ -100,7 +107,7 @@ static const char *rdwr_string(enum rdwr_mode m)
 #define CHECK_NTTIME(t, field) do { \
        NTTIME t2; \
        finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
-       finfo.all_info.in.fname = fname; \
+       finfo.all_info.in.file.path = fname; \
        status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
        CHECK_STATUS(status, NT_STATUS_OK); \
        t2 = finfo.all_info.out.field; \
@@ -115,7 +122,7 @@ static const char *rdwr_string(enum rdwr_mode m)
 
 #define CHECK_ALL_INFO(v, field) do { \
        finfo.all_info.level = RAW_FILEINFO_ALL_INFO; \
-       finfo.all_info.in.fname = fname; \
+       finfo.all_info.in.file.path = fname; \
        status = smb_raw_pathinfo(cli->tree, mem_ctx, &finfo); \
        CHECK_STATUS(status, NT_STATUS_OK); \
        if ((v) != (finfo.all_info.out.field)) { \
@@ -134,9 +141,9 @@ static const char *rdwr_string(enum rdwr_mode m)
 
 #define SET_ATTRIB(sattrib) do { \
        union smb_setfileinfo sfinfo; \
-       sfinfo.generic.level = RAW_SFILEINFO_BASIC_INFORMATION; \
-       sfinfo.generic.file.fname = fname; \
        ZERO_STRUCT(sfinfo.basic_info.in); \
+       sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; \
+       sfinfo.basic_info.in.file.path = fname; \
        sfinfo.basic_info.in.attrib = sattrib; \
        status = smb_raw_setpathinfo(cli->tree, &sfinfo); \
        if (!NT_STATUS_IS_OK(status)) { \
@@ -164,7 +171,7 @@ static BOOL test_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openold.in.search_attrs = 0;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
-       fnum = io.openold.out.fnum;
+       fnum = io.openold.out.file.fnum;
 
        smbcli_unlink(cli->tree, fname);
        CREATE_FILE;
@@ -172,12 +179,12 @@ static BOOL test_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openold.out.fnum;
+       fnum = io.openold.out.file.fnum;
        CHECK_RDWR(fnum, RDWR_RDWR);
 
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum2 = io.openold.out.fnum;
+       fnum2 = io.openold.out.file.fnum;
        CHECK_RDWR(fnum2, RDWR_RDWR);
        smbcli_close(cli->tree, fnum2);
        smbcli_close(cli->tree, fnum);
@@ -190,21 +197,21 @@ static BOOL test_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openold.in.open_mode = OPEN_FLAGS_OPEN_READ;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openold.out.fnum;
+       fnum = io.openold.out.file.fnum;
        CHECK_RDWR(fnum, RDWR_RDONLY);
        smbcli_close(cli->tree, fnum);
 
        io.openold.in.open_mode = OPEN_FLAGS_OPEN_WRITE;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openold.out.fnum;
+       fnum = io.openold.out.file.fnum;
        CHECK_RDWR(fnum, RDWR_WRONLY);
        smbcli_close(cli->tree, fnum);
 
        io.openold.in.open_mode = OPEN_FLAGS_OPEN_RDWR;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openold.out.fnum;
+       fnum = io.openold.out.file.fnum;
        CHECK_RDWR(fnum, RDWR_RDWR);
        smbcli_close(cli->tree, fnum);
 
@@ -212,7 +219,7 @@ static BOOL test_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openold.in.open_mode = OPEN_FLAGS_OPEN_RDWR | OPEN_FLAGS_DENY_WRITE;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openold.out.fnum;
+       fnum = io.openold.out.file.fnum;
        CHECK_RDWR(fnum, RDWR_RDWR);
        
        if (io.openold.in.open_mode != io.openold.out.rmode) {
@@ -227,7 +234,7 @@ static BOOL test_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openold.in.open_mode = OPEN_FLAGS_OPEN_READ | OPEN_FLAGS_DENY_NONE;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum2 = io.openold.out.fnum;
+       fnum2 = io.openold.out.file.fnum;
        CHECK_RDWR(fnum2, RDWR_RDONLY);
        smbcli_close(cli->tree, fnum);
        smbcli_close(cli->tree, fnum2);
@@ -240,7 +247,7 @@ static BOOL test_open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openold.in.open_mode = OPEN_FLAGS_OPEN_READ;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openold.out.fnum;
+       fnum = io.openold.out.file.fnum;
 
        /* check other reply fields */
        CHECK_TIME(io.openold.out.write_time, write_time);
@@ -263,6 +270,7 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        union smb_open io;
        union smb_fileinfo finfo;
        const char *fname = BASEDIR "\\torture_openx.txt";
+       const char *fname_exe = BASEDIR "\\torture_openx.exe";
        NTSTATUS status;
        int fnum = -1, fnum2;
        BOOL ret = True;
@@ -277,8 +285,8 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
                { OPENX_OPEN_FUNC_OPEN,                           False, NT_STATUS_OBJECT_NAME_NOT_FOUND },
                { OPENX_OPEN_FUNC_OPEN  | OPENX_OPEN_FUNC_CREATE, True,  NT_STATUS_OK },
                { OPENX_OPEN_FUNC_OPEN  | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
-               { OPENX_OPEN_FUNC_FAIL,                           True,  NT_STATUS_INVALID_LOCK_SEQUENCE },
-               { OPENX_OPEN_FUNC_FAIL,                           False, NT_STATUS_INVALID_LOCK_SEQUENCE },
+               { OPENX_OPEN_FUNC_FAIL,                           True,  NT_STATUS_DOS(ERRDOS, ERRbadaccess) },
+               { OPENX_OPEN_FUNC_FAIL,                           False, NT_STATUS_DOS(ERRDOS, ERRbadaccess) },
                { OPENX_OPEN_FUNC_FAIL  | OPENX_OPEN_FUNC_CREATE, True,  NT_STATUS_OBJECT_NAME_COLLISION },
                { OPENX_OPEN_FUNC_FAIL  | OPENX_OPEN_FUNC_CREATE, False, NT_STATUS_OK },
                { OPENX_OPEN_FUNC_TRUNC,                          True,  NT_STATUS_OK },
@@ -320,7 +328,7 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
                        ret = False;
                }
                if (NT_STATUS_IS_OK(status)) {
-                       smbcli_close(cli->tree, io.openx.out.fnum);
+                       smbcli_close(cli->tree, io.openx.out.file.fnum);
                }
                if (open_funcs[i].with_file) {
                        smbcli_unlink(cli->tree, fname);
@@ -333,7 +341,7 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN | OPENX_OPEN_FUNC_CREATE;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openx.out.fnum;
+       fnum = io.openx.out.file.fnum;
 
        CHECK_ALL_INFO(io.openx.out.size, size);
        CHECK_TIME(io.openx.out.write_time, write_time);
@@ -358,7 +366,7 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openx.out.fnum;
+       fnum = io.openx.out.file.fnum;
 
        CHECK_ALL_INFO(io.openx.out.size, size);
        CHECK_TIME(io.openx.out.write_time, write_time);
@@ -374,12 +382,12 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openx.in.search_attrs = FILE_ATTRIBUTE_HIDDEN;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       smbcli_close(cli->tree, io.openx.out.fnum);
+       smbcli_close(cli->tree, io.openx.out.file.fnum);
 
        io.openx.in.search_attrs = 0;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       smbcli_close(cli->tree, io.openx.out.fnum);
+       smbcli_close(cli->tree, io.openx.out.file.fnum);
 
        SET_ATTRIB(FILE_ATTRIBUTE_NORMAL);
        smbcli_unlink(cli->tree, fname);
@@ -390,9 +398,16 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openx.in.file_attrs = FILE_ATTRIBUTE_SYSTEM;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       CHECK_ALL_INFO(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE, 
-                      attrib & ~FILE_ATTRIBUTE_NONINDEXED);
-       smbcli_close(cli->tree, io.openx.out.fnum);
+       if (lp_parm_bool(global_loadparm, NULL, "torture", "samba3", false)) {
+               CHECK_ALL_INFO(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE, 
+                              attrib & ~(FILE_ATTRIBUTE_NONINDEXED|
+                                         FILE_ATTRIBUTE_SPARSE));
+       }
+       else {
+               CHECK_ALL_INFO(FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE, 
+                              attrib & ~(FILE_ATTRIBUTE_NONINDEXED));
+       }
+       smbcli_close(cli->tree, io.openx.out.file.fnum);
        smbcli_unlink(cli->tree, fname);
 
        /* check timeout on create - win2003 ignores the timeout! */
@@ -401,7 +416,7 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR | OPENX_MODE_DENY_ALL;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openx.out.fnum;
+       fnum = io.openx.out.file.fnum;
 
        io.openx.in.timeout = 20000;
        tv = timeval_current();
@@ -428,7 +443,7 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openx.in.timeout = 0;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       smbcli_close(cli->tree, io.openx.out.fnum);
+       smbcli_close(cli->tree, io.openx.out.file.fnum);
 
        /* check the extended return flag */
        io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO | OPENX_FLAGS_EXTENDED_RETURN;
@@ -436,14 +451,39 @@ static BOOL test_openx(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
        CHECK_VAL(io.openx.out.access_mask, SEC_STD_ALL);
-       smbcli_close(cli->tree, io.openx.out.fnum);
+       smbcli_close(cli->tree, io.openx.out.file.fnum);
 
        io.openx.in.fname = "\\A.+,;=[].B";
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_NOT_FOUND);
 
+       /* Check the mapping for open exec. */
+
+       /* First create an .exe file. */
+       smbcli_unlink(cli->tree, fname_exe);
+       fnum = create_complex_file(cli, mem_ctx, fname_exe);
+       smbcli_close(cli->tree, fnum);
+
+       io.openx.level = RAW_OPEN_OPENX;
+       io.openx.in.fname = fname_exe;
+       io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+       io.openx.in.open_mode = OPENX_MODE_ACCESS_EXEC | OPENX_MODE_DENY_NONE;
+       io.openx.in.search_attrs = 0;
+       io.openx.in.file_attrs = 0;
+       io.openx.in.write_time = 0;
+       io.openx.in.size = 0;
+       io.openx.in.timeout = 0;
+       status = smb_raw_open(cli->tree, mem_ctx, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       /* Can we read and write ? */
+       CHECK_RDWR(io.openx.out.file.fnum, RDWR_RDONLY);
+       smbcli_close(cli->tree, io.openx.out.file.fnum);
+       smbcli_unlink(cli->tree, fname);
+
 done:
        smbcli_close(cli->tree, fnum);
+       smbcli_unlink(cli->tree, fname_exe);
        smbcli_unlink(cli->tree, fname);
 
        return ret;
@@ -519,6 +559,7 @@ static BOOL test_t2open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        /* check all combinations of open_func */
        for (i=0; i<ARRAY_SIZE(open_funcs); i++) {
+       again:
                if (open_funcs[i].with_file) {
                        io.t2open.in.fname = fname1;
                } else {
@@ -526,6 +567,15 @@ static BOOL test_t2open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
                }
                io.t2open.in.open_func = open_funcs[i].open_func;
                status = smb_raw_open(cli->tree, mem_ctx, &io);
+               if ((io.t2open.in.num_eas != 0)
+                   && NT_STATUS_EQUAL(status, NT_STATUS_EAS_NOT_SUPPORTED)
+                   && lp_parm_bool(global_loadparm, NULL, "torture", "samba3", false)) {
+                       printf("(%s) EAs not supported, not treating as fatal "
+                              "in Samba3 test\n", __location__);
+                       io.t2open.in.num_eas = 0;
+                       goto again;
+               }
+
                if (!NT_STATUS_EQUAL(status, open_funcs[i].correct_status)) {
                        printf("(%s) incorrect status %s should be %s (i=%d with_file=%d open_func=0x%x)\n", 
                               __location__, nt_errstr(status), nt_errstr(open_funcs[i].correct_status),
@@ -533,7 +583,7 @@ static BOOL test_t2open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
                        ret = False;
                }
                if (NT_STATUS_IS_OK(status)) {
-                       smbcli_close(cli->tree, io.t2open.out.fnum);
+                       smbcli_close(cli->tree, io.t2open.out.file.fnum);
                }
        }
 
@@ -546,7 +596,7 @@ static BOOL test_t2open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.t2open.in.fname = fname;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.t2open.out.fnum;
+       fnum = io.t2open.out.file.fnum;
 
        CHECK_ALL_INFO(io.t2open.out.size, size);
 #if 0
@@ -561,11 +611,14 @@ static BOOL test_t2open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        smbcli_close(cli->tree, fnum);
 
        status = torture_check_ea(cli, fname, ".CLASSINFO", "first value");
-       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_STATUS(status, io.t2open.in.num_eas
+                    ? NT_STATUS_OK : NT_STATUS_EAS_NOT_SUPPORTED);
        status = torture_check_ea(cli, fname, "EA TWO", "foo");
-       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_STATUS(status, io.t2open.in.num_eas
+                    ? NT_STATUS_OK : NT_STATUS_EAS_NOT_SUPPORTED);
        status = torture_check_ea(cli, fname, "X THIRD", "xy");
-       CHECK_STATUS(status, NT_STATUS_OK);
+       CHECK_STATUS(status, io.t2open.in.num_eas
+                    ? NT_STATUS_OK : NT_STATUS_EAS_NOT_SUPPORTED);
 
        /* now check the search attrib for hidden files - win2003 ignores this? */
        SET_ATTRIB(FILE_ATTRIBUTE_HIDDEN);
@@ -573,11 +626,11 @@ static BOOL test_t2open(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       smbcli_close(cli->tree, io.t2open.out.fnum);
+       smbcli_close(cli->tree, io.t2open.out.file.fnum);
 
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       smbcli_close(cli->tree, io.t2open.out.fnum);
+       smbcli_close(cli->tree, io.t2open.out.file.fnum);
 
        SET_ATTRIB(FILE_ATTRIBUTE_NORMAL);
        smbcli_unlink(cli->tree, fname);
@@ -674,7 +727,7 @@ static BOOL test_ntcreatex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
                        ret = False;
                }
                if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
-                       smbcli_close(cli->tree, io.ntcreatex.out.fnum);
+                       smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
                        smbcli_unlink(cli->tree, fname);
                }
        }
@@ -684,7 +737,7 @@ static BOOL test_ntcreatex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.ntcreatex.out.fnum;
+       fnum = io.ntcreatex.out.file.fnum;
 
        CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
        CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
@@ -711,7 +764,7 @@ static BOOL test_ntcreatex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.ntcreatex.out.fnum;
+       fnum = io.ntcreatex.out.file.fnum;
 
        CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
        CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
@@ -748,7 +801,7 @@ static BOOL test_ntcreatex(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.ntcreatex.out.fnum;
+       fnum = io.ntcreatex.out.file.fnum;
 
        CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
        CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
@@ -849,7 +902,7 @@ static BOOL test_nttrans_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
                        ret = False;
                }
                if (NT_STATUS_IS_OK(status) || open_funcs[i].with_file) {
-                       smbcli_close(cli->tree, io.ntcreatex.out.fnum);
+                       smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
                        smbcli_unlink(cli->tree, fname);
                }
        }
@@ -859,7 +912,7 @@ static BOOL test_nttrans_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
 
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.ntcreatex.out.fnum;
+       fnum = io.ntcreatex.out.file.fnum;
 
        CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
        CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
@@ -886,7 +939,7 @@ static BOOL test_nttrans_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.ntcreatex.out.fnum;
+       fnum = io.ntcreatex.out.file.fnum;
 
        CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
        CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_EXISTED);
@@ -923,7 +976,7 @@ static BOOL test_nttrans_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.ntcreatex.out.fnum;
+       fnum = io.ntcreatex.out.file.fnum;
 
        CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
        CHECK_VAL(io.ntcreatex.out.create_action, NTCREATEX_ACTION_CREATED);
@@ -968,7 +1021,8 @@ static BOOL test_ntcreatex_brlocked(struct smbcli_state *cli, TALLOC_CTX *mem_ct
        NTSTATUS status;
        BOOL ret = True;
 
-       /* reasonable default parameters */
+       printf("Testing ntcreatex with a byte range locked file\n");
+
        io.generic.level = RAW_OPEN_NTCREATEX;
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
        io.ntcreatex.in.root_fid = 0;
@@ -988,7 +1042,7 @@ static BOOL test_ntcreatex_brlocked(struct smbcli_state *cli, TALLOC_CTX *mem_ct
        CHECK_STATUS(status, NT_STATUS_OK);
 
        io2.lockx.level = RAW_LOCK_LOCKX;
-       io2.lockx.in.fnum = io.ntcreatex.out.fnum;
+       io2.lockx.in.file.fnum = io.ntcreatex.out.file.fnum;
        io2.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
        io2.lockx.in.timeout = 0;
        io2.lockx.in.ulock_cnt = 0;
@@ -1019,8 +1073,8 @@ static BOOL test_ntcreatex_brlocked(struct smbcli_state *cli, TALLOC_CTX *mem_ct
        CHECK_STATUS(status, NT_STATUS_OK);
 
  done:
-       smbcli_close(cli->tree, io.ntcreatex.out.fnum);
-       smbcli_close(cli->tree, io1.ntcreatex.out.fnum);
+       smbcli_close(cli->tree, io.ntcreatex.out.file.fnum);
+       smbcli_close(cli->tree, io1.ntcreatex.out.file.fnum);
        smbcli_unlink(cli->tree, fname);
        return ret;
 }
@@ -1046,7 +1100,7 @@ static BOOL test_mknew(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.mknew.in.fname = fname;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.mknew.out.fnum;
+       fnum = io.mknew.out.file.fnum;
 
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OBJECT_NAME_COLLISION);
@@ -1058,7 +1112,7 @@ static BOOL test_mknew(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.mknew.in.write_time = basetime;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.mknew.out.fnum;
+       fnum = io.mknew.out.file.fnum;
        CHECK_TIME(basetime, write_time);
 
        smbcli_close(cli->tree, fnum);
@@ -1068,7 +1122,7 @@ static BOOL test_mknew(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.mknew.in.attrib = FILE_ATTRIBUTE_HIDDEN;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.mknew.out.fnum;
+       fnum = io.mknew.out.file.fnum;
        CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE, 
                       attrib & ~FILE_ATTRIBUTE_NONINDEXED);
        
@@ -1101,12 +1155,12 @@ static BOOL test_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.create.in.fname = fname;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.create.out.fnum;
+       fnum = io.create.out.file.fnum;
 
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
 
-       smbcli_close(cli->tree, io.create.out.fnum);
+       smbcli_close(cli->tree, io.create.out.file.fnum);
        smbcli_close(cli->tree, fnum);
        smbcli_unlink(cli->tree, fname);
 
@@ -1114,7 +1168,7 @@ static BOOL test_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.create.in.write_time = basetime;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.create.out.fnum;
+       fnum = io.create.out.file.fnum;
        CHECK_TIME(basetime, write_time);
 
        smbcli_close(cli->tree, fnum);
@@ -1124,7 +1178,7 @@ static BOOL test_create(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.create.in.attrib = FILE_ATTRIBUTE_HIDDEN;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.create.out.fnum;
+       fnum = io.create.out.file.fnum;
        CHECK_ALL_INFO(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE, 
                       attrib & ~FILE_ATTRIBUTE_NONINDEXED);
        
@@ -1157,12 +1211,12 @@ static BOOL test_ctemp(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.ctemp.in.directory = BASEDIR;
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.ctemp.out.fnum;
+       fnum = io.ctemp.out.file.fnum;
 
        name = io.ctemp.out.name;
 
        finfo.generic.level = RAW_FILEINFO_NAME_INFO;
-       finfo.generic.in.fnum = fnum;
+       finfo.generic.in.file.fnum = fnum;
        status = smb_raw_fileinfo(cli->tree, mem_ctx, &finfo);
        CHECK_STATUS(status, NT_STATUS_OK);
 
@@ -1216,11 +1270,11 @@ static BOOL test_chained(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
        io.openxreadx.in.mincnt = sizeof(buf);
        io.openxreadx.in.maxcnt = sizeof(buf);
        io.openxreadx.in.remaining = 0;
-       io.openxreadx.out.data = buf2;
+       io.openxreadx.out.data = (uint8_t *)buf2;
 
        status = smb_raw_open(cli->tree, mem_ctx, &io);
        CHECK_STATUS(status, NT_STATUS_OK);
-       fnum = io.openxreadx.out.fnum;
+       fnum = io.openxreadx.out.file.fnum;
 
        if (memcmp(buf, buf2, sizeof(buf)) != 0) {
                d_printf("wrong data in reply buffer\n");
@@ -1234,40 +1288,201 @@ done:
        return ret;
 }
 
-
-/* basic testing of all RAW_OPEN_* calls 
+/*
+  test RAW_OPEN_OPENX without a leading slash on the path.
+  NetApp filers are known to fail on this.
+  
 */
-BOOL torture_raw_open(void)
+static BOOL test_no_leading_slash(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
+{
+       union smb_open io;
+       const char *fname = BASEDIR "\\torture_no_leading_slash.txt";
+       NTSTATUS status;
+       int fnum = -1;
+       BOOL ret = True;
+       const char *buf = "test";
+
+       printf("Checking RAW_OPEN_OPENX without leading slash on path\n");
+       smbcli_unlink(cli->tree, fname);
+
+        /* Create the file */
+       fnum = create_complex_file(cli, mem_ctx, fname);
+       smbcli_write(cli->tree, fnum, 0, buf, 0, sizeof(buf));
+       smbcli_close(cli->tree, fnum);  
+
+        /* Prepare to open the file using path without leading slash */
+       io.openx.level = RAW_OPEN_OPENX;
+       io.openx.in.fname = fname + 1;
+       io.openx.in.flags = OPENX_FLAGS_ADDITIONAL_INFO;
+       io.openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
+       io.openx.in.open_func = OPENX_OPEN_FUNC_OPEN;
+       io.openx.in.search_attrs = 0;
+       io.openx.in.file_attrs = 0;
+       io.openx.in.write_time = 0;
+       io.openx.in.size = 1024*1024;
+       io.openx.in.timeout = 0;
+
+       status = smb_raw_open(cli->tree, mem_ctx, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       fnum = io.openx.out.file.fnum;
+
+done:
+       smbcli_close(cli->tree, fnum);
+       smbcli_unlink(cli->tree, fname);
+
+       return ret;
+}
+
+/* A little torture test to expose a race condition in Samba 3.0.20 ... :-) */
+
+static BOOL test_raw_open_multi(void)
 {
        struct smbcli_state *cli;
+       TALLOC_CTX *mem_ctx = talloc_init("torture_test_oplock_multi");
+       const char *fname = "\\test_oplock.dat";
+       NTSTATUS status;
        BOOL ret = True;
-       TALLOC_CTX *mem_ctx;
+       union smb_open io;
+       struct smbcli_state **clients;
+       struct smbcli_request **requests;
+       union smb_open *ios;
+       const char *host = lp_parm_string(global_loadparm, NULL, "torture", "host");
+       const char *share = lp_parm_string(global_loadparm, NULL, "torture", "share");
+       int i, num_files = 3;
+       struct event_context *ev;
+       int num_ok = 0;
+       int num_collision = 0;
+       
+       ev = cli_credentials_get_event_context(cmdline_credentials);
+       clients = talloc_array(mem_ctx, struct smbcli_state *, num_files);
+       requests = talloc_array(mem_ctx, struct smbcli_request *, num_files);
+       ios = talloc_array(mem_ctx, union smb_open, num_files);
+       if ((ev == NULL) || (clients == NULL) || (requests == NULL) ||
+           (ios == NULL)) {
+               DEBUG(0, ("talloc failed\n"));
+               return False;
+       }
 
-       if (!torture_open_connection(&cli)) {
+       if (!torture_open_connection_share(mem_ctx, &cli, host, share, ev)) {
                return False;
        }
 
-       mem_ctx = talloc_init("torture_raw_open");
+       cli->tree->session->transport->options.request_timeout = 60000;
+
+       for (i=0; i<num_files; i++) {
+               if (!torture_open_connection_share(mem_ctx, &(clients[i]),
+                                                  host, share, ev)) {
+                       DEBUG(0, ("Could not open %d'th connection\n", i));
+                       return False;
+               }
+               clients[i]->tree->session->transport->
+                       options.request_timeout = 60000;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli->tree, fname);
+
+       /*
+         base ntcreatex parms
+       */
+       io.generic.level = RAW_OPEN_NTCREATEX;
+       io.ntcreatex.in.root_fid = 0;
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       io.ntcreatex.in.alloc_size = 0;
+       io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+       io.ntcreatex.in.flags = 0;
+
+       for (i=0; i<num_files; i++) {
+               ios[i] = io;
+               requests[i] = smb_raw_open_send(clients[i]->tree, &ios[i]);
+               if (requests[i] == NULL) {
+                       DEBUG(0, ("could not send %d'th request\n", i));
+                       return False;
+               }
+       }
+
+       DEBUG(10, ("waiting for replies\n"));
+       while (1) {
+               BOOL unreplied = False;
+               for (i=0; i<num_files; i++) {
+                       if (requests[i] == NULL) {
+                               continue;
+                       }
+                       if (requests[i]->state < SMBCLI_REQUEST_DONE) {
+                               unreplied = True;
+                               break;
+                       }
+                       status = smb_raw_open_recv(requests[i], mem_ctx,
+                                                  &ios[i]);
+
+                       DEBUG(0, ("File %d returned status %s\n", i,
+                                 nt_errstr(status)));
+
+                       if (NT_STATUS_IS_OK(status)) {
+                               num_ok += 1;
+                       } 
+
+                       if (NT_STATUS_EQUAL(status,
+                                           NT_STATUS_OBJECT_NAME_COLLISION)) {
+                               num_collision += 1;
+                       }
+
+                       requests[i] = NULL;
+               }
+               if (!unreplied) {
+                       break;
+               }
+
+               if (event_loop_once(ev) != 0) {
+                       DEBUG(0, ("event_loop_once failed\n"));
+                       return False;
+               }
+       }
+
+       if ((num_ok != 1) || (num_ok + num_collision != num_files)) {
+               ret = False;
+       }
+
+       for (i=0; i<num_files; i++) {
+               torture_close_connection(clients[i]);
+       }
+       talloc_free(mem_ctx);
+       return ret;
+}
+
+/* basic testing of all RAW_OPEN_* calls 
+*/
+bool torture_raw_open(struct torture_context *torture, struct smbcli_state *cli)
+{
+       bool ret = true;
 
        if (!torture_setup_dir(cli, BASEDIR)) {
-               return False;
+               return false;
        }
 
-       ret &= test_ntcreatex_brlocked(cli, mem_ctx);
-       ret &= test_open(cli, mem_ctx);
-       ret &= test_openx(cli, mem_ctx);
-       ret &= test_ntcreatex(cli, mem_ctx);
-       ret &= test_nttrans_create(cli, mem_ctx);
-       ret &= test_t2open(cli, mem_ctx);
-       ret &= test_mknew(cli, mem_ctx);
-       ret &= test_create(cli, mem_ctx);
-       ret &= test_ctemp(cli, mem_ctx);
-       ret &= test_chained(cli, mem_ctx);
+       ret &= test_ntcreatex_brlocked(cli, torture);
+       ret &= test_open(cli, torture);
+       ret &= test_raw_open_multi();
+       ret &= test_openx(cli, torture);
+       ret &= test_ntcreatex(cli, torture);
+       ret &= test_nttrans_create(cli, torture);
+       ret &= test_t2open(cli, torture);
+       ret &= test_mknew(cli, torture);
+       ret &= test_create(cli, torture);
+       ret &= test_ctemp(cli, torture);
+       ret &= test_chained(cli, torture);
+       ret &= test_no_leading_slash(cli, torture);
 
        smb_raw_exit(cli->session);
        smbcli_deltree(cli->tree, BASEDIR);
 
-       torture_close_connection(cli);
-       talloc_free(mem_ctx);
        return ret;
 }