Merge branch 'v4-0-test' of git://git.samba.org/samba into 4-0-local
authorAndrew Bartlett <abartlet@samba.org>
Wed, 27 Feb 2008 23:33:54 +0000 (10:33 +1100)
committerAndrew Bartlett <abartlet@samba.org>
Wed, 27 Feb 2008 23:33:54 +0000 (10:33 +1100)
(This used to be commit ba864cfd7ce4b69179431131cac9661cbf48bf32)

38 files changed:
source4/build/smb_build/makefile.pm
source4/cluster/ctdb/opendb_ctdb.c
source4/lib/replace/Makefile.in
source4/lib/replace/configure.ac
source4/lib/replace/getifaddrs.m4
source4/lib/replace/libreplace.m4
source4/lib/replace/replace.h
source4/lib/replace/socket.c [new file with mode: 0644]
source4/lib/replace/socket.m4 [new file with mode: 0644]
source4/lib/replace/system/network.h
source4/librpc/idl/unixinfo.idl
source4/ntvfs/common/opendb.c
source4/ntvfs/common/opendb.h
source4/ntvfs/common/opendb_tdb.c
source4/ntvfs/posix/config.mk
source4/ntvfs/posix/pvfs_lock.c
source4/ntvfs/posix/pvfs_open.c
source4/ntvfs/posix/pvfs_oplock.c [new file with mode: 0644]
source4/ntvfs/posix/pvfs_qfileinfo.c
source4/ntvfs/posix/pvfs_rename.c
source4/ntvfs/posix/pvfs_setfileinfo.c
source4/ntvfs/posix/pvfs_unlink.c
source4/ntvfs/posix/pvfs_write.c
source4/ntvfs/posix/vfs_posix.c
source4/ntvfs/posix/vfs_posix.h
source4/param/share.c
source4/param/share_classic.c
source4/param/share_ldb.c
source4/pidl/idl.yp
source4/pidl/lib/Parse/Pidl/IDL.pm
source4/rules.mk
source4/samba4-knownfail
source4/samba4-skip
source4/selftest/target/Samba4.pm
source4/setup/provision.reg
source4/smbd/service_stream.c
source4/torture/basic/base.c
source4/torture/raw/oplock.c

index 17474db00ecdabade885b1976e445f21e0548a35..29da771353b1b9f0d0cc3e97f9ab9d5e54b1fa93 100644 (file)
@@ -281,16 +281,7 @@ sub StaticLibrary($$)
        $self->output("$ctx->{NAME}_OUTPUT = $ctx->{OUTPUT}\n");
        $self->_prepare_list($ctx, "FULL_OBJ_LIST");
 
-       $self->output(<< "__EOD__"
-#
-$ctx->{RESULT_STATIC_LIBRARY}: \$($ctx->{NAME}_FULL_OBJ_LIST)
-       \@echo Linking \$@
-       \@rm -f \$@
-       \@mkdir -p $ctx->{STATICDIR}
-       \@\$(STLD) \$(STLD_FLAGS) \$@ \$($ctx->{NAME}_FULL_OBJ_LIST)
-
-__EOD__
-);
+       $self->output("$ctx->{RESULT_STATIC_LIBRARY}: \$($ctx->{NAME}_FULL_OBJ_LIST)\n");
 }
 
 sub Header($$)
index 86dc1f50f11c6fd18d8aef6fd247c00a931adafd..3dfc6819b7c09bbdcd02da250cc6305e43a6fed7 100644 (file)
@@ -279,11 +279,13 @@ static NTSTATUS odb_oplock_break_send(struct odb_context *odb, struct opendb_ent
   Note that the path is only used by the delete on close logic, not
   for comparing with other filenames
 */
-static NTSTATUS odb_ctdb_open_file(struct odb_lock *lck, void *file_handle,
-                                 uint32_t stream_id, uint32_t share_access, 
-                                 uint32_t access_mask, bool delete_on_close,
-                                 const char *path, 
-                                 uint32_t oplock_level, uint32_t *oplock_granted)
+static NTSTATUS odb_ctdb_open_file(struct odb_lock *lck,
+                                  void *file_handle, const char *path,
+                                  uint32_t stream_id, uint32_t share_access,
+                                  uint32_t access_mask, bool delete_on_close,
+                                  uint32_t open_disposition, bool break_to_none,
+                                  uint32_t oplock_level, uint32_t *oplock_granted)
+
 {
        struct odb_context *odb = lck->odb;
        struct opendb_entry e;
@@ -464,6 +466,16 @@ static NTSTATUS odb_ctdb_update_oplock(struct odb_lock *lck, void *file_handle,
        return NT_STATUS_FOOBAR;
 }
 
+static NTSTATUS odb_ctdb_break_oplocks(struct odb_lock *lck)
+{
+       /*
+        * as this file will went away and isn't used yet,
+        * copy the implementation from the tdb backend
+        * --metze
+        */
+       return NT_STATUS_FOOBAR;
+}
+
 /*
   remove a pending opendb entry
 */
@@ -584,8 +596,9 @@ static NTSTATUS odb_ctdb_get_delete_on_close(struct odb_context *odb,
   create_options and access_mask
 */
 static NTSTATUS odb_ctdb_can_open(struct odb_lock *lck,
-                                uint32_t share_access, uint32_t create_options, 
-                                uint32_t access_mask)
+                                 uint32_t stream_id, uint32_t share_access,
+                                 uint32_t access_mask, bool delete_on_close,
+                                 uint32_t open_disposition, bool break_to_none)
 {
        struct odb_context *odb = lck->odb;
        NTSTATUS status;
@@ -599,7 +612,7 @@ static NTSTATUS odb_ctdb_can_open(struct odb_lock *lck,
        }
        NT_STATUS_NOT_OK_RETURN(status);
 
-       if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) && 
+       if (delete_on_close &&
            file.num_entries != 0) {
                return NT_STATUS_SHARING_VIOLATION;
        }
@@ -642,7 +655,8 @@ static const struct opendb_ops opendb_ctdb_ops = {
        .odb_set_delete_on_close = odb_ctdb_set_delete_on_close,
        .odb_get_delete_on_close = odb_ctdb_get_delete_on_close,
        .odb_can_open            = odb_ctdb_can_open,
-       .odb_update_oplock       = odb_ctdb_update_oplock
+       .odb_update_oplock       = odb_ctdb_update_oplock,
+       .odb_break_oplocks       = odb_ctdb_break_oplocks
 };
 
 
index 30f39ac6cb4b92c75a9e0b3ff0da402b147c5f8f..af9522f3a6bce57ccc383c071b2238e46b504028 100644 (file)
@@ -10,6 +10,7 @@ VPATH = @libreplacedir@
 srcdir = @srcdir@
 builddir = @builddir@
 INSTALL = @INSTALL@
+LIBS = @LIBS@
 
 .PHONY: test all showflags install installcheck clean distclean realdistclean
 
@@ -25,6 +26,7 @@ showflags:
        @echo '  CC     = $(CC)'
        @echo '  CFLAGS = $(CFLAGS)'
        @echo '  LDFLAGS= $(LDFLAGS)'
+       @echo '  LIBS   = $(LIBS)'
 
 install: all
        mkdir -p $(libdir)
@@ -41,7 +43,7 @@ installcheck: install test
 TEST_OBJS = test/testsuite.o test/os2_delete.o test/strptime.o
 
 testsuite: libreplace.a $(TEST_OBJS)
-       $(CC) -o testsuite $(TEST_OBJS) -L. -lreplace $(LDFLAGS)
+       $(CC) -o testsuite $(TEST_OBJS) -L. -lreplace $(LDFLAGS) $(LIBS)
 
 .c.o:
        @echo Compiling $*.c
index beeb77e15204a6d7bb7f0b22bfe3003d2218a06b..f5e054f4767379ef98714c306638cf8003c9917e 100644 (file)
@@ -3,6 +3,8 @@ AC_INIT(replace.c)
 AC_CONFIG_SRCDIR([replace.c])
 AC_CONFIG_HEADER(config.h)
 
+CFLAGS="$CFLAGS -I$srcdir"
+
 AC_LIBREPLACE_ALL_CHECKS
 
 if test "$ac_cv_prog_gcc" = yes; then
index dd2a95cb815b1ba13006c9df8659d00644566603..767797e8d2a37b809509d6cd785b9cb3492958e0 100644 (file)
@@ -71,6 +71,7 @@ AC_TRY_RUN([
            libreplace_cv_HAVE_IFACE_AIX=yes,libreplace_cv_HAVE_IFACE_AIX=no,libreplace_cv_HAVE_IFACE_AIX=cross)])
 if test x"$libreplace_cv_HAVE_IFACE_AIX" = x"yes"; then
     iface=yes;AC_DEFINE(HAVE_IFACE_AIX,1,[Whether iface AIX is available])
+       old_LIBS="$old_LIBS $LIBS"
 fi
 fi
 
@@ -87,6 +88,7 @@ AC_TRY_RUN([
            libreplace_cv_HAVE_IFACE_IFCONF=yes,libreplace_cv_HAVE_IFACE_IFCONF=no,libreplace_cv_HAVE_IFACE_IFCONF=cross)])
 if test x"$libreplace_cv_HAVE_IFACE_IFCONF" = x"yes"; then
     iface=yes;AC_DEFINE(HAVE_IFACE_IFCONF,1,[Whether iface ifconf is available])
+       old_LIBS="$old_LIBS $LIBS"
 fi
 fi
 
@@ -102,6 +104,7 @@ AC_TRY_RUN([
            libreplace_cv_HAVE_IFACE_IFREQ=yes,libreplace_cv_HAVE_IFACE_IFREQ=no,libreplace_cv_HAVE_IFACE_IFREQ=cross)])
 if test x"$libreplace_cv_HAVE_IFACE_IFREQ" = x"yes"; then
     iface=yes;AC_DEFINE(HAVE_IFACE_IFREQ,1,[Whether iface ifreq is available])
+       old_LIBS="$old_LIBS $LIBS"
 fi
 fi
 
index 2e0cd34f4ac6d5ac0d917713289c66c29ed30038..e0cc57f4c80c6cd340ae63d5dd9872516683d29b 100644 (file)
@@ -344,6 +344,7 @@ m4_include(getpass.m4)
 m4_include(strptime.m4)
 m4_include(win32.m4)
 m4_include(timegm.m4)
+m4_include(socket.m4)
 m4_include(inet_ntop.m4)
 m4_include(inet_pton.m4)
 m4_include(getaddrinfo.m4)
index 3f91544e9782f914c1d898ebf7b5c8f50da5b843..0d16f4ffd0a797ad6f959eb07612a6419a1b698b 100644 (file)
@@ -340,6 +340,16 @@ ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset)
 /* prototype is in "system/network.h" */
 #endif
 
+#ifndef HAVE_CONNECT
+#define connect rep_connect
+/* prototype is in "system/network.h" */
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME
+#define gethostbyname rep_gethostbyname
+/* prototype is in "system/network.h" */
+#endif
+
 #ifndef HAVE_GETIFADDRS
 #define getifaddrs rep_getifaddrs
 /* prototype is in "system/network.h" */
diff --git a/source4/lib/replace/socket.c b/source4/lib/replace/socket.c
new file mode 100644 (file)
index 0000000..35e975f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Unix SMB/CIFS implementation.
+ *
+ * Dummy replacements for socket functions.
+ *
+ * Copyright (C) Michael Adam <obnox@samba.org> 2008
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "replace.h"
+#include "system/network.h"
+
+int rep_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
+{
+       errno = ENOSYS;
+       return -1;
+}
+
+struct hostent *rep_gethostbyname(const char *name)
+{
+       errno = ENOSYS;
+       return NULL;
+}
diff --git a/source4/lib/replace/socket.m4 b/source4/lib/replace/socket.m4
new file mode 100644 (file)
index 0000000..c0c8f93
--- /dev/null
@@ -0,0 +1,40 @@
+dnl The following test is roughl taken from the cvs sources.
+dnl
+dnl If we can't find connect, try looking in -lsocket, -lnsl, and -linet.
+dnl The Irix 5 libc.so has connect and gethostbyname, but Irix 5 also has
+dnl libsocket.so which has a bad implementation of gethostbyname (it
+dnl only looks in /etc/hosts), so we only look for -lsocket if we need
+dnl it.
+AC_CHECK_FUNCS(connect)
+if test x"$ac_cv_func_connect" = x"no"; then
+       AC_CHECK_LIB_EXT(nsl_s, SOCKET_LIBS, connect)
+       AC_CHECK_LIB_EXT(nsl, SOCKET_LIBS, connect)
+       AC_CHECK_LIB_EXT(socket, SOCKET_LIBS, connect)
+       AC_CHECK_LIB_EXT(inet, SOCKET_LIBS, connect)
+       dnl We can't just call AC_CHECK_FUNCS(connect) here,
+       dnl because the value has been cached.
+       if test x"$ac_cv_lib_ext_nsl_s_connect" = x"yes" ||
+               test x"$ac_cv_lib_ext_nsl_connect" = x"yes" ||
+               test x"$ac_cv_lib_ext_socket_connect" = x"yes" ||
+               test x"$ac_cv_lib_ext_inet_connect" = x"yes"
+       then
+               AC_DEFINE(HAVE_CONNECT,1,[Whether the system has connect()])
+       fi
+fi
+
+AC_CHECK_FUNCS(gethostbyname)
+if test x"$ac_cv_func_gethostbyname" = x"no"; then
+       AC_CHECK_LIB_EXT(nsl_s, NSL_LIBS, gethostbyname)
+       AC_CHECK_LIB_EXT(nsl, NSL_LIBS, gethostbyname)
+       AC_CHECK_LIB_EXT(socket, NSL_LIBS, gethostbyname)
+       dnl We can't just call AC_CHECK_FUNCS(gethostbyname) here,
+       dnl because the value has been cached.
+       if test x"$ac_cv_lib_ext_nsl_s_gethostbyname" = x"yes" ||
+               test x"$ac_cv_lib_ext_nsl_gethostbyname" = x"yes" ||
+               test x"$ac_cv_lib_ext_socket_gethostbyname" = x"yes"
+       then
+               AC_DEFINE(HAVE_GETHOSTBYNAME,1,
+                         [Whether the system has gethostbyname()])
+       fi
+fi
+
index d09e3f71f8d5b3511484edbb3fbbcde546cb0133..410c6d7cca2904d12e738c470cc90a6cc581a5ac 100644 (file)
 #include <stropts.h>
 #endif
 
+#ifndef HAVE_SOCKLEN_T
+#define HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif
+
 #ifdef REPLACE_INET_NTOA
 /* define is in "replace.h" */
 char *rep_inet_ntoa(struct in_addr ip);
@@ -98,6 +103,16 @@ int rep_inet_pton(int af, const char *src, void *dst);
 const char *rep_inet_ntop(int af, const void *src, char *dst, socklen_t size);
 #endif
 
+#ifndef HAVE_CONNECT
+/* define is in "replace.h" */
+int rep_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+#endif
+
+#ifndef HAVE_GETHOSTBYNAME
+/* define is in "replace.h" */
+struct hostent *rep_gethostbyname(const char *name);
+#endif
+
 #ifdef HAVE_IFADDRS_H
 #include <ifaddrs.h>
 #endif
@@ -245,11 +260,6 @@ void rep_freeifaddrs(struct ifaddrs *);
 #define HOST_NAME_MAX 256
 #endif
 
-#ifndef HAVE_SOCKLEN_T
-#define HAVE_SOCKLEN_T
-typedef int socklen_t;
-#endif
-
 #ifndef HAVE_SA_FAMILY_T
 #define HAVE_SA_FAMILY_T
 typedef unsigned short int sa_family_t;
index 48bc565fff51212f686b386172c0a5fcb1ae9361..6929e86e61f26e2a7f17e1baf3ffb999d212e9e2 100644 (file)
@@ -42,8 +42,8 @@ import "security.idl";
 
        typedef struct {
                NTSTATUS status;
-               utf8string homedir;
-               utf8string shell;
+               [charset(UTF8),string] uint8 homedir[];
+               [charset(UTF8),string] uint8 shell[];
        } unixinfo_GetPWUidInfo;
 
        /******************/
index 4ac10806e13255cf0d45fe1985f8c8fd6155d6d7..36144d0406b09a20cb1c1d62f6ce5323e91be0f7 100644 (file)
@@ -93,15 +93,16 @@ _PUBLIC_ DATA_BLOB odb_get_key(TALLOC_CTX *mem_ctx, struct odb_lock *lck)
   Note that the path is only used by the delete on close logic, not
   for comparing with other filenames
 */
-_PUBLIC_ NTSTATUS odb_open_file(struct odb_lock *lck, void *file_handle,
-                               uint32_t stream_id, uint32_t share_access, 
+_PUBLIC_ NTSTATUS odb_open_file(struct odb_lock *lck,
+                               void *file_handle, const char *path,
+                               uint32_t stream_id, uint32_t share_access,
                                uint32_t access_mask, bool delete_on_close,
-                               const char *path, 
+                               uint32_t open_disposition, bool break_to_none,
                                uint32_t oplock_level, uint32_t *oplock_granted)
 {
-       return ops->odb_open_file(lck, file_handle, stream_id, share_access,
-                                 access_mask, delete_on_close, path, oplock_level,
-                                 oplock_granted);
+       return ops->odb_open_file(lck, file_handle, path, stream_id, share_access,
+                                 access_mask, delete_on_close, open_disposition,
+                                 break_to_none, oplock_level, oplock_granted);
 }
 
 
@@ -165,10 +166,12 @@ _PUBLIC_ NTSTATUS odb_get_delete_on_close(struct odb_context *odb,
   create_options and access_mask
 */
 _PUBLIC_ NTSTATUS odb_can_open(struct odb_lock *lck,
-                              uint32_t share_access, uint32_t create_options, 
-                              uint32_t access_mask)
+                              uint32_t stream_id, uint32_t share_access,
+                              uint32_t access_mask, bool delete_on_close,
+                              uint32_t open_disposition, bool break_to_none)
 {
-       return ops->odb_can_open(lck, share_access, create_options, access_mask);
+       return ops->odb_can_open(lck, stream_id, share_access, access_mask,
+                                delete_on_close, open_disposition, break_to_none);
 }
 
 _PUBLIC_ NTSTATUS odb_update_oplock(struct odb_lock *lck, void *file_handle,
@@ -176,3 +179,8 @@ _PUBLIC_ NTSTATUS odb_update_oplock(struct odb_lock *lck, void *file_handle,
 {
        return ops->odb_update_oplock(lck, file_handle, oplock_level);
 }
+
+_PUBLIC_ NTSTATUS odb_break_oplocks(struct odb_lock *lck)
+{
+       return ops->odb_break_oplocks(lck);
+}
index c34a07d6facf31d1e40114bf59af86ec967aa65d..9591bcf6b9b38817b34cd0262488fabf952d6131 100644 (file)
@@ -25,10 +25,11 @@ struct opendb_ops {
        struct odb_lock *(*odb_lock)(TALLOC_CTX *mem_ctx,
                                     struct odb_context *odb, DATA_BLOB *file_key);
        DATA_BLOB (*odb_get_key)(TALLOC_CTX *mem_ctx, struct odb_lock *lck);
-       NTSTATUS (*odb_open_file)(struct odb_lock *lck, void *file_handle,
-                                 uint32_t stream_id, uint32_t share_access, 
+       NTSTATUS (*odb_open_file)(struct odb_lock *lck,
+                                 void *file_handle, const char *path,
+                                 uint32_t stream_id, uint32_t share_access,
                                  uint32_t access_mask, bool delete_on_close,
-                                 const char *path, 
+                                 uint32_t open_disposition, bool break_to_none,
                                  uint32_t oplock_level, uint32_t *oplock_granted);
        NTSTATUS (*odb_open_file_pending)(struct odb_lock *lck, void *private);
        NTSTATUS (*odb_close_file)(struct odb_lock *lck, void *file_handle);
@@ -39,10 +40,12 @@ struct opendb_ops {
                                            DATA_BLOB *key, bool *del_on_close, 
                                            int *open_count, char **path);
        NTSTATUS (*odb_can_open)(struct odb_lock *lck,
-                                uint32_t share_access, uint32_t create_options, 
-                                uint32_t access_mask);
+                                uint32_t stream_id, uint32_t share_access,
+                                uint32_t access_mask, bool delete_on_close,
+                                uint32_t open_disposition, bool break_to_none);
        NTSTATUS (*odb_update_oplock)(struct odb_lock *lck, void *file_handle,
                                      uint32_t oplock_level);
+       NTSTATUS (*odb_break_oplocks)(struct odb_lock *lck);
 };
 
 struct opendb_oplock_break {
index 3d4a760e2e4adcb8d8e9aaa35e52d3571f586f07..a51c823a633593544af1c22120cbee3df012fefb 100644 (file)
@@ -146,7 +146,10 @@ static DATA_BLOB odb_tdb_get_key(TALLOC_CTX *mem_ctx, struct odb_lock *lck)
 
   return NT_STATUS_OK on no conflict
 */
-static NTSTATUS share_conflict(struct opendb_entry *e1, struct opendb_entry *e2)
+static NTSTATUS share_conflict(struct opendb_entry *e1,
+                              uint32_t stream_id,
+                              uint32_t share_access,
+                              uint32_t access_mask)
 {
        /* if either open involves no read.write or delete access then
           it can't conflict */
@@ -157,18 +160,18 @@ static NTSTATUS share_conflict(struct opendb_entry *e1, struct opendb_entry *e2)
                                 SEC_STD_DELETE))) {
                return NT_STATUS_OK;
        }
-       if (!(e2->access_mask & (SEC_FILE_WRITE_DATA |
-                                SEC_FILE_APPEND_DATA |
-                                SEC_FILE_READ_DATA |
-                                SEC_FILE_EXECUTE |
-                                SEC_STD_DELETE))) {
+       if (!(access_mask & (SEC_FILE_WRITE_DATA |
+                            SEC_FILE_APPEND_DATA |
+                            SEC_FILE_READ_DATA |
+                            SEC_FILE_EXECUTE |
+                            SEC_STD_DELETE))) {
                return NT_STATUS_OK;
        }
 
        /* data IO access masks. This is skipped if the two open handles
           are on different streams (as in that case the masks don't
           interact) */
-       if (e1->stream_id != e2->stream_id) {
+       if (e1->stream_id != stream_id) {
                return NT_STATUS_OK;
        }
 
@@ -176,20 +179,20 @@ static NTSTATUS share_conflict(struct opendb_entry *e1, struct opendb_entry *e2)
        if (((am) & (right)) && !((sa) & (share))) return NT_STATUS_SHARING_VIOLATION
 
        CHECK_MASK(e1->access_mask, SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
-                  e2->share_access, NTCREATEX_SHARE_ACCESS_WRITE);
-       CHECK_MASK(e2->access_mask, SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
+                  share_access, NTCREATEX_SHARE_ACCESS_WRITE);
+       CHECK_MASK(access_mask, SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA,
                   e1->share_access, NTCREATEX_SHARE_ACCESS_WRITE);
        
        CHECK_MASK(e1->access_mask, SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
-                  e2->share_access, NTCREATEX_SHARE_ACCESS_READ);
-       CHECK_MASK(e2->access_mask, SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
+                  share_access, NTCREATEX_SHARE_ACCESS_READ);
+       CHECK_MASK(access_mask, SEC_FILE_READ_DATA | SEC_FILE_EXECUTE,
                   e1->share_access, NTCREATEX_SHARE_ACCESS_READ);
 
        CHECK_MASK(e1->access_mask, SEC_STD_DELETE,
-                  e2->share_access, NTCREATEX_SHARE_ACCESS_DELETE);
-       CHECK_MASK(e2->access_mask, SEC_STD_DELETE,
+                  share_access, NTCREATEX_SHARE_ACCESS_DELETE);
+       CHECK_MASK(access_mask, SEC_STD_DELETE,
                   e1->share_access, NTCREATEX_SHARE_ACCESS_DELETE);
-
+#undef CHECK_MASK
        return NT_STATUS_OK;
 }
 
@@ -284,6 +287,125 @@ static NTSTATUS odb_oplock_break_send(struct odb_context *odb,
        return NT_STATUS_OK;
 }
 
+static bool access_attributes_only(uint32_t access_mask,
+                                  uint32_t open_disposition,
+                                  bool break_to_none)
+{
+       switch (open_disposition) {
+       case NTCREATEX_DISP_SUPERSEDE:
+       case NTCREATEX_DISP_OVERWRITE_IF:
+       case NTCREATEX_DISP_OVERWRITE:
+               return false;
+       default:
+               break;
+       }
+
+       if (break_to_none) {
+               return false;
+       }
+
+#define CHECK_MASK(m,g) ((m) && (((m) & ~(g))==0) && (((m) & (g)) != 0))
+       return CHECK_MASK(access_mask,
+                         SEC_STD_SYNCHRONIZE |
+                         SEC_FILE_READ_ATTRIBUTE |
+                         SEC_FILE_WRITE_ATTRIBUTE);
+#undef CHECK_MASK
+}
+
+static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb,
+                                         const struct opendb_file *file,
+                                         uint32_t stream_id, uint32_t share_access,
+                                         uint32_t access_mask, bool delete_on_close,
+                                         uint32_t open_disposition, bool break_to_none,
+                                         bool *_attrs_only)
+{
+       NTSTATUS status;
+       uint32_t i;
+       bool attrs_only = false;
+
+       /* see if anyone has an oplock, which we need to break */
+       for (i=0;i<file->num_entries;i++) {
+               if (file->entries[i].oplock_level == OPLOCK_BATCH) {
+                       bool oplock_return = OPLOCK_BREAK_TO_LEVEL_II;
+                       /* if this is an attribute only access
+                        * it doesn't conflict with a BACTCH oplock
+                        * but we'll not grant the oplock below
+                        */
+                       attrs_only = access_attributes_only(access_mask,
+                                                           open_disposition,
+                                                           break_to_none);
+                       if (attrs_only) {
+                               break;
+                       }
+                       /* a batch oplock caches close calls, which
+                          means the client application might have
+                          already closed the file. We have to allow
+                          this close to propogate by sending a oplock
+                          break request and suspending this call
+                          until the break is acknowledged or the file
+                          is closed */
+                       if (break_to_none) {
+                               oplock_return = OPLOCK_BREAK_TO_NONE;
+                       }
+                       odb_oplock_break_send(odb, &file->entries[i],
+                                             oplock_return);
+                       return NT_STATUS_OPLOCK_NOT_GRANTED;
+               }
+       }
+
+       if (file->delete_on_close) {
+               /* while delete on close is set, no new opens are allowed */
+               return NT_STATUS_DELETE_PENDING;
+       }
+
+       if (file->num_entries != 0 && delete_on_close) {
+               return NT_STATUS_SHARING_VIOLATION;
+       }
+
+       /* check for sharing violations */
+       for (i=0;i<file->num_entries;i++) {
+               status = share_conflict(&file->entries[i], stream_id,
+                                       share_access, access_mask);
+               NT_STATUS_NOT_OK_RETURN(status);
+       }
+
+       /* we now know the open could succeed, but we need to check
+          for any exclusive oplocks. We can't grant a second open
+          till these are broken. Note that we check for batch oplocks
+          before checking for sharing violations, and check for
+          exclusive oplocks afterwards. */
+       for (i=0;i<file->num_entries;i++) {
+               if (file->entries[i].oplock_level == OPLOCK_EXCLUSIVE) {
+                       bool oplock_return = OPLOCK_BREAK_TO_LEVEL_II;
+                       /* if this is an attribute only access
+                        * it doesn't conflict with an EXCLUSIVE oplock
+                        * but we'll not grant the oplock below
+                        */
+                       attrs_only = access_attributes_only(access_mask,
+                                                           open_disposition,
+                                                           break_to_none);
+                       if (attrs_only) {
+                               break;
+                       }
+                       /*
+                        * send an oplock break to the holder of the
+                        * oplock and tell caller to retry later
+                        */
+                       if (break_to_none) {
+                               oplock_return = OPLOCK_BREAK_TO_NONE;
+                       }
+                       odb_oplock_break_send(odb, &file->entries[i],
+                                             oplock_return);
+                       return NT_STATUS_OPLOCK_NOT_GRANTED;
+               }
+       }
+
+       if (_attrs_only) {
+               *_attrs_only = attrs_only;
+       }
+       return NT_STATUS_OK;
+}
+
 /*
   register an open file in the open files database. This implements the share_access
   rules
@@ -291,17 +413,18 @@ static NTSTATUS odb_oplock_break_send(struct odb_context *odb,
   Note that the path is only used by the delete on close logic, not
   for comparing with other filenames
 */
-static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, void *file_handle,
-                                 uint32_t stream_id, uint32_t share_access, 
+static NTSTATUS odb_tdb_open_file(struct odb_lock *lck,
+                                 void *file_handle, const char *path,
+                                 uint32_t stream_id, uint32_t share_access,
                                  uint32_t access_mask, bool delete_on_close,
-                                 const char *path, 
+                                 uint32_t open_disposition, bool break_to_none,
                                  uint32_t oplock_level, uint32_t *oplock_granted)
 {
        struct odb_context *odb = lck->odb;
        struct opendb_entry e;
-       int i;
        struct opendb_file file;
        NTSTATUS status;
+       bool attrs_only = false;
 
        if (odb->oplocks == false) {
                oplock_level = OPLOCK_NONE;
@@ -316,6 +439,13 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, void *file_handle,
                NT_STATUS_NOT_OK_RETURN(status);
        }
 
+       /* see if it conflicts */
+       status = odb_tdb_open_can_internal(odb, &file, stream_id,
+                                          share_access, access_mask,
+                                          delete_on_close, open_disposition,
+                                          break_to_none, &attrs_only);
+       NT_STATUS_NOT_OK_RETURN(status);
+
        /* see if it conflicts */
        e.server          = odb->ntvfs_ctx->server_id;
        e.file_handle     = file_handle;
@@ -324,61 +454,37 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, void *file_handle,
        e.access_mask     = access_mask;
        e.delete_on_close = delete_on_close;
        e.oplock_level    = OPLOCK_NONE;
-               
-       /* see if anyone has an oplock, which we need to break */
-       for (i=0;i<file.num_entries;i++) {
-               if (file.entries[i].oplock_level == OPLOCK_BATCH) {
-                       /* a batch oplock caches close calls, which
-                          means the client application might have
-                          already closed the file. We have to allow
-                          this close to propogate by sending a oplock
-                          break request and suspending this call
-                          until the break is acknowledged or the file
-                          is closed */
-                       odb_oplock_break_send(odb, &file.entries[i],
-                                             OPLOCK_BREAK_TO_LEVEL_II/*TODO*/);
-                       return NT_STATUS_OPLOCK_NOT_GRANTED;
-               }
-       }
-
-       if (file.delete_on_close || 
-           (file.num_entries != 0 && delete_on_close)) {
-               /* while delete on close is set, no new opens are allowed */
-               return NT_STATUS_DELETE_PENDING;
-       }
-
-       /* check for sharing violations */
-       for (i=0;i<file.num_entries;i++) {
-               status = share_conflict(&file.entries[i], &e);
-               NT_STATUS_NOT_OK_RETURN(status);
-       }
-
-       /* we now know the open could succeed, but we need to check
-          for any exclusive oplocks. We can't grant a second open
-          till these are broken. Note that we check for batch oplocks
-          before checking for sharing violations, and check for
-          exclusive oplocks afterwards. */
-       for (i=0;i<file.num_entries;i++) {
-               if (file.entries[i].oplock_level == OPLOCK_EXCLUSIVE) {
-                       odb_oplock_break_send(odb, &file.entries[i],
-                                             OPLOCK_BREAK_TO_NONE/*TODO*/);
-                       return NT_STATUS_OPLOCK_NOT_GRANTED;
-               }
-       }
 
        /*
-         possibly grant an exclusive or batch oplock if this is the only client
-         with the file open. We don't yet grant levelII oplocks.
+         possibly grant an exclusive, batch or level2 oplock
        */
-       if (oplock_granted != NULL) {
-               if ((oplock_level == OPLOCK_BATCH ||
-                    oplock_level == OPLOCK_EXCLUSIVE) &&
-                   file.num_entries == 0) {
-                       (*oplock_granted) = oplock_level;
+       if (oplock_granted) {
+               if (attrs_only) {
+                       e.oplock_level  = OPLOCK_NONE;
+                       *oplock_granted = NO_OPLOCK_RETURN;
+               } else if (oplock_level == OPLOCK_EXCLUSIVE) {
+                       if (file.num_entries == 0) {
+                               e.oplock_level  = OPLOCK_EXCLUSIVE;
+                               *oplock_granted = EXCLUSIVE_OPLOCK_RETURN;
+                       } else {
+                               e.oplock_level  = OPLOCK_LEVEL_II;
+                               *oplock_granted = LEVEL_II_OPLOCK_RETURN;
+                       }
+               } else if (oplock_level == OPLOCK_BATCH) {
+                       if (file.num_entries == 0) {
+                               e.oplock_level  = OPLOCK_BATCH;
+                               *oplock_granted = BATCH_OPLOCK_RETURN;
+                       } else {
+                               e.oplock_level  = OPLOCK_LEVEL_II;
+                               *oplock_granted = LEVEL_II_OPLOCK_RETURN;
+                       }
+               } else if (oplock_level == OPLOCK_LEVEL_II) {
+                       e.oplock_level  = OPLOCK_LEVEL_II;
+                       *oplock_granted = LEVEL_II_OPLOCK_RETURN;
                } else {
-                       (*oplock_granted) = OPLOCK_NONE;
+                       e.oplock_level  = OPLOCK_NONE;
+                       *oplock_granted = NO_OPLOCK_RETURN;
                }
-               e.oplock_level = (*oplock_granted);
        }
 
        /* it doesn't conflict, so add it to the end */
@@ -503,6 +609,43 @@ static NTSTATUS odb_tdb_update_oplock(struct odb_lock *lck, void *file_handle,
        return odb_push_record(lck, &file);
 }
 
+/*
+  send oplocks breaks to none to all level2 holders
+*/
+static NTSTATUS odb_tdb_break_oplocks(struct odb_lock *lck)
+{
+       struct odb_context *odb = lck->odb;
+       NTSTATUS status;
+       struct opendb_file file;
+       int i;
+       bool modified = true;
+
+       status = odb_pull_record(lck, &file);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               return NT_STATUS_OK;
+       }
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       /* see if anyone has an oplock, which we need to break */
+       for (i=0;i<file.num_entries;i++) {
+               if (file.entries[i].oplock_level == OPLOCK_LEVEL_II) {
+                       /*
+                        * there could be multiple level2 oplocks
+                        * and we just send a break to none to all of them
+                        * without waiting for a release
+                        */
+                       odb_oplock_break_send(odb, &file.entries[i],
+                                             OPLOCK_BREAK_TO_NONE);
+                       file.entries[i].oplock_level = OPLOCK_NONE;
+                       modified = true;
+               }
+       }
+
+       if (modified) {
+               return odb_push_record(lck, &file);
+       }
+       return NT_STATUS_OK;
+}
 
 /*
   remove a pending opendb entry
@@ -624,14 +767,14 @@ static NTSTATUS odb_tdb_get_delete_on_close(struct odb_context *odb,
   create_options and access_mask
 */
 static NTSTATUS odb_tdb_can_open(struct odb_lock *lck,
-                                uint32_t share_access, uint32_t create_options, 
-                                uint32_t access_mask)
+                                uint32_t stream_id, uint32_t share_access,
+                                uint32_t access_mask, bool delete_on_close,
+                                uint32_t open_disposition, bool break_to_none)
 {
        struct odb_context *odb = lck->odb;
        NTSTATUS status;
        struct opendb_file file;
-       struct opendb_entry e;
-       int i;
+       bool attrs_only = false;
 
        status = odb_pull_record(lck, &file);
        if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
@@ -639,32 +782,11 @@ static NTSTATUS odb_tdb_can_open(struct odb_lock *lck,
        }
        NT_STATUS_NOT_OK_RETURN(status);
 
-       if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) && 
-           file.num_entries != 0) {
-               return NT_STATUS_SHARING_VIOLATION;
-       }
-
-       if (file.delete_on_close) {
-               return NT_STATUS_DELETE_PENDING;
-       }
-
-       e.server       = odb->ntvfs_ctx->server_id;
-       e.file_handle  = NULL;
-       e.stream_id    = 0;
-       e.share_access = share_access;
-       e.access_mask  = access_mask;
-               
-       for (i=0;i<file.num_entries;i++) {
-               status = share_conflict(&file.entries[i], &e);
-               if (!NT_STATUS_IS_OK(status)) {
-                       /* note that we discard the error code
-                          here. We do this as unless we are actually
-                          doing an open (which comes via a different
-                          function), we need to return a sharing
-                          violation */
-                       return NT_STATUS_SHARING_VIOLATION;
-               }
-       }
+       status = odb_tdb_open_can_internal(odb, &file, stream_id,
+                                          share_access, access_mask,
+                                          delete_on_close, open_disposition,
+                                          break_to_none, &attrs_only);
+       NT_STATUS_NOT_OK_RETURN(status);
 
        return NT_STATUS_OK;
 }
@@ -682,7 +804,8 @@ static const struct opendb_ops opendb_tdb_ops = {
        .odb_set_delete_on_close = odb_tdb_set_delete_on_close,
        .odb_get_delete_on_close = odb_tdb_get_delete_on_close,
        .odb_can_open            = odb_tdb_can_open,
-       .odb_update_oplock       = odb_tdb_update_oplock
+       .odb_update_oplock       = odb_tdb_update_oplock,
+       .odb_break_oplocks       = odb_tdb_break_oplocks
 };
 
 
index 6879940337b7d40d396699cde3861877db5cd133..88048c2af7baf842b73afb0cf10f478c561f5cf9 100644 (file)
@@ -53,6 +53,7 @@ OBJ_FILES = \
                pvfs_resolve.o \
                pvfs_shortname.o \
                pvfs_lock.o \
+               pvfs_oplock.o \
                pvfs_wait.o \
                pvfs_seek.o \
                pvfs_ioctl.o \
index df85b2b77526d960b94f9baf5046033129a37091..baa92880f13d570e8c6cb6b33082a67e05a070fc 100644 (file)
@@ -294,6 +294,10 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
                return ntvfs_map_lock(ntvfs, req, lck);
        }
 
+       if (lck->lockx.in.mode & LOCKING_ANDX_OPLOCK_RELEASE) {
+               return pvfs_oplock_release(ntvfs, req, lck);
+       }
+
        f = pvfs_find_fd(pvfs, req, lck->lockx.in.file.ntvfs);
        if (!f) {
                return NT_STATUS_INVALID_HANDLE;
@@ -303,6 +307,9 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_FILE_IS_A_DIRECTORY;
        }
 
+       status = pvfs_break_level2_oplocks(f);
+       NT_STATUS_NOT_OK_RETURN(status);
+
        if (lck->lockx.in.timeout != 0 && 
            (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
                pending = talloc(f, struct pvfs_pending_lock);
@@ -338,13 +345,6 @@ NTSTATUS pvfs_lock(struct ntvfs_module_context *ntvfs,
                return NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks);
        }
 
-       if (lck->lockx.in.mode & LOCKING_ANDX_OPLOCK_RELEASE) {
-               DEBUG(0,("received unexpected oplock break\n"));
-               talloc_free(pending);
-               return NT_STATUS_NOT_IMPLEMENTED;
-       }
-
-
        /* the unlocks happen first */
        locks = lck->lockx.in.locks;
 
index 3a8b17ab16ddb371a50688d3a29618c024cda4d7..a01352f60cff54cf5064e5d9d850d85e799b5edf 100644 (file)
@@ -268,6 +268,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        f->handle->seek_offset       = 0;
        f->handle->position          = 0;
        f->handle->mode              = 0;
+       f->handle->oplock            = NULL;
        f->handle->sticky_write_time = false;
        f->handle->open_completed    = false;
 
@@ -296,9 +297,10 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                }
                
                /* see if we are allowed to open at the same time as existing opens */
-               status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
+               status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
                                       share_access, access_mask, del_on_close, 
-                                      name->full_name, OPLOCK_NONE, NULL);
+                                      io->generic.in.open_disposition,
+                                      false, OPLOCK_NONE, NULL);
 
                if (!NT_STATUS_IS_OK(status)) {
                        talloc_free(lck);
@@ -349,9 +351,10 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                        return NT_STATUS_INTERNAL_DB_CORRUPTION;
                }
 
-               status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
+               status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
                                       share_access, access_mask, del_on_close, 
-                                      name->full_name, OPLOCK_NONE, NULL);
+                                      io->generic.in.open_disposition,
+                                      false, OPLOCK_NONE, NULL);
 
                if (!NT_STATUS_IS_OK(status)) {
                        goto cleanup_delete;
@@ -669,9 +672,10 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                oplock_level = OPLOCK_EXCLUSIVE;
        }
 
-       status = odb_open_file(lck, f->handle, name->stream_id,
+       status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
                               share_access, access_mask, del_on_close, 
-                              name->full_name, oplock_level, &oplock_granted);
+                              io->generic.in.open_disposition,
+                              false, oplock_level, &oplock_granted);
        talloc_free(lck);
        if (!NT_STATUS_IS_OK(status)) {
                /* bad news, we must have hit a race - we don't delete the file
@@ -681,9 +685,6 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                return status;
        }
 
-       if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
-               oplock_granted = OPLOCK_BATCH;
-       }
 
        f->ntvfs             = h;
        f->pvfs              = pvfs;
@@ -702,12 +703,23 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        f->handle->seek_offset       = 0;
        f->handle->position          = 0;
        f->handle->mode              = 0;
+       f->handle->oplock            = NULL;
        f->handle->have_opendb_entry = true;
        f->handle->sticky_write_time = false;
        f->handle->open_completed    = false;
 
        DLIST_ADD(pvfs->files.list, f);
 
+       if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
+               oplock_granted = OPLOCK_BATCH;
+       } else if (oplock_granted != OPLOCK_NONE) {
+               status = pvfs_setup_oplock(f, oplock_granted);
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_free(lck);
+                       return status;
+               }
+       }
+
        /* setup a destructor to avoid file descriptor leaks on
           abnormal termination */
        talloc_set_destructor(f, pvfs_fnum_destructor);
@@ -748,20 +760,25 @@ cleanup_delete:
        return status;
 }
 
-
 /*
-  state of a pending open retry
+  state of a pending retry
 */
-struct pvfs_open_retry {
+struct pvfs_odb_retry {
        struct ntvfs_module_context *ntvfs;
        struct ntvfs_request *req;
-       union smb_open *io;
-       struct pvfs_wait *wait_handle;
        DATA_BLOB odb_locking_key;
+       void *io;
+       void *private_data;
+       void (*callback)(struct pvfs_odb_retry *r,
+                        struct ntvfs_module_context *ntvfs,
+                        struct ntvfs_request *req,
+                        void *io,
+                        void *private_data,
+                        enum pvfs_wait_notice reason);
 };
 
-/* destroy a pending open request */
-static int pvfs_retry_destructor(struct pvfs_open_retry *r)
+/* destroy a pending request */
+static int pvfs_odb_retry_destructor(struct pvfs_odb_retry *r)
 {
        struct pvfs_state *pvfs = r->ntvfs->private_data;
        if (r->odb_locking_key.data) {
@@ -775,15 +792,92 @@ static int pvfs_retry_destructor(struct pvfs_open_retry *r)
        return 0;
 }
 
+static void pvfs_odb_retry_callback(void *_r, enum pvfs_wait_notice reason)
+{
+       struct pvfs_odb_retry *r = talloc_get_type(_r, struct pvfs_odb_retry);
+
+       if (reason == PVFS_WAIT_EVENT) {
+               /*
+                * The pending odb entry is already removed.
+                * We use a null locking key to indicate this
+                * to the destructor.
+                */
+               data_blob_free(&r->odb_locking_key);
+       }
+
+       r->callback(r, r->ntvfs, r->req, r->io, r->private_data, reason);
+}
+
 /*
-  retry an open
+  setup for a retry of a request that was rejected
+  by odb_open_file() or odb_can_open()
 */
-static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
+NTSTATUS pvfs_odb_retry_setup(struct ntvfs_module_context *ntvfs,
+                             struct ntvfs_request *req,
+                             struct odb_lock *lck,
+                             struct timeval end_time,
+                             void *io,
+                             void *private_data,
+                             void (*callback)(struct pvfs_odb_retry *r,
+                                              struct ntvfs_module_context *ntvfs,
+                                              struct ntvfs_request *req,
+                                              void *io,
+                                              void *private_data,
+                                              enum pvfs_wait_notice reason))
 {
-       struct pvfs_open_retry *r = private;
-       struct ntvfs_module_context *ntvfs = r->ntvfs;
-       struct ntvfs_request *req = r->req;
-       union smb_open *io = r->io;
+       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_odb_retry *r;
+       struct pvfs_wait *wait_handle;
+       NTSTATUS status;
+
+       r = talloc(req, struct pvfs_odb_retry);
+       NT_STATUS_HAVE_NO_MEMORY(r);
+
+       r->ntvfs = ntvfs;
+       r->req = req;
+       r->io = io;
+       r->private_data = private_data;
+       r->callback = callback;
+       r->odb_locking_key = odb_get_key(r, lck);
+       if (r->odb_locking_key.data == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* setup a pending lock */
+       status = odb_open_file_pending(lck, r);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       talloc_free(lck);
+
+       talloc_set_destructor(r, pvfs_odb_retry_destructor);
+
+       wait_handle = pvfs_wait_message(pvfs, req,
+                                       MSG_PVFS_RETRY_OPEN, end_time,
+                                       pvfs_odb_retry_callback, r);
+       if (wait_handle == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       talloc_steal(r, wait_handle);
+
+       talloc_steal(pvfs, r);
+
+       return NT_STATUS_OK;
+}
+
+/*
+  retry an open after a sharing violation
+*/
+static void pvfs_retry_open_sharing(struct pvfs_odb_retry *r,
+                                   struct ntvfs_module_context *ntvfs,
+                                   struct ntvfs_request *req,
+                                   void *_io,
+                                   void *private_data,
+                                   enum pvfs_wait_notice reason)
+{
+       union smb_open *io = talloc_get_type(_io, union smb_open);
        NTSTATUS status;
 
        /* w2k3 ignores SMBntcancel for outstanding open requests. It's probably
@@ -792,8 +886,6 @@ static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
                return;
        }
 
-       talloc_free(r->wait_handle);
-
        if (reason == PVFS_WAIT_TIMEOUT) {
                /* if it timed out, then give the failure
                   immediately */
@@ -803,9 +895,6 @@ static void pvfs_open_retry(void *private, enum pvfs_wait_notice reason)
                return;
        }
 
-       /* the pending odb entry is already removed. We use a null locking
-          key to indicate this */
-       data_blob_free(&r->odb_locking_key);
        talloc_free(r);
 
        /* try the open again, which could trigger another retry setup
@@ -919,10 +1008,10 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
                                      struct ntvfs_request *req, 
                                      union smb_open *io,
                                      struct pvfs_file *f,
-                                     struct odb_lock *lck)
+                                     struct odb_lock *lck,
+                                     NTSTATUS parent_status)
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
-       struct pvfs_open_retry *r;
        NTSTATUS status;
        struct timeval end_time;
 
@@ -936,40 +1025,21 @@ static NTSTATUS pvfs_open_setup_retry(struct ntvfs_module_context *ntvfs,
                }
        }
 
-       r = talloc(req, struct pvfs_open_retry);
-       if (r == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       r->ntvfs = ntvfs;
-       r->req = req;
-       r->io = io;
-       r->odb_locking_key = data_blob_talloc(r, 
-                                             f->handle->odb_locking_key.data, 
-                                             f->handle->odb_locking_key.length);
-
-       end_time = timeval_add(&req->statistics.request_time, 0, pvfs->sharing_violation_delay);
-
-       /* setup a pending lock */
-       status = odb_open_file_pending(lck, r);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       talloc_free(lck);
+       /* the retry should allocate a new file handle */
        talloc_free(f);
 
-       talloc_set_destructor(r, pvfs_retry_destructor);
-
-       r->wait_handle = pvfs_wait_message(pvfs, req, MSG_PVFS_RETRY_OPEN, end_time, 
-                                          pvfs_open_retry, r);
-       if (r->wait_handle == NULL) {
-               return NT_STATUS_NO_MEMORY;
+       if (NT_STATUS_EQUAL(parent_status, NT_STATUS_SHARING_VIOLATION)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      0, pvfs->sharing_violation_delay);
+       } else if (NT_STATUS_EQUAL(parent_status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      pvfs->oplock_break_timeout, 0);
+       } else {
+               return NT_STATUS_INTERNAL_ERROR;
        }
 
-       talloc_steal(pvfs, r);
-
-       return NT_STATUS_OK;
+       return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
+                                   pvfs_retry_open_sharing);
 }
 
 /*
@@ -1133,6 +1203,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        f->handle->seek_offset       = 0;
        f->handle->position          = 0;
        f->handle->mode              = 0;
+       f->handle->oplock            = NULL;
        f->handle->have_opendb_entry = false;
        f->handle->sticky_write_time = false;
        f->handle->open_completed    = false;
@@ -1186,15 +1257,21 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        }
 
        /* see if we are allowed to open at the same time as existing opens */
-       status = odb_open_file(lck, f->handle, f->handle->name->stream_id,
+       status = odb_open_file(lck, f->handle, name->full_name, name->stream_id,
                               share_access, access_mask, del_on_close,
-                              name->full_name, oplock_level, &oplock_granted);
+                              io->generic.in.open_disposition,
+                              false, oplock_level, &oplock_granted);
 
-       /* on a sharing violation we need to retry when the file is closed by 
-          the other user, or after 1 second */
-       if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) &&
+       /*
+        * on a sharing violation we need to retry when the file is closed by
+        * the other user, or after 1 second
+        * on a non granted oplock we need to retry when the file is closed by
+        * the other user, or after 30 seconds
+       */
+       if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+            NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
            (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
-               return pvfs_open_setup_retry(ntvfs, req, io, f, lck);
+               return pvfs_open_setup_retry(ntvfs, req, io, f, lck, status);
        }
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -1204,6 +1281,12 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
 
        if (pvfs->flags & PVFS_FLAG_FAKE_OPLOCKS) {
                oplock_granted = OPLOCK_BATCH;
+       } else if (oplock_granted != OPLOCK_NONE) {
+               status = pvfs_setup_oplock(f, oplock_granted);
+               if (!NT_STATUS_IS_OK(status)) {
+                       talloc_free(lck);
+                       return status;
+               }
        }
 
        f->handle->have_opendb_entry = true;
@@ -1424,6 +1507,9 @@ NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
        NTSTATUS status;
        DATA_BLOB key;
        struct odb_lock *lck;
+       uint32_t share_access;
+       uint32_t access_mask;
+       bool delete_on_close;
 
        status = pvfs_locking_key(name, name, &key);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1436,15 +1522,18 @@ NTSTATUS pvfs_can_delete(struct pvfs_state *pvfs,
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       status = odb_can_open(lck,
-                             NTCREATEX_SHARE_ACCESS_READ |
-                             NTCREATEX_SHARE_ACCESS_WRITE | 
-                             NTCREATEX_SHARE_ACCESS_DELETE, 
-                             NTCREATEX_OPTIONS_DELETE_ON_CLOSE, 
-                             SEC_STD_DELETE);
+       share_access    = NTCREATEX_SHARE_ACCESS_READ |
+                         NTCREATEX_SHARE_ACCESS_WRITE |
+                         NTCREATEX_SHARE_ACCESS_DELETE;
+       access_mask     = SEC_STD_DELETE;
+       delete_on_close = true;
+
+       status = odb_can_open(lck, name->stream_id,
+                             share_access, access_mask, delete_on_close,
+                             NTCREATEX_DISP_OPEN, false);
 
        if (NT_STATUS_IS_OK(status)) {
-               status = pvfs_access_check_simple(pvfs, req, name, SEC_STD_DELETE);
+               status = pvfs_access_check_simple(pvfs, req, name, access_mask);
        }
 
        /*
@@ -1483,6 +1572,70 @@ NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
        NTSTATUS status;
        DATA_BLOB key;
        struct odb_lock *lck;
+       uint32_t share_access;
+       uint32_t access_mask;
+       bool delete_on_close;
+
+       status = pvfs_locking_key(name, name, &key);
+       if (!NT_STATUS_IS_OK(status)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       lck = odb_lock(req, pvfs->odb_context, &key);
+       if (lck == NULL) {
+               DEBUG(0,("Unable to lock opendb for can_stat\n"));
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       share_access    = NTCREATEX_SHARE_ACCESS_READ |
+                         NTCREATEX_SHARE_ACCESS_WRITE;
+       access_mask     = SEC_STD_DELETE;
+       delete_on_close = false;
+
+       status = odb_can_open(lck, name->stream_id,
+                             share_access, access_mask, delete_on_close,
+                             NTCREATEX_DISP_OPEN, false);
+
+       /*
+        * if it's a sharing violation or we got no oplock
+        * only keep the lock if the caller requested access
+        * to the lock
+        */
+       if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+           NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
+               if (lckp) {
+                       *lckp = lck;
+               } else {
+                       talloc_free(lck);
+               }
+       } else if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(lck);
+               if (lckp) {
+                       *lckp = NULL;
+               }
+       } else if (lckp) {
+               *lckp = lck;
+       }
+
+       return status;
+}
+
+/*
+  determine if the file size of a file can be changed,
+  or if it is prevented by an already open file
+*/
+NTSTATUS pvfs_can_update_file_size(struct pvfs_state *pvfs,
+                                  struct ntvfs_request *req,
+                                  struct pvfs_filename *name,
+                                  struct odb_lock **lckp)
+{
+       NTSTATUS status;
+       DATA_BLOB key;
+       struct odb_lock *lck;
+       uint32_t share_access;
+       uint32_t access_mask;
+       bool break_to_none;
+       bool delete_on_close;
 
        status = pvfs_locking_key(name, name, &key);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1495,11 +1648,25 @@ NTSTATUS pvfs_can_rename(struct pvfs_state *pvfs,
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       status = odb_can_open(lck,
-                             NTCREATEX_SHARE_ACCESS_READ |
-                             NTCREATEX_SHARE_ACCESS_WRITE,
-                             0,
-                             SEC_STD_DELETE);
+       share_access    = NTCREATEX_SHARE_ACCESS_READ |
+                         NTCREATEX_SHARE_ACCESS_WRITE |
+                         NTCREATEX_SHARE_ACCESS_DELETE;
+       /*
+        * I would have thought that we would need to pass
+        * SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA here too
+        *
+        * But you only need SEC_FILE_WRITE_ATTRIBUTE permissions
+        * to set the filesize.
+        *
+        * --metze
+        */
+       access_mask     = SEC_FILE_WRITE_ATTRIBUTE;
+       delete_on_close = false;
+       break_to_none   = true;
+
+       status = odb_can_open(lck, name->stream_id,
+                             share_access, access_mask, delete_on_close,
+                             NTCREATEX_DISP_OPEN, break_to_none);
 
        /*
         * if it's a sharing violation or we got no oplock
@@ -1536,6 +1703,9 @@ NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
        NTSTATUS status;
        DATA_BLOB key;
        struct odb_lock *lck;
+       uint32_t share_access;
+       uint32_t access_mask;
+       bool delete_on_close;
 
        status = pvfs_locking_key(name, name, &key);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1548,10 +1718,14 @@ NTSTATUS pvfs_can_stat(struct pvfs_state *pvfs,
                return NT_STATUS_INTERNAL_DB_CORRUPTION;
        }
 
-       status = odb_can_open(lck,
-                             NTCREATEX_SHARE_ACCESS_READ |
-                             NTCREATEX_SHARE_ACCESS_WRITE,
-                             0, 0);
+       share_access    = NTCREATEX_SHARE_ACCESS_READ |
+                         NTCREATEX_SHARE_ACCESS_WRITE;
+       access_mask     = SEC_FILE_READ_ATTRIBUTE;
+       delete_on_close = false;
+
+       status = odb_can_open(lck, name->stream_id,
+                             share_access, access_mask, delete_on_close,
+                             NTCREATEX_DISP_OPEN, false);
 
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(lck);
diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c
new file mode 100644 (file)
index 0000000..cf30ddb
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+   Unix SMB/CIFS implementation.
+
+   POSIX NTVFS backend - oplock handling
+
+   Copyright (C) Stefan Metzmacher 2008
+
+   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 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "lib/messaging/messaging.h"
+#include "lib/messaging/irpc.h"
+#include "vfs_posix.h"
+
+
+struct pvfs_oplock {
+       struct pvfs_file_handle *handle;
+       struct pvfs_file *file;
+       uint32_t level;
+       struct messaging_context *msg_ctx;
+};
+
+/*
+  receive oplock breaks and forward them to the client
+*/
+static void pvfs_oplock_break(struct pvfs_oplock *opl, uint8_t level)
+{
+       NTSTATUS status;
+       struct pvfs_file *f = opl->file;
+       struct pvfs_file_handle *h = opl->handle;
+       struct pvfs_state *pvfs = h->pvfs;
+
+       DEBUG(10,("pvfs_oplock_break: sending oplock break level %d for '%s' %p\n",
+               level, h->name->original_name, h));
+       status = ntvfs_send_oplock_break(pvfs->ntvfs, f->ntvfs, level);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("pvfs_oplock_break: sending oplock break failed: %s\n",
+                       nt_errstr(status)));
+       }
+}
+
+static void pvfs_oplock_break_dispatch(struct messaging_context *msg,
+                                      void *private_data, uint32_t msg_type,
+                                      struct server_id src, DATA_BLOB *data)
+{
+       struct pvfs_oplock *opl = talloc_get_type(private_data,
+                                                 struct pvfs_oplock);
+       struct opendb_oplock_break opb;
+
+       ZERO_STRUCT(opb);
+
+       /* we need to check that this one is for us. See
+          messaging_send_ptr() for the other side of this.
+        */
+       if (data->length == sizeof(struct opendb_oplock_break)) {
+               struct opendb_oplock_break *p;
+               p = (struct opendb_oplock_break *)data->data;
+               opb = *p;
+       } else {
+               DEBUG(0,("%s: ignore oplock break with length[%u]\n",
+                       __location__, data->length));
+               return;
+       }
+       if (opb.file_handle != opl->handle) {
+               return;
+       }
+
+       /*
+        * maybe we should use ntvfs_setup_async()
+        */
+       pvfs_oplock_break(opl, opb.level);
+}
+
+static int pvfs_oplock_destructor(struct pvfs_oplock *opl)
+{
+       messaging_deregister(opl->msg_ctx, MSG_NTVFS_OPLOCK_BREAK, opl);
+       return 0;
+}
+
+NTSTATUS pvfs_setup_oplock(struct pvfs_file *f, uint32_t oplock_granted)
+{
+       NTSTATUS status;
+       struct pvfs_oplock *opl;
+       uint32_t level = OPLOCK_NONE;
+
+       f->handle->oplock = NULL;
+
+       switch (oplock_granted) {
+       case EXCLUSIVE_OPLOCK_RETURN:
+               level = OPLOCK_EXCLUSIVE;
+               break;
+       case BATCH_OPLOCK_RETURN:
+               level = OPLOCK_BATCH;
+               break;
+       case LEVEL_II_OPLOCK_RETURN:
+               level = OPLOCK_LEVEL_II;
+               break;
+       }
+
+       if (level == OPLOCK_NONE) {
+               return NT_STATUS_OK;
+       }
+
+       opl = talloc(f->handle, struct pvfs_oplock);
+       NT_STATUS_HAVE_NO_MEMORY(opl);
+
+       opl->handle     = f->handle;
+       opl->file       = f;
+       opl->level      = level;
+       opl->msg_ctx    = f->pvfs->ntvfs->ctx->msg_ctx;
+
+       status = messaging_register(opl->msg_ctx,
+                                   opl,
+                                   MSG_NTVFS_OPLOCK_BREAK,
+                                   pvfs_oplock_break_dispatch);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       /* destructor */
+       talloc_set_destructor(opl, pvfs_oplock_destructor);
+
+       f->handle->oplock = opl;
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS pvfs_oplock_release(struct ntvfs_module_context *ntvfs,
+                            struct ntvfs_request *req, union smb_lock *lck)
+{
+       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct pvfs_file *f;
+       struct pvfs_file_handle *h;
+       struct odb_lock *olck;
+       uint8_t oplock_break;
+       NTSTATUS status;
+
+       f = pvfs_find_fd(pvfs, req, lck->lockx.in.file.ntvfs);
+       if (!f) {
+               return NT_STATUS_INVALID_HANDLE;
+       }
+
+       h = f->handle;
+
+       if (h->fd == -1) {
+               return NT_STATUS_FILE_IS_A_DIRECTORY;
+       }
+
+       if (!h->have_opendb_entry) {
+               return NT_STATUS_FOOBAR;
+       }
+
+       if (!h->oplock) {
+               return NT_STATUS_FOOBAR;
+       }
+
+       olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
+       if (olck == NULL) {
+               DEBUG(0,("Unable to lock opendb for oplock update\n"));
+               return NT_STATUS_FOOBAR;
+       }
+
+       oplock_break = (lck->lockx.in.mode >> 8) & 0xFF;
+       if (oplock_break == OPLOCK_BREAK_TO_NONE) {
+               h->oplock->level = OPLOCK_NONE;
+       } else if (oplock_break == OPLOCK_BREAK_TO_LEVEL_II) {
+               h->oplock->level = OPLOCK_LEVEL_II;
+       } else {
+               /* fallback to level II in case of a invalid value */
+               DEBUG(1,("unexpected oplock break level[0x%02X]\n", oplock_break));
+               h->oplock->level = OPLOCK_LEVEL_II;
+       }
+       status = odb_update_oplock(olck, h, h->oplock->level);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("Unable to update oplock level for '%s' - %s\n",
+                        h->name->full_name, nt_errstr(status)));
+               talloc_free(olck);
+               return status;
+       }
+
+       talloc_free(olck);
+
+       /* after a break to none, we no longer have an oplock attached */
+       if (h->oplock->level == OPLOCK_NONE) {
+               talloc_free(h->oplock);
+               h->oplock = NULL;
+       }
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS pvfs_break_level2_oplocks(struct pvfs_file *f)
+{
+       struct pvfs_file_handle *h = f->handle;
+       struct odb_lock *olck;
+       NTSTATUS status;
+
+       if (h->oplock && h->oplock->level == OPLOCK_EXCLUSIVE) {
+               return NT_STATUS_OK;
+       }
+
+       olck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
+       if (olck == NULL) {
+               DEBUG(0,("Unable to lock opendb for oplock update\n"));
+               return NT_STATUS_FOOBAR;
+       }
+
+       if (h->oplock && h->oplock->level == OPLOCK_BATCH) {
+               status = odb_update_oplock(olck, h, OPLOCK_LEVEL_II);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,("Unable to update oplock level for '%s' - %s\n",
+                                h->name->full_name, nt_errstr(status)));
+                       talloc_free(olck);
+                       return status;
+               }
+       }
+
+       status = odb_break_oplocks(olck);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("Unable to break level2 oplocks to none for '%s' - %s\n",
+                        h->name->full_name, nt_errstr(status)));
+               talloc_free(olck);
+               return status;
+       }
+
+       talloc_free(olck);
+
+       return NT_STATUS_OK;
+}
index 2f01c08fb07d3e082d65989a121d46707b9ab468..8d23d707a430d11398ec5440fa7ab672c43513f5 100644 (file)
@@ -330,7 +330,7 @@ NTSTATUS pvfs_qpathinfo(struct ntvfs_module_context *ntvfs,
 
        status = pvfs_can_stat(pvfs, req, name);
        if (!NT_STATUS_IS_OK(status)) {
-               return NT_STATUS_DELETE_PENDING;
+               return status;
        }
 
        status = pvfs_access_check_simple(pvfs, req, name, 
index 5693e793141c7e51854092e5085eb34037bb66ab..3c60c00247442829cb37443325772b74185ebc0c 100644 (file)
@@ -180,6 +180,84 @@ static const char *pvfs_resolve_wildcard(TALLOC_CTX *mem_ctx,
        return talloc_asprintf(mem_ctx, "%s.%s", base1, ext1);
 }
 
+/*
+  retry an rename after a sharing violation
+*/
+static void pvfs_retry_rename(struct pvfs_odb_retry *r,
+                             struct ntvfs_module_context *ntvfs,
+                             struct ntvfs_request *req,
+                             void *_io,
+                             void *private_data,
+                             enum pvfs_wait_notice reason)
+{
+       union smb_rename *io = talloc_get_type(_io, union smb_rename);
+       NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
+
+       talloc_free(r);
+
+       switch (reason) {
+       case PVFS_WAIT_CANCEL:
+/*TODO*/
+               status = NT_STATUS_CANCELLED;
+               break;
+       case PVFS_WAIT_TIMEOUT:
+               /* if it timed out, then give the failure
+                  immediately */
+/*TODO*/
+               status = NT_STATUS_SHARING_VIOLATION;
+               break;
+       case PVFS_WAIT_EVENT:
+
+               /* try the open again, which could trigger another retry setup
+                  if it wants to, so we have to unmark the async flag so we
+                  will know if it does a second async reply */
+               req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
+
+               status = pvfs_rename(ntvfs, req, io);
+               if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
+                       /* the 2nd try also replied async, so we don't send
+                          the reply yet */
+                       return;
+               }
+
+               /* re-mark it async, just in case someone up the chain does
+                  paranoid checking */
+               req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+               break;
+       }
+
+       /* send the reply up the chain */
+       req->async_states->status = status;
+       req->async_states->send_fn(req);
+}
+
+/*
+  setup for a rename retry after a sharing violation
+  or a non granted oplock
+*/
+static NTSTATUS pvfs_rename_setup_retry(struct ntvfs_module_context *ntvfs,
+                                       struct ntvfs_request *req,
+                                       union smb_rename *io,
+                                       struct odb_lock *lck,
+                                       NTSTATUS status)
+{
+       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct timeval end_time;
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      0, pvfs->sharing_violation_delay);
+       } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      pvfs->oplock_break_timeout, 0);
+       } else {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
+                                   pvfs_retry_rename);
+}
+
 /*
   rename one file from a wildcard set
 */
@@ -354,8 +432,19 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
        }
 
        status = pvfs_can_rename(pvfs, req, name1, &lck);
+       /*
+        * on a sharing violation we need to retry when the file is closed by
+        * the other user, or after 1 second
+        * on a non granted oplock we need to retry when the file is closed by
+        * the other user, or after 30 seconds
+        */
+       if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+            NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
+           (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
+               return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status);
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
-               talloc_free(lck);
                return status;
        }
 
@@ -377,6 +466,7 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
        struct pvfs_state *pvfs = ntvfs->private_data;
        NTSTATUS status;
        struct pvfs_filename *name1, *name2;
+       struct odb_lock *lck = NULL;
 
        switch (ren->ntrename.in.flags) {
        case RENAME_FLAG_RENAME:
@@ -422,7 +512,18 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
                return status;
        }
 
-       status = pvfs_can_rename(pvfs, req, name1, NULL);
+       status = pvfs_can_rename(pvfs, req, name1, &lck);
+       /*
+        * on a sharing violation we need to retry when the file is closed by
+        * the other user, or after 1 second
+        * on a non granted oplock we need to retry when the file is closed by
+        * the other user, or after 30 seconds
+        */
+       if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+            NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
+           (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
+               return pvfs_rename_setup_retry(pvfs->ntvfs, req, ren, lck, status);
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -432,6 +533,9 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
                status = pvfs_access_check_parent(pvfs, req, name2, SEC_DIR_ADD_FILE);
                NT_STATUS_NOT_OK_RETURN(status);
                status = pvfs_do_rename(pvfs, name1, name2->full_name);
+               if (NT_STATUS_IS_OK(status)) {
+                       status = odb_rename(lck, name2->full_name);
+               }
                NT_STATUS_NOT_OK_RETURN(status);
                break;
 
index fbbb8c2d4baeb3b1ab85a5c5171377d7add6ddee..da1e31e63904bc397c0cf230c9ea4c8ff2b610cb 100644 (file)
@@ -152,6 +152,9 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
                }
 
                status = pvfs_can_delete(pvfs, req, name2, NULL);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
+                       return NT_STATUS_ACCESS_DENIED;
+               }
                if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
                        return NT_STATUS_ACCESS_DENIED;
                }
@@ -352,6 +355,9 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
 
        case RAW_SFILEINFO_ALLOCATION_INFO:
        case RAW_SFILEINFO_ALLOCATION_INFORMATION:
+               status = pvfs_break_level2_oplocks(f);
+               NT_STATUS_NOT_OK_RETURN(status);
+
                newstats.dos.alloc_size = info->allocation_info.in.alloc_size;
                if (newstats.dos.alloc_size < newstats.st.st_size) {
                        newstats.st.st_size = newstats.dos.alloc_size;
@@ -362,6 +368,9 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
 
        case RAW_SFILEINFO_END_OF_FILE_INFO:
        case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
+               status = pvfs_break_level2_oplocks(f);
+               NT_STATUS_NOT_OK_RETURN(status);
+
                newstats.st.st_size = info->end_of_file_info.in.size;
                break;
 
@@ -463,6 +472,84 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
        return pvfs_dosattrib_save(pvfs, h->name, h->fd);
 }
 
+/*
+  retry an open after a sharing violation
+*/
+static void pvfs_retry_setpathinfo(struct pvfs_odb_retry *r,
+                                  struct ntvfs_module_context *ntvfs,
+                                  struct ntvfs_request *req,
+                                  void *_info,
+                                  void *private_data,
+                                  enum pvfs_wait_notice reason)
+{
+       union smb_setfileinfo *info = talloc_get_type(_info,
+                                     union smb_setfileinfo);
+       NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
+
+       talloc_free(r);
+
+       switch (reason) {
+       case PVFS_WAIT_CANCEL:
+/*TODO*/
+               status = NT_STATUS_CANCELLED;
+               break;
+       case PVFS_WAIT_TIMEOUT:
+               /* if it timed out, then give the failure
+                  immediately */
+/*TODO*/
+               status = NT_STATUS_SHARING_VIOLATION;
+               break;
+       case PVFS_WAIT_EVENT:
+
+               /* try the open again, which could trigger another retry setup
+                  if it wants to, so we have to unmark the async flag so we
+                  will know if it does a second async reply */
+               req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
+
+               status = pvfs_setpathinfo(ntvfs, req, info);
+               if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
+                       /* the 2nd try also replied async, so we don't send
+                          the reply yet */
+                       return;
+               }
+
+               /* re-mark it async, just in case someone up the chain does
+                  paranoid checking */
+               req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+               break;
+       }
+
+       /* send the reply up the chain */
+       req->async_states->status = status;
+       req->async_states->send_fn(req);
+}
+
+/*
+  setup for a unlink retry after a sharing violation
+  or a non granted oplock
+*/
+static NTSTATUS pvfs_setpathinfo_setup_retry(struct ntvfs_module_context *ntvfs,
+                                            struct ntvfs_request *req,
+                                            union smb_setfileinfo *info,
+                                            struct odb_lock *lck,
+                                            NTSTATUS status)
+{
+       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct timeval end_time;
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      0, pvfs->sharing_violation_delay);
+       } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      pvfs->oplock_break_timeout, 0);
+       } else {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, info, NULL,
+                                   pvfs_retry_setpathinfo);
+}
 
 /*
   set info on a pathname
@@ -477,6 +564,7 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
        struct utimbuf unix_times;
        uint32_t access_needed;
        uint32_t change_mask = 0;
+       struct odb_lock *lck = NULL;
 
        /* resolve the cifs name to a posix name */
        status = pvfs_resolve_name(pvfs, req, info->generic.in.file.path, 
@@ -551,6 +639,20 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
 
        case RAW_SFILEINFO_ALLOCATION_INFO:
        case RAW_SFILEINFO_ALLOCATION_INFORMATION:
+               status = pvfs_can_update_file_size(pvfs, req, name, &lck);
+               /*
+                * on a sharing violation we need to retry when the file is closed by
+                * the other user, or after 1 second
+                * on a non granted oplock we need to retry when the file is closed by
+                * the other user, or after 30 seconds
+               */
+               if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+                    NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
+                   (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
+                       return pvfs_setpathinfo_setup_retry(pvfs->ntvfs, req, info, lck, status);
+               }
+               NT_STATUS_NOT_OK_RETURN(status);
+
                if (info->allocation_info.in.alloc_size > newstats.dos.alloc_size) {
                        /* strange. Increasing the allocation size via setpathinfo 
                           should be silently ignored */
@@ -566,6 +668,20 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
 
        case RAW_SFILEINFO_END_OF_FILE_INFO:
        case RAW_SFILEINFO_END_OF_FILE_INFORMATION:
+               status = pvfs_can_update_file_size(pvfs, req, name, &lck);
+               /*
+                * on a sharing violation we need to retry when the file is closed by
+                * the other user, or after 1 second
+                * on a non granted oplock we need to retry when the file is closed by
+                * the other user, or after 30 seconds
+               */
+               if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+                    NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
+                   (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
+                       return pvfs_setpathinfo_setup_retry(pvfs->ntvfs, req, info, lck, status);
+               }
+               NT_STATUS_NOT_OK_RETURN(status);
+
                newstats.st.st_size = info->end_of_file_info.in.size;
                break;
 
index bda4014beec16c8a701347d0e6d8a36188350627..7a2d964b9dd82d82a90f504c19b88d538458909b 100644 (file)
 #include "vfs_posix.h"
 #include "system/dir.h"
 
+/*
+  retry an open after a sharing violation
+*/
+static void pvfs_retry_unlink(struct pvfs_odb_retry *r,
+                             struct ntvfs_module_context *ntvfs,
+                             struct ntvfs_request *req,
+                             void *_io,
+                             void *private_data,
+                             enum pvfs_wait_notice reason)
+{
+       union smb_unlink *io = talloc_get_type(_io, union smb_unlink);
+       NTSTATUS status = NT_STATUS_INTERNAL_ERROR;
+
+       talloc_free(r);
+
+       switch (reason) {
+       case PVFS_WAIT_CANCEL:
+/*TODO*/
+               status = NT_STATUS_CANCELLED;
+               break;
+       case PVFS_WAIT_TIMEOUT:
+               /* if it timed out, then give the failure
+                  immediately */
+/*TODO*/
+               status = NT_STATUS_SHARING_VIOLATION;
+               break;
+       case PVFS_WAIT_EVENT:
+
+               /* try the open again, which could trigger another retry setup
+                  if it wants to, so we have to unmark the async flag so we
+                  will know if it does a second async reply */
+               req->async_states->state &= ~NTVFS_ASYNC_STATE_ASYNC;
+
+               status = pvfs_unlink(ntvfs, req, io);
+               if (req->async_states->state & NTVFS_ASYNC_STATE_ASYNC) {
+                       /* the 2nd try also replied async, so we don't send
+                          the reply yet */
+                       return;
+               }
+
+               /* re-mark it async, just in case someone up the chain does
+                  paranoid checking */
+               req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+               break;
+       }
+
+       /* send the reply up the chain */
+       req->async_states->status = status;
+       req->async_states->send_fn(req);
+}
+
+/*
+  setup for a unlink retry after a sharing violation
+  or a non granted oplock
+*/
+static NTSTATUS pvfs_unlink_setup_retry(struct ntvfs_module_context *ntvfs,
+                                       struct ntvfs_request *req,
+                                       union smb_unlink *io,
+                                       struct odb_lock *lck,
+                                       NTSTATUS status)
+{
+       struct pvfs_state *pvfs = ntvfs->private_data;
+       struct timeval end_time;
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      0, pvfs->sharing_violation_delay);
+       } else if (NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) {
+               end_time = timeval_add(&req->statistics.request_time,
+                                      pvfs->oplock_break_timeout, 0);
+       } else {
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
+                                   pvfs_retry_unlink);
+}
+
 
 /*
   unlink a file
@@ -67,6 +145,7 @@ static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
                                struct pvfs_filename *name)
 {
        NTSTATUS status;
+       struct odb_lock *lck = NULL;
 
        /* make sure its matches the given attributes */
        status = pvfs_match_attrib(pvfs, name,
@@ -75,7 +154,20 @@ static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
                return status;
        }
 
-       status = pvfs_can_delete(pvfs, req, name, NULL);
+       status = pvfs_can_delete(pvfs, req, name, &lck);
+
+       /*
+        * on a sharing violation we need to retry when the file is closed by
+        * the other user, or after 1 second
+        * on a non granted oplock we need to retry when the file is closed by
+        * the other user, or after 30 seconds
+        */
+       if ((NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION) ||
+            NT_STATUS_EQUAL(status, NT_STATUS_OPLOCK_NOT_GRANTED)) &&
+           (req->async_states->state & NTVFS_ASYNC_STATE_MAY_ASYNC)) {
+               return pvfs_unlink_setup_retry(pvfs->ntvfs, req, unl, lck, status);
+       }
+
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
index 5a11f01952bb19e4f91524b02315b82cf1c9837d..dda8c8340738e4b8d16e1f12200ab83934d3a6a7 100644 (file)
@@ -57,7 +57,10 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
                                 wr->writex.in.count,
                                 WRITE_LOCK);
        NT_STATUS_NOT_OK_RETURN(status);
-       
+
+       status = pvfs_break_level2_oplocks(f);
+       NT_STATUS_NOT_OK_RETURN(status);
+
        if (f->handle->name->stream_name) {
                ret = pvfs_stream_write(pvfs,
                                        f->handle,
index e058e6f546d64167e6fd81e1cefb436f7d5f8966..ca874d1db1f0551a901c5a39cafe00a481f3f5f3 100644 (file)
@@ -91,6 +91,10 @@ static void pvfs_setup_options(struct pvfs_state *pvfs)
                                                        PVFS_SHARE_DELAY,
                                                        PVFS_SHARE_DELAY_DEFAULT);
 
+       pvfs->oplock_break_timeout = share_int_option(scfg,
+                                                     PVFS_OPLOCK_TIMEOUT,
+                                                     PVFS_OPLOCK_TIMEOUT_DEFAULT);
+
        pvfs->share_name = talloc_strdup(pvfs, scfg->name);
 
        pvfs->fs_attribs = 
index 84c456dcfee48f644ed74a6022db7498087d37f0..4d22a917149c7d0f7aff4c6c21d53b7de1640a1c 100644 (file)
@@ -29,6 +29,7 @@
 #include "dsdb/samdb/samdb.h"
 
 struct pvfs_wait;
+struct pvfs_oplock;
 
 /* this is the private structure for the posix vfs backend. It is used
    to hold per-connection (per tree connect) state information */
@@ -51,9 +52,12 @@ struct pvfs_state {
           ntcancel */
        struct pvfs_wait *wait_list;
 
-       /* the sharing violation timeout */
+       /* the sharing violation timeout (nsecs) */
        uint_t sharing_violation_delay;
 
+       /* the oplock break timeout (secs) */
+       uint_t oplock_break_timeout;
+
        /* filesystem attributes (see FS_ATTR_*) */
        uint32_t fs_attribs;
 
@@ -154,6 +158,13 @@ struct pvfs_file_handle {
 
        bool have_opendb_entry;
 
+       /*
+        * we need to wait for oplock break requests from other processes,
+        * and we need to remember the pvfs_file so we can correctly
+        * forward the oplock break to the client
+        */
+       struct pvfs_oplock *oplock;
+
        /* we need this hook back to our parent for lock destruction */
        struct pvfs_state *pvfs;
 
@@ -230,10 +241,16 @@ struct pvfs_dir;
 /* types of notification for pvfs wait events */
 enum pvfs_wait_notice {PVFS_WAIT_EVENT, PVFS_WAIT_TIMEOUT, PVFS_WAIT_CANCEL};
 
+/*
+  state of a pending retry
+*/
+struct pvfs_odb_retry;
+
 #define PVFS_EADB                      "posix:eadb"
 #define PVFS_XATTR                     "posix:xattr"
 #define PVFS_FAKE_OPLOCKS              "posix:fakeoplocks"
 #define PVFS_SHARE_DELAY               "posix:sharedelay"
+#define PVFS_OPLOCK_TIMEOUT            "posix:oplocktimeout"
 #define PVFS_ALLOCATION_ROUNDING       "posix:allocationrounding"
 #define PVFS_SEARCH_INACTIVITY         "posix:searchinactivity"
 #define PVFS_ACL                       "posix:acl"
@@ -241,7 +258,8 @@ enum pvfs_wait_notice {PVFS_WAIT_EVENT, PVFS_WAIT_TIMEOUT, PVFS_WAIT_CANCEL};
 
 #define PVFS_XATTR_DEFAULT                     true
 #define PVFS_FAKE_OPLOCKS_DEFAULT              false
-#define PVFS_SHARE_DELAY_DEFAULT               1000000
+#define PVFS_SHARE_DELAY_DEFAULT               1000000 /* nsecs */
+#define PVFS_OPLOCK_TIMEOUT_DEFAULT            30 /* secs */
 #define PVFS_ALLOCATION_ROUNDING_DEFAULT       512
 #define PVFS_SEARCH_INACTIVITY_DEFAULT         300
 
index 2c97625bccd9c6c9dc4d008cd4d01a59bed97057..bc2999b03d1666204b90bee3ce98f7b4ad6442ed 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
    
-   Modular services configuration system
+   Modular shares configuration system
    
    Copyright (C) Simo Sorce    2006
    
index b517c9c4c25165d5d15a0bc39ef198ad4e014acb..eb5e486c449957480a7fa9544c4c56303c23d32a 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
    
-   Classic file based services configuration
+   Classic file based shares configuration
    
    Copyright (C) Simo Sorce    2006
    
index bdea94a5cd46d3a04d1ffdafce9113066a2d76cc..fb40f1e9bfe8be040e3480ea91dd26eccebc1787 100644 (file)
@@ -1,7 +1,7 @@
 /* 
    Unix SMB/CIFS implementation.
    
-   LDB based services configuration
+   LDB based shares configuration
    
    Copyright (C) Simo Sorce    2006
    
index 028b628e18d06e3270fc815fc5637a12c3e18e5b..c7ca0c76042f6f24ccd8f3c9abdb4c6394ca268d 100644 (file)
@@ -391,7 +391,7 @@ sub _Error {
                error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
                delete $_[0]->YYData->{ERRMSG};
                return;
-       };
+       }
        my $last_token = $_[0]->YYData->{LAST_TOKEN};
        
        error($_[0]->YYData, "Syntax error near '$last_token'");
index aeee69e3063e21fbb6a4c38b76cd1177aff6afa4..4adb4dcea8c16eee29ec60b720cbe2c6f5dc02cb 100644 (file)
@@ -2408,7 +2408,7 @@ sub _Error {
                error($_[0]->YYData, $_[0]->YYData->{ERRMSG});
                delete $_[0]->YYData->{ERRMSG};
                return;
-       };
+       }
        my $last_token = $_[0]->YYData->{LAST_TOKEN};
        
        error($_[0]->YYData, "Syntax error near '$last_token'");
index b6a54fae255c3f8b03b91a1568407f67d292e5b7..9791466712368350492dec554b05917706377751 100644 (file)
@@ -100,6 +100,13 @@ check:: test
 unused_macros:
        $(srcdir)/script/find_unused_macros.pl `find . -name "*.[ch]"` | sort
 
+# Create a static library
+%.a:
+       @echo Linking $@
+       @rm -f $@
+       @mkdir -p $(@D)
+       @$(STLD) $(STLD_FLAGS) $@ $^
+
 ###############################################################################
 # File types
 ###############################################################################
index 18fb4b914bbfaef1c12888496ea4d1c0ac901519..aaa11774aea8ca73457e4a464fbd7514cdfa8cd4 100644 (file)
@@ -3,7 +3,8 @@ local.iconv.*.next_codepoint()
 base.delaywrite.finfo update on close
 base.delete.*.deltest20a
 base.delete.*.deltest20b
-raw.oplock.*.OPLOCK
+raw.oplock.*BATCH19
+raw.oplock.*BATCH20
 rpc.winreg
 local.registry.*.security # Not implemented yet
 rpc.wkssvc
index 541738ecc4e444aa05de43a09aa322de0ab665d5..4d2da6ed646434e1a31b22c17c481d8593f8372c 100644 (file)
@@ -1,12 +1,10 @@
 base.delaywrite
 raw.composite
-raw.oplock
 base.iometer
 base.casetable
 base.nttrans
 .*base.bench.holdcon.*                         # Very slow
 base.scan.maxfid
-raw.bench.oplock
 raw.hold.oplock
 raw.ping.pong
 rpc.samr_accessmask
@@ -25,9 +23,7 @@ ntvfs.cifs.base.scan-maxfid
 ntvfs.cifs.base.utable
 ntvfs.cifs.base.smb
 ntvfs.cifs.raw.composite
-ntvfs.cifs.raw.oplock
 ntvfs.cifs.raw.notify
-ntvfs.cifs.raw.bench-oplock
 ntvfs.cifs.raw.scan-eamax
 ntvfs.cifs.raw.context
 ntvfs.cifs.raw.qfileinfo.ipc
index 37e3cbe3549f09561dac353b0952b8161e551fc1..e0be8048a0c5ce744d7e4f74e8e7fd188d050729 100644 (file)
@@ -562,12 +562,16 @@ sub provision($$$$$$)
        gensec:require_pac = true
        log level = $smbd_loglevel
 
+       # this is a global option
+       opendb:oplocks = yes
+
 [tmp]
        path = $tmpdir
        read only = no
        ntvfs handler = posix
        posix:sharedelay = 100000
        posix:eadb = $lockdir/eadb.tdb
+       posix:oplocktimeout = 3
 
 [test1]
        path = $tmpdir/test1
@@ -575,6 +579,7 @@ sub provision($$$$$$)
        ntvfs handler = posix
        posix:sharedelay = 100000
        posix:eadb = $lockdir/eadb.tdb
+       posix:oplocktimeout = 3
 
 [test2]
        path = $tmpdir/test2
@@ -582,6 +587,7 @@ sub provision($$$$$$)
        ntvfs handler = posix
        posix:sharedelay = 100000
        posix:eadb = $lockdir/eadb.tdb
+       posix:oplocktimeout = 3
 
 [cifs]
        read only = no
index 892b5ec50c236fb658c59905478a85eaa6e6435f..b80db09c098015490cbe44b5383049fbf2899aa6 100644 (file)
@@ -2,37 +2,46 @@ REGEDIT4
 
 [HKEY_LOCAL_MACHINE]
 
-[HKEY_LOCAL_MACHINE\System]
+[HKEY_LOCAL_MACHINE\SOFTWARE]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet]
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control]
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ProductOptions]
+[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion]
+CurrentVersion=5.2
+
+[HKEY_LOCAL_MACHINE\SYSTEM]
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet]
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control]
+
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ProductOptions]
 ProductType=LanmanNT
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Print]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server]
 
-[HKEY_LOCAL_MACHINE\System]
+[HKEY_LOCAL_MACHINE\SYSTEM]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Netlogon]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Netlogon\Parameters]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters]
 RefusePasswordChange=REG_DWORD:0
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\REPLICATOR]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\REPLICATOR]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\REPLICATOR\Parameters]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\REPLICATOR\Parameters]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Alerter]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Alerter]
 
-[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Alerter\Parameters]
+[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Alerter\Parameters]
 
 [HKEY_USERS]
 
index 7e1f6493ee8409eeb977032dc271ad777ab1ae3b..23cf830b291ea1af1fadb56cc9c2f9c5216a133c 100644 (file)
@@ -174,6 +174,7 @@ static void stream_new_connection(struct event_context *ev,
        srv_conn->server_id     = server_id;
        srv_conn->ops           = stream_socket->ops;
        srv_conn->event.ctx     = ev;
+       srv_conn->lp_ctx        = lp_ctx;
        srv_conn->event.fde     = event_add_fd(ev, srv_conn, socket_get_fd(sock),
                                               0, stream_io_handler_fde, srv_conn);
 
index 42d7ddaaa12e4c60c7a6a4c181e227eb51434b0b..66f9359744d5b6217cf42c016942bb5ccf94fa5d 100644 (file)
@@ -664,7 +664,7 @@ static bool run_deferopen(struct torture_context *tctx, struct smbcli_state *cli
                        }
                        if (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),NT_STATUS_SHARING_VIOLATION)) {
                                double e = timeval_elapsed(&tv);
-                               if (e < (0.5 * sec) || e > (1.5 * sec)) {
+                               if (e < (0.5 * sec) || e > ((1.5 * sec) + 1)) {
                                        torture_comment(tctx,"Timing incorrect %.2f violation 1 sec == %.2f\n",
                                                e, sec);
                                        return false;
index 3edd0c68205f19e24b3f0fdb6ca19f947214d856..7ac88c09968da5587104f122757cb8a8ef5c1636 100644 (file)
 
 #define CHECK_VAL(v, correct) do { \
        if ((v) != (correct)) { \
-               torture_comment(tctx, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
+               torture_result(tctx, TORTURE_FAIL, "(%s): wrong value for %s got 0x%x - should be 0x%x\n", \
                                __location__, #v, (int)v, (int)correct); \
                ret = false; \
        }} while (0)
 
+#define CHECK_STRMATCH(v, correct) do { \
+       if (!v || strstr((v),(correct)) == NULL) { \
+               torture_result(tctx, TORTURE_FAIL,  "(%s): wrong value for %s got '%s' - should be '%s'\n", \
+                               __location__, #v, v?v:"NULL", correct); \
+               ret = false; \
+       } \
+} while (0)
+
 #define CHECK_STATUS(tctx, status, correct) do { \
        if (!NT_STATUS_EQUAL(status, correct)) { \
                torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
@@ -123,9 +131,9 @@ static bool oplock_handler_close(struct smbcli_transport *transport, uint16_t ti
        return true;
 }
 
-static bool test_raw_oplock_normal(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_exclusive1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_normal.dat";
+       const char *fname = BASEDIR "\\test_exclusive1.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
@@ -156,7 +164,7 @@ static bool test_raw_oplock_normal(struct torture_context *tctx, struct smbcli_s
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
-       torture_comment(tctx, "open a file with a normal oplock\n");
+       torture_comment(tctx, "open a file with an exclusive oplock (share mode: none)\n");
        ZERO_STRUCT(break_info);
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
 
@@ -188,15 +196,14 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_exclusive2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch1.dat";
+       const char *fname = BASEDIR "\\test_exclusive2.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
        union smb_unlink unl;
-       uint16_t fnum=0;
-       char c = 0;
+       uint16_t fnum=0, fnum2=0;
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
@@ -222,48 +229,59 @@ static bool test_raw_oplock_batch1(struct torture_context *tctx, struct smbcli_s
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
-       /*
-         with a batch oplock we get a break
-       */
-       torture_comment(tctx, "open with batch oplock\n");
+       torture_comment(tctx, "open a file with an exclusive oplock (share mode: all)\n");
        ZERO_STRUCT(break_info);
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
-               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
-
-       torture_comment(tctx, "unlink should generate a break\n");
-       unl.unlink.in.pattern = fname;
-       unl.unlink.in.attrib = 0;
-       status = smb_raw_unlink(cli2->tree, &unl);
-       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
 
+       torture_comment(tctx, "a 2nd open should cause a break to level 2\n");
+       status = smb_raw_open(cli2->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
        CHECK_VAL(break_info.count, 1);
        CHECK_VAL(break_info.fnum, fnum);
        CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
        CHECK_VAL(break_info.failures, 0);
-
-       torture_comment(tctx, "2nd unlink should not generate a break\n");
        ZERO_STRUCT(break_info);
+
+       /* now we have 2 level II oplocks... */
+       torture_comment(tctx, "try to unlink it - should not cause a break, but a sharing violation\n");
+       unl.unlink.in.pattern = fname;
+       unl.unlink.in.attrib = 0;
        status = smb_raw_unlink(cli2->tree, &unl);
        CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
-
        CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.failures, 0);
 
-       torture_comment(tctx, "writing should generate a self break to none\n");
-       smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
-       msleep(100);
-       smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
+       torture_comment(tctx, "close 1st handle\n");
+       smbcli_close(cli1->tree, fnum);
 
-       CHECK_VAL(break_info.count, 1);
-       CHECK_VAL(break_info.fnum, fnum);
-       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
+       torture_comment(tctx, "try to unlink it - should not cause a break, but a sharing violation\n");
+       unl.unlink.in.pattern = fname;
+       unl.unlink.in.attrib = 0;
+       status = smb_raw_unlink(cli2->tree, &unl);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+       CHECK_VAL(break_info.count, 0);
        CHECK_VAL(break_info.failures, 0);
 
-       smbcli_close(cli1->tree, fnum);
+       torture_comment(tctx, "close 1st handle\n");
+       smbcli_close(cli2->tree, fnum2);
+
+       torture_comment(tctx, "unlink it\n");
+       unl.unlink.in.pattern = fname;
+       unl.unlink.in.attrib = 0;
+       status = smb_raw_unlink(cli2->tree, &unl);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.failures, 0);
 
 done:
        smb_raw_exit(cli1->session);
@@ -272,15 +290,15 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_exclusive3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch2.dat";
+       const char *fname = BASEDIR "\\test_exclusive3.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
-       union smb_unlink unl;
+       union smb_setfileinfo sfi;
        uint16_t fnum=0;
-       char c = 0;
+       bool s3 = torture_setting_bool(tctx, "samba3", false);
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
@@ -306,41 +324,33 @@ static bool test_raw_oplock_batch2(struct torture_context *tctx, struct smbcli_s
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
-       torture_comment(tctx, "open with batch oplock\n");
+       torture_comment(tctx, "open a file with an exclusive oplock (share mode: %s)\n",
+                       s3?"all":"none");
        ZERO_STRUCT(break_info);
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
-               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+       if (s3) {
+               io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+                       NTCREATEX_SHARE_ACCESS_WRITE|
+                       NTCREATEX_SHARE_ACCESS_DELETE;
+       }
+
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
 
-       torture_comment(tctx, "unlink should generate a break, which we ack as break to none\n");
-       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none, cli1->tree);
-       unl.unlink.in.pattern = fname;
-       unl.unlink.in.attrib = 0;
-       status = smb_raw_unlink(cli2->tree, &unl);
-       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+       torture_comment(tctx, "setpathinfo EOF should trigger a break to none\n");
+       ZERO_STRUCT(sfi);
+       sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+       sfi.generic.in.file.path = fname;
+       sfi.end_of_file_info.in.size = 100;
 
+       status = smb_raw_setpathinfo(cli2->tree, &sfi);
+
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
        CHECK_VAL(break_info.count, 1);
-       CHECK_VAL(break_info.fnum, fnum);
-       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
        CHECK_VAL(break_info.failures, 0);
-
-       torture_comment(tctx, "2nd unlink should not generate a break\n");
-       ZERO_STRUCT(break_info);
-       status = smb_raw_unlink(cli2->tree, &unl);
-       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
-
-       CHECK_VAL(break_info.count, 0);
-
-       torture_comment(tctx, "writing should not generate a break\n");
-       smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
-       msleep(100);
-       smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
-
-       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
 
        smbcli_close(cli1->tree, fnum);
 
@@ -351,14 +361,13 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_exclusive4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch3.dat";
+       const char *fname = BASEDIR "\\test_exclusive4.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
-       union smb_unlink unl;
-       uint16_t fnum=0;
+       uint16_t fnum=0, fnum2=0;
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
@@ -384,29 +393,30 @@ static bool test_raw_oplock_batch3(struct torture_context *tctx, struct smbcli_s
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
-       torture_comment(tctx, "if we close on break then the unlink can succeed\n");
+       torture_comment(tctx, "open with exclusive oplock\n");
        ZERO_STRUCT(break_info);
-       smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
-               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
 
-       unl.unlink.in.pattern = fname;
-       unl.unlink.in.attrib = 0;
        ZERO_STRUCT(break_info);
-       status = smb_raw_unlink(cli2->tree, &unl);
-       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       torture_comment(tctx, "second open with attributes only shouldn't cause oplock break\n");
 
-       CHECK_VAL(break_info.count, 1);
-       CHECK_VAL(break_info.fnum, fnum);
-       CHECK_VAL(break_info.level, 1);
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+       io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+       status = smb_raw_open(cli2->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+       CHECK_VAL(break_info.count, 0);
        CHECK_VAL(break_info.failures, 0);
 
        smbcli_close(cli1->tree, fnum);
+       smbcli_close(cli2->tree, fnum2);
 
 done:
        smb_raw_exit(cli1->session);
@@ -415,14 +425,13 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_exclusive5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch4.dat";
+       const char *fname = BASEDIR "\\test_exclusive5.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
-       union smb_read rd;
-       uint16_t fnum=0;
+       uint16_t fnum=0, fnum2=0;
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
@@ -432,6 +441,7 @@ static bool test_raw_oplock_batch4(struct torture_context *tctx, struct smbcli_s
        smbcli_unlink(cli1->tree, fname);
 
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
        /*
          base ntcreatex parms
@@ -448,29 +458,36 @@ static bool test_raw_oplock_batch4(struct torture_context *tctx, struct smbcli_s
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
-       torture_comment(tctx, "a self read should not cause a break\n");
+       torture_comment(tctx, "open with exclusive oplock\n");
        ZERO_STRUCT(break_info);
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
-               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
 
-       rd.read.level = RAW_READ_READ;
-       rd.read.in.file.fnum = fnum;
-       rd.read.in.count = 1;
-       rd.read.in.offset = 0;
-       rd.read.in.remaining = 0;
-       status = smb_raw_read(cli1->tree, &rd);
+       ZERO_STRUCT(break_info);
+
+       torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE_IF dispostion causes oplock break\n");
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+       io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
+       status = smb_raw_open(cli2->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
-       CHECK_VAL(break_info.count, 0);
+       fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+       CHECK_VAL(break_info.count, 1);
        CHECK_VAL(break_info.failures, 0);
 
        smbcli_close(cli1->tree, fnum);
+       smbcli_close(cli2->tree, fnum2);
 
 done:
        smb_raw_exit(cli1->session);
@@ -479,20 +496,24 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_exclusive6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch5.dat";
+       const char *fname1 = BASEDIR "\\test_exclusive6_1.dat";
+       const char *fname2 = BASEDIR "\\test_exclusive6_2.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
+       union smb_rename rn;
        uint16_t fnum=0;
+       bool s3 = torture_setting_bool(tctx, "samba3", false);
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
        }
 
        /* cleanup */
-       smbcli_unlink(cli1->tree, fname);
+       smbcli_unlink(cli1->tree, fname1);
+       smbcli_unlink(cli1->tree, fname2);
 
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
@@ -509,29 +530,36 @@ static bool test_raw_oplock_batch5(struct torture_context *tctx, struct smbcli_s
        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.fname = fname1;
 
-       torture_comment(tctx, "a 2nd open should give a break\n");
+       /* we should use no share mode, when samba3 passes this */
+       torture_comment(tctx, "open a file with an exclusive oplock (share mode: %s)\n",
+                       s3?"all":"none");
        ZERO_STRUCT(break_info);
-       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
+       if (s3) {
+               io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+                       NTCREATEX_SHARE_ACCESS_WRITE|
+                       NTCREATEX_SHARE_ACCESS_DELETE;
+       }
 
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
-               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
 
-       ZERO_STRUCT(break_info);
+       torture_comment(tctx, "rename should not generate a break but get a sharing violation\n");
+       ZERO_STRUCT(rn);
+       rn.generic.level = RAW_RENAME_RENAME;
+       rn.rename.in.pattern1 = fname1;
+       rn.rename.in.pattern2 = fname2;
+       rn.rename.in.attrib = 0;
 
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
-       status = smb_raw_open(cli2->tree, tctx, &io);
-       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+       printf("trying rename while first file open\n");
+       status = smb_raw_rename(cli2->tree, &rn);
 
-       CHECK_VAL(break_info.count, 1);
-       CHECK_VAL(break_info.fnum, fnum);
-       CHECK_VAL(break_info.level, 1);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+       CHECK_VAL(break_info.count, 0);
        CHECK_VAL(break_info.failures, 0);
 
        smbcli_close(cli1->tree, fnum);
@@ -543,13 +571,14 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_batch1(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch6.dat";
+       const char *fname = BASEDIR "\\test_batch1.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
-       uint16_t fnum=0, fnum2=0;
+       union smb_unlink unl;
+       uint16_t fnum=0;
        char c = 0;
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
@@ -576,13 +605,11 @@ static bool test_raw_oplock_batch6(struct torture_context *tctx, struct smbcli_s
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
-       torture_comment(tctx, "a 2nd open should give a break to level II if the first open allowed shared read\n");
+       /*
+         with a batch oplock we get a break
+       */
+       torture_comment(tctx, "open with batch oplock\n");
        ZERO_STRUCT(break_info);
-       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
-       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
-
-       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
-       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
                NTCREATEX_FLAGS_REQUEST_OPLOCK | 
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
@@ -591,31 +618,35 @@ static bool test_raw_oplock_batch6(struct torture_context *tctx, struct smbcli_s
        fnum = io.ntcreatex.out.file.fnum;
        CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
 
-       ZERO_STRUCT(break_info);
-
-       status = smb_raw_open(cli2->tree, tctx, &io);
-       CHECK_STATUS(tctx, status, NT_STATUS_OK);
-       fnum2 = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+       torture_comment(tctx, "unlink should generate a break\n");
+       unl.unlink.in.pattern = fname;
+       unl.unlink.in.attrib = 0;
+       status = smb_raw_unlink(cli2->tree, &unl);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
 
        CHECK_VAL(break_info.count, 1);
        CHECK_VAL(break_info.fnum, fnum);
-       CHECK_VAL(break_info.level, 1);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
        CHECK_VAL(break_info.failures, 0);
+
+       torture_comment(tctx, "2nd unlink should not generate a break\n");
        ZERO_STRUCT(break_info);
+       status = smb_raw_unlink(cli2->tree, &unl);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
 
-       torture_comment(tctx, "write should trigger a break to none on both\n");
+       CHECK_VAL(break_info.count, 0);
+
+       torture_comment(tctx, "writing should generate a self break to none\n");
        smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
        msleep(100);
        smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
 
-       CHECK_VAL(break_info.count, 2);
-       CHECK_VAL(break_info.level, 0);
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.fnum, fnum);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
        CHECK_VAL(break_info.failures, 0);
 
        smbcli_close(cli1->tree, fnum);
-       smbcli_close(cli2->tree, fnum2);
-
 
 done:
        smb_raw_exit(cli1->session);
@@ -624,13 +655,15 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch7(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_batch2(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch7.dat";
+       const char *fname = BASEDIR "\\test_batch2.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
-       uint16_t fnum=0, fnum2=0;
+       union smb_unlink unl;
+       uint16_t fnum=0;
+       char c = 0;
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
@@ -656,36 +689,818 @@ static bool test_raw_oplock_batch7(struct torture_context *tctx, struct smbcli_s
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
-       torture_comment(tctx, "a 2nd open should get an oplock when we close instead of ack\n");
+       torture_comment(tctx, "open with batch oplock\n");
        ZERO_STRUCT(break_info);
-       smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
-
-       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
-       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
                NTCREATEX_FLAGS_REQUEST_OPLOCK | 
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
-       fnum2 = io.ntcreatex.out.file.fnum;
+       fnum = io.ntcreatex.out.file.fnum;
        CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
 
-       ZERO_STRUCT(break_info);
-
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
-               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       torture_comment(tctx, "unlink should generate a break, which we ack as break to none\n");
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none, cli1->tree);
+       unl.unlink.in.pattern = fname;
+       unl.unlink.in.attrib = 0;
+       status = smb_raw_unlink(cli2->tree, &unl);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.fnum, fnum);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+       CHECK_VAL(break_info.failures, 0);
+
+       torture_comment(tctx, "2nd unlink should not generate a break\n");
+       ZERO_STRUCT(break_info);
+       status = smb_raw_unlink(cli2->tree, &unl);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+       CHECK_VAL(break_info.count, 0);
+
+       torture_comment(tctx, "writing should not generate a break\n");
+       smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
+       msleep(100);
+       smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
+
+       CHECK_VAL(break_info.count, 0);
+
+       smbcli_close(cli1->tree, fnum);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch3(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch3.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       union smb_unlink unl;
+       uint16_t fnum=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       torture_comment(tctx, "if we close on break then the unlink can succeed\n");
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       unl.unlink.in.pattern = fname;
+       unl.unlink.in.attrib = 0;
+       ZERO_STRUCT(break_info);
+       status = smb_raw_unlink(cli2->tree, &unl);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.fnum, fnum);
+       CHECK_VAL(break_info.level, 1);
+       CHECK_VAL(break_info.failures, 0);
+
+       smbcli_close(cli1->tree, fnum);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch4(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch4.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       union smb_read rd;
+       uint16_t fnum=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       torture_comment(tctx, "a self read should not cause a break\n");
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       rd.read.level = RAW_READ_READ;
+       rd.read.in.file.fnum = fnum;
+       rd.read.in.count = 1;
+       rd.read.in.offset = 0;
+       rd.read.in.remaining = 0;
+       status = smb_raw_read(cli1->tree, &rd);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.failures, 0);
+
+       smbcli_close(cli1->tree, fnum);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch5(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch5.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       uint16_t fnum=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       torture_comment(tctx, "a 2nd open should give a break\n");
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       ZERO_STRUCT(break_info);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+       status = smb_raw_open(cli2->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
+
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.fnum, fnum);
+       CHECK_VAL(break_info.level, 1);
+       CHECK_VAL(break_info.failures, 0);
+
+       smbcli_close(cli1->tree, fnum);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch6(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch6.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       uint16_t fnum=0, fnum2=0;
+       char c = 0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       torture_comment(tctx, "a 2nd open should give a break to level II if the first open allowed shared read\n");
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
+
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       ZERO_STRUCT(break_info);
+
+       status = smb_raw_open(cli2->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.fnum, fnum);
+       CHECK_VAL(break_info.level, 1);
+       CHECK_VAL(break_info.failures, 0);
+       ZERO_STRUCT(break_info);
+
+       torture_comment(tctx, "write should trigger a break to none on both\n");
+       smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
+       msleep(100);
+       smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
+
+       CHECK_VAL(break_info.count, 2);
+       CHECK_VAL(break_info.level, 0);
+       CHECK_VAL(break_info.failures, 0);
+
+       smbcli_close(cli1->tree, fnum);
+       smbcli_close(cli2->tree, fnum2);
+
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch7(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch7.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       uint16_t fnum=0, fnum2=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       torture_comment(tctx, "a 2nd open should get an oplock when we close instead of ack\n");
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
+
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       ZERO_STRUCT(break_info);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       status = smb_raw_open(cli2->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.fnum, fnum2);
+       CHECK_VAL(break_info.level, 1);
+       CHECK_VAL(break_info.failures, 0);
+       
+       smbcli_close(cli2->tree, fnum);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch8(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch8.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       uint16_t fnum=0, fnum2=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       torture_comment(tctx, "open with batch oplock\n");
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       ZERO_STRUCT(break_info);
+       torture_comment(tctx, "second open with attributes only shouldn't cause oplock break\n");
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+       status = smb_raw_open(cli2->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
+       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.failures, 0);
+
+       smbcli_close(cli1->tree, fnum);
+       smbcli_close(cli2->tree, fnum2);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch9.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       uint16_t fnum=0, fnum2=0;
+       char c = 0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       torture_comment(tctx, "open with attributes only can create file\n");
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+
+       torture_comment(tctx, "Subsequent normal open should break oplock on attribute only open to level II\n");
+
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+       status = smb_raw_open(cli2->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.fnum, fnum);
+       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+       smbcli_close(cli2->tree, fnum2);
+
+       torture_comment(tctx, "third oplocked open should grant level2 without break\n");
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+       status = smb_raw_open(cli2->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+       ZERO_STRUCT(break_info);
+
+       torture_comment(tctx, "write should trigger a break to none on both\n");
+       smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
+
+       /* Now the oplock break request comes in. But right now we can't
+        * answer it. Do another write */
+
+       msleep(100);
+       smbcli_write(cli2->tree, fnum2, 0, &c, 1, 1);
+
+       CHECK_VAL(break_info.count, 2);
+       CHECK_VAL(break_info.level, 0);
+       CHECK_VAL(break_info.failures, 0);
+
+       smbcli_close(cli1->tree, fnum);
+       smbcli_close(cli2->tree, fnum2);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch10.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       uint16_t fnum=0, fnum2=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       torture_comment(tctx, "Open with oplock after a non-oplock open should grant level2\n");
+       ZERO_STRUCT(break_info);
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+
+       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
        status = smb_raw_open(cli2->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+       torture_comment(tctx, "write should trigger a break to none\n");
+       {
+               union smb_write wr;
+               wr.write.level = RAW_WRITE_WRITE;
+               wr.write.in.file.fnum = fnum;
+               wr.write.in.count = 1;
+               wr.write.in.offset = 0;
+               wr.write.in.remaining = 0;
+               wr.write.in.data = (const uint8_t *)"x";
+               status = smb_raw_write(cli1->tree, &wr);
+               CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       }
+
+       /* Now the oplock break request comes in. But right now we can't
+        * answer it. Do another write */
+
+       msleep(100);
+       
+       {
+               union smb_write wr;
+               wr.write.level = RAW_WRITE_WRITE;
+               wr.write.in.file.fnum = fnum;
+               wr.write.in.count = 1;
+               wr.write.in.offset = 0;
+               wr.write.in.remaining = 0;
+               wr.write.in.data = (const uint8_t *)"x";
+               status = smb_raw_write(cli1->tree, &wr);
+               CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       }
+
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.fnum, fnum2);
+       CHECK_VAL(break_info.level, 0);
+       CHECK_VAL(break_info.failures, 0);
+
+       smbcli_close(cli1->tree, fnum);
+       smbcli_close(cli2->tree, fnum2);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch11(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch11.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       union smb_setfileinfo sfi;
+       uint16_t fnum=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       /* Test if a set-eof on pathname breaks an exclusive oplock. */
+       torture_comment(tctx, "Test if setpathinfo set EOF breaks oplocks.\n");
+
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       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;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.failures, 0);
        CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
+       
+       ZERO_STRUCT(sfi);
+       sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
+       sfi.generic.in.file.path = fname;
+       sfi.end_of_file_info.in.size = 100;
+
+        status = smb_raw_setpathinfo(cli2->tree, &sfi);
 
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
        CHECK_VAL(break_info.count, 1);
-       CHECK_VAL(break_info.fnum, fnum2);
-       CHECK_VAL(break_info.level, 1);
        CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(break_info.level, 0);
+
+       smbcli_close(cli1->tree, fnum);
+
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch12.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       union smb_setfileinfo sfi;
+       uint16_t fnum=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       /* Test if a set-allocation size on pathname breaks an exclusive oplock. */
+       torture_comment(tctx, "Test if setpathinfo allocation size breaks oplocks.\n");
+
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       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;
+       status = smb_raw_open(cli1->tree, tctx, &io);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       fnum = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
        
-       smbcli_close(cli2->tree, fnum);
+       ZERO_STRUCT(sfi);
+       sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
+       sfi.generic.in.file.path = fname;
+       sfi.allocation_info.in.alloc_size = 65536 * 8;
+
+        status = smb_raw_setpathinfo(cli2->tree, &sfi);
+
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(break_info.level, 0);
+
+       smbcli_close(cli1->tree, fnum);
 
 done:
        smb_raw_exit(cli1->session);
@@ -694,9 +1509,9 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch8(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_batch13(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch8.dat";
+       const char *fname = BASEDIR "\\test_batch13.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
@@ -710,6 +1525,7 @@ static bool test_raw_oplock_batch8(struct torture_context *tctx, struct smbcli_s
        smbcli_unlink(cli1->tree, fname);
 
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
        /*
          base ntcreatex parms
@@ -730,26 +1546,35 @@ static bool test_raw_oplock_batch8(struct torture_context *tctx, struct smbcli_s
        ZERO_STRUCT(break_info);
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
+
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
                NTCREATEX_FLAGS_REQUEST_OPLOCK | 
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
        CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
 
        ZERO_STRUCT(break_info);
-       torture_comment(tctx, "second open with attributes only shouldn't cause oplock break\n");
+
+       torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE dispostion causes oplock break\n");
 
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
                NTCREATEX_FLAGS_REQUEST_OPLOCK | 
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
        io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
        status = smb_raw_open(cli2->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum2 = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
-       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+       CHECK_VAL(break_info.count, 1);
        CHECK_VAL(break_info.failures, 0);
 
        smbcli_close(cli1->tree, fnum);
@@ -762,14 +1587,13 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_batch14(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch9.dat";
+       const char *fname = BASEDIR "\\test_batch14.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
        uint16_t fnum=0, fnum2=0;
-       char c = 0;
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
@@ -795,71 +1619,114 @@ static bool test_raw_oplock_batch9(struct torture_context *tctx, struct smbcli_s
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
-       torture_comment(tctx, "open with attributes only can create file\n");
+       torture_comment(tctx, "open with batch oplock\n");
+       ZERO_STRUCT(break_info);
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
                NTCREATEX_FLAGS_REQUEST_OPLOCK | 
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
-       io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
-       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
        CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
 
-       torture_comment(tctx, "Subsequent normal open should break oplock on attribute only open to level II\n");
-
        ZERO_STRUCT(break_info);
-       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_SUPERSEDE dispostion causes oplock break\n");
 
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
                NTCREATEX_FLAGS_REQUEST_OPLOCK | 
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
-       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
-       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+       io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
        status = smb_raw_open(cli2->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum2 = io.ntcreatex.out.file.fnum;
+       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
        CHECK_VAL(break_info.count, 1);
-       CHECK_VAL(break_info.fnum, fnum);
        CHECK_VAL(break_info.failures, 0);
-       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
-       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
+
+       smbcli_close(cli1->tree, fnum);
        smbcli_close(cli2->tree, fnum2);
+done:
+       smb_raw_exit(cli1->session);
+       smb_raw_exit(cli2->session);
+       smbcli_deltree(cli1->tree, BASEDIR);
+       return ret;
+}
+
+static bool test_raw_oplock_batch15(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+{
+       const char *fname = BASEDIR "\\test_batch15.dat";
+       NTSTATUS status;
+       bool ret = true;
+       union smb_open io;
+       union smb_fileinfo qfi;
+       uint16_t fnum=0;
+
+       if (!torture_setup_dir(cli1, BASEDIR)) {
+               return false;
+       }
+
+       /* cleanup */
+       smbcli_unlink(cli1->tree, fname);
+
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+       /*
+         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_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       io.ntcreatex.in.create_options = 0;
+       io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       /* Test if a qpathinfo all info on pathname breaks a batch oplock. */
+       torture_comment(tctx, "Test if qpathinfo all info breaks a batch oplock (should not).\n");
 
-       torture_comment(tctx, "third oplocked open should grant level2 without break\n");
        ZERO_STRUCT(break_info);
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
-       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+               NTCREATEX_FLAGS_REQUEST_OPLOCK |
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
        io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
-       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
-       status = smb_raw_open(cli2->tree, tctx, &io);
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+               NTCREATEX_SHARE_ACCESS_WRITE|
+               NTCREATEX_SHARE_ACCESS_DELETE;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
+       status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
-       fnum2 = io.ntcreatex.out.file.fnum;
+       fnum = io.ntcreatex.out.file.fnum;
        CHECK_VAL(break_info.count, 0);
        CHECK_VAL(break_info.failures, 0);
-       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
-
-       ZERO_STRUCT(break_info);
-
-       torture_comment(tctx, "write should trigger a break to none on both\n");
-       smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
 
-       /* Now the oplock break request comes in. But right now we can't
-        * answer it. Do another write */
+       ZERO_STRUCT(qfi);
+       qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+       qfi.generic.in.file.path = fname;
 
-       msleep(100);
-       smbcli_write(cli2->tree, fnum2, 0, &c, 1, 1);
+       status = smb_raw_pathinfo(cli2->tree, tctx, &qfi);
 
-       CHECK_VAL(break_info.count, 2);
-       CHECK_VAL(break_info.level, 0);
-       CHECK_VAL(break_info.failures, 0);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_VAL(break_info.count, 0);
 
        smbcli_close(cli1->tree, fnum);
-       smbcli_close(cli2->tree, fnum2);
 
 done:
        smb_raw_exit(cli1->session);
@@ -868,9 +1735,9 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_batch16(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch10.dat";
+       const char *fname = BASEDIR "\\test_batch16.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
@@ -884,6 +1751,7 @@ static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_
        smbcli_unlink(cli1->tree, fname);
 
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
        /*
          base ntcreatex parms
@@ -900,70 +1768,39 @@ static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
-       torture_comment(tctx, "Open with oplock after a non-oplock open should grant level2\n");
+       torture_comment(tctx, "open with batch oplock\n");
        ZERO_STRUCT(break_info);
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
-       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
+
+
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+               NTCREATEX_FLAGS_REQUEST_OPLOCK |
+               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
        io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
                NTCREATEX_SHARE_ACCESS_WRITE|
                NTCREATEX_SHARE_ACCESS_DELETE;
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(break_info.count, 0);
-       CHECK_VAL(break_info.failures, 0);
-       CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
+       CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
 
-       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
+       ZERO_STRUCT(break_info);
+
+       torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE_IF dispostion causes oplock break\n");
 
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK |
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
-       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
+       io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
        io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
                NTCREATEX_SHARE_ACCESS_WRITE|
                NTCREATEX_SHARE_ACCESS_DELETE;
-       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
        status = smb_raw_open(cli2->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum2 = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(break_info.count, 0);
-       CHECK_VAL(break_info.failures, 0);
        CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
-
-       torture_comment(tctx, "write should trigger a break to none\n");
-       {
-               union smb_write wr;
-               wr.write.level = RAW_WRITE_WRITE;
-               wr.write.in.file.fnum = fnum;
-               wr.write.in.count = 1;
-               wr.write.in.offset = 0;
-               wr.write.in.remaining = 0;
-               wr.write.in.data = (const uint8_t *)"x";
-               status = smb_raw_write(cli1->tree, &wr);
-               CHECK_STATUS(tctx, status, NT_STATUS_OK);
-       }
-
-       /* Now the oplock break request comes in. But right now we can't
-        * answer it. Do another write */
-
-       msleep(100);
-       
-       {
-               union smb_write wr;
-               wr.write.level = RAW_WRITE_WRITE;
-               wr.write.in.file.fnum = fnum;
-               wr.write.in.count = 1;
-               wr.write.in.offset = 0;
-               wr.write.in.remaining = 0;
-               wr.write.in.data = (const uint8_t *)"x";
-               status = smb_raw_write(cli1->tree, &wr);
-               CHECK_STATUS(tctx, status, NT_STATUS_OK);
-       }
-
        CHECK_VAL(break_info.count, 1);
-       CHECK_VAL(break_info.fnum, fnum2);
-       CHECK_VAL(break_info.level, 0);
        CHECK_VAL(break_info.failures, 0);
 
        smbcli_close(cli1->tree, fnum);
@@ -976,21 +1813,24 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch11(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_batch17(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch11.dat";
+       const char *fname1 = BASEDIR "\\test_batch17_1.dat";
+       const char *fname2 = BASEDIR "\\test_batch17_2.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
-       union smb_setfileinfo sfi;
+       union smb_rename rn;
        uint16_t fnum=0;
+       bool s3 = torture_setting_bool(tctx, "samba3", false);
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
        }
 
        /* cleanup */
-       smbcli_unlink(cli1->tree, fname);
+       smbcli_unlink(cli1->tree, fname1);
+       smbcli_unlink(cli1->tree, fname2);
 
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
@@ -1007,40 +1847,40 @@ static bool test_raw_oplock_batch11(struct torture_context *tctx, struct smbcli_
        io.ntcreatex.in.create_options = 0;
        io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
        io.ntcreatex.in.security_flags = 0;
-       io.ntcreatex.in.fname = fname;
-
-       /* Test if a set-eof on pathname breaks an exclusive oplock. */
-       torture_comment(tctx, "Test if setpathinfo set EOF breaks oplocks.\n");
+       io.ntcreatex.in.fname = fname1;
 
+       /* we should use no share mode, when samba3 passes this */
+       torture_comment(tctx, "open a file with an batch oplock (share mode: %s)\n",
+                       s3?"all":"none");
        ZERO_STRUCT(break_info);
-       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
-
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK |
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
-       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
-       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;
+       if (s3) {
+               io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+                       NTCREATEX_SHARE_ACCESS_WRITE|
+                       NTCREATEX_SHARE_ACCESS_DELETE;
+       }
+
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(break_info.count, 0);
-       CHECK_VAL(break_info.failures, 0);
        CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
-       
-       ZERO_STRUCT(sfi);
-       sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
-       sfi.generic.in.file.path = fname;
-       sfi.end_of_file_info.in.size = 100;
 
-        status = smb_raw_setpathinfo(cli2->tree, &sfi);
+       torture_comment(tctx, "rename should trigger a break\n");
+       ZERO_STRUCT(rn);
+       rn.generic.level = RAW_RENAME_RENAME;
+       rn.rename.in.pattern1 = fname1;
+       rn.rename.in.pattern2 = fname2;
+       rn.rename.in.attrib = 0;
 
-       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       printf("trying rename while first file open\n");
+       status = smb_raw_rename(cli2->tree, &rn);
+
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
        CHECK_VAL(break_info.count, 1);
        CHECK_VAL(break_info.failures, 0);
-       CHECK_VAL(break_info.level, 0);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
 
        smbcli_close(cli1->tree, fnum);
 
@@ -1051,21 +1891,24 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_batch18(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch12.dat";
+       const char *fname1 = BASEDIR "\\test_batch18_1.dat";
+       const char *fname2 = BASEDIR "\\test_batch18_2.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
-       union smb_setfileinfo sfi;
+       union smb_rename rn;
        uint16_t fnum=0;
+       bool s3 = torture_setting_bool(tctx, "samba3", false);
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
        }
 
        /* cleanup */
-       smbcli_unlink(cli1->tree, fname);
+       smbcli_unlink(cli1->tree, fname1);
+       smbcli_unlink(cli1->tree, fname2);
 
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
@@ -1082,40 +1925,40 @@ static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_
        io.ntcreatex.in.create_options = 0;
        io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
        io.ntcreatex.in.security_flags = 0;
-       io.ntcreatex.in.fname = fname;
-
-       /* Test if a set-allocation size on pathname breaks an exclusive oplock. */
-       torture_comment(tctx, "Test if setpathinfo allocation size breaks oplocks.\n");
+       io.ntcreatex.in.fname = fname1;
 
+       /* we should use no share mode, when samba3 passes this */
+       torture_comment(tctx, "open a file with an batch oplock (share mode: %s)\n",
+                       s3?"all":"none");
        ZERO_STRUCT(break_info);
-       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
-
        io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+               NTCREATEX_FLAGS_REQUEST_OPLOCK |
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
-       io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
-       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;
+       if (s3) {
+               io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
+                       NTCREATEX_SHARE_ACCESS_WRITE|
+                       NTCREATEX_SHARE_ACCESS_DELETE;
+       }
+
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(break_info.count, 0);
-       CHECK_VAL(break_info.failures, 0);
        CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
-       
-       ZERO_STRUCT(sfi);
-       sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
-       sfi.generic.in.file.path = fname;
-       sfi.allocation_info.in.alloc_size = 65536 * 8;
 
-        status = smb_raw_setpathinfo(cli2->tree, &sfi);
+       torture_comment(tctx, "ntrename should trigger a break\n");
+       ZERO_STRUCT(rn);
+       rn.generic.level = RAW_RENAME_NTRENAME;
+       rn.ntrename.in.attrib   = 0;
+       rn.ntrename.in.flags    = RENAME_FLAG_RENAME;
+       rn.ntrename.in.old_name = fname1;
+       rn.ntrename.in.new_name = fname2;
+       printf("trying rename while first file open\n");
+       status = smb_raw_rename(cli2->tree, &rn);
 
-       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
        CHECK_VAL(break_info.count, 1);
        CHECK_VAL(break_info.failures, 0);
-       CHECK_VAL(break_info.level, 0);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
 
        smbcli_close(cli1->tree, fnum);
 
@@ -1126,23 +1969,32 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch13(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_batch19(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch13.dat";
+       const char *fname1 = BASEDIR "\\test_batch19_1.dat";
+       const char *fname2 = BASEDIR "\\test_batch19_2.dat";
+       const char *fname3 = BASEDIR "\\test_batch19_3.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
-       uint16_t fnum=0, fnum2=0;
+       union smb_fileinfo qfi;
+       union smb_setfileinfo sfi;
+       uint16_t fnum=0;
+
+       if (torture_setting_bool(tctx, "samba3", false)) {
+               torture_skip(tctx, "BACHT19 disabled against samba3\n");
+       }
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
        }
 
        /* cleanup */
-       smbcli_unlink(cli1->tree, fname);
+       smbcli_unlink(cli1->tree, fname1);
+       smbcli_unlink(cli1->tree, fname2);
+       smbcli_unlink(cli1->tree, fname3);
 
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
-       smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
        /*
          base ntcreatex parms
@@ -1157,45 +2009,60 @@ static bool test_raw_oplock_batch13(struct torture_context *tctx, struct smbcli_
        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.fname = fname1;
 
-       torture_comment(tctx, "open with batch oplock\n");
+       torture_comment(tctx, "open a file with an batch oplock (share mode: none)\n");
        ZERO_STRUCT(break_info);
-       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
-
-
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+               NTCREATEX_FLAGS_REQUEST_OPLOCK |
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
-       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
-               NTCREATEX_SHARE_ACCESS_WRITE|
-               NTCREATEX_SHARE_ACCESS_DELETE;
        status = smb_raw_open(cli1->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum = io.ntcreatex.out.file.fnum;
        CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
 
-       ZERO_STRUCT(break_info);
+       torture_comment(tctx, "setpathinfo rename info should not trigger a break nor a violation\n");
+       ZERO_STRUCT(sfi);
+       sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+       sfi.generic.in.file.path = fname1;
+       sfi.rename_information.in.overwrite     = 0;
+       sfi.rename_information.in.root_fid      = 0;
+       sfi.rename_information.in.new_name      = fname2+strlen(BASEDIR)+1;
 
-       torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE dispostion causes oplock break\n");
+        status = smb_raw_setpathinfo(cli2->tree, &sfi);
 
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
-               NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
-       io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
-       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
-               NTCREATEX_SHARE_ACCESS_WRITE|
-               NTCREATEX_SHARE_ACCESS_DELETE;
-       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
-       status = smb_raw_open(cli2->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
-       fnum2 = io.ntcreatex.out.file.fnum;
-       CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
-       CHECK_VAL(break_info.count, 1);
-       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(break_info.count, 0);
+
+       ZERO_STRUCT(qfi);
+       qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+       qfi.generic.in.file.fnum = fnum;
+
+       status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2);
+
+       torture_comment(tctx, "setfileinfo rename info should not trigger a break nor a violation\n");
+       ZERO_STRUCT(sfi);
+       sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+       sfi.generic.in.file.fnum = fnum;
+       sfi.rename_information.in.overwrite     = 0;
+       sfi.rename_information.in.root_fid      = 0;
+       sfi.rename_information.in.new_name      = fname3+strlen(BASEDIR)+1;
+
+       status = smb_raw_setfileinfo(cli1->tree, &sfi);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_VAL(break_info.count, 0);
+
+       ZERO_STRUCT(qfi);
+       qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+       qfi.generic.in.file.fnum = fnum;
+
+       status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
 
        smbcli_close(cli1->tree, fnum);
-       smbcli_close(cli2->tree, fnum2);
 
 done:
        smb_raw_exit(cli1->session);
@@ -1204,20 +2071,30 @@ done:
        return ret;
 }
 
-static bool test_raw_oplock_batch14(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
+static bool test_raw_oplock_batch20(struct torture_context *tctx, struct smbcli_state *cli1, struct smbcli_state *cli2)
 {
-       const char *fname = BASEDIR "\\test_batch14.dat";
+       const char *fname1 = BASEDIR "\\test_batch20_1.dat";
+       const char *fname2 = BASEDIR "\\test_batch20_2.dat";
+       const char *fname3 = BASEDIR "\\test_batch20_3.dat";
        NTSTATUS status;
        bool ret = true;
        union smb_open io;
-       uint16_t fnum=0, fnum2=0;
+       union smb_fileinfo qfi;
+       union smb_setfileinfo sfi;
+       uint16_t fnum=0,fnum2=0;
+
+       if (torture_setting_bool(tctx, "samba3", false)) {
+               torture_skip(tctx, "BACHT20 disabled against samba3\n");
+       }
 
        if (!torture_setup_dir(cli1, BASEDIR)) {
                return false;
        }
 
        /* cleanup */
-       smbcli_unlink(cli1->tree, fname);
+       smbcli_unlink(cli1->tree, fname1);
+       smbcli_unlink(cli1->tree, fname2);
+       smbcli_unlink(cli1->tree, fname3);
 
        smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
 
@@ -1234,14 +2111,12 @@ static bool test_raw_oplock_batch14(struct torture_context *tctx, struct smbcli_
        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.fname = fname1;
 
-       torture_comment(tctx, "open with batch oplock\n");
+       torture_comment(tctx, "open a file with an batch oplock (share mode: all)\n");
        ZERO_STRUCT(break_info);
-       smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
-
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+               NTCREATEX_FLAGS_REQUEST_OPLOCK |
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
        io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
                NTCREATEX_SHARE_ACCESS_WRITE|
@@ -1251,27 +2126,77 @@ static bool test_raw_oplock_batch14(struct torture_context *tctx, struct smbcli_
        fnum = io.ntcreatex.out.file.fnum;
        CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
 
-       ZERO_STRUCT(break_info);
+       torture_comment(tctx, "setpathinfo rename info should not trigger a break nor a violation\n");
+       ZERO_STRUCT(sfi);
+       sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+       sfi.generic.in.file.path = fname1;
+       sfi.rename_information.in.overwrite     = 0;
+       sfi.rename_information.in.root_fid      = 0;
+       sfi.rename_information.in.new_name      = fname2+strlen(BASEDIR)+1;
 
-       torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_SUPERSEDE dispostion causes oplock break\n");
+       status = smb_raw_setpathinfo(cli2->tree, &sfi);
 
-       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
-               NTCREATEX_FLAGS_REQUEST_OPLOCK | 
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_VAL(break_info.count, 0);
+
+       ZERO_STRUCT(qfi);
+       qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+       qfi.generic.in.file.fnum = fnum;
+
+       status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_STRMATCH(qfi.all_info.out.fname.s, fname2);
+
+       /* we should use no share mode, when samba3 passes this */
+       torture_comment(tctx, "open a file with the new name an batch oplock (share mode: all)\n");
+       ZERO_STRUCT(break_info);
+       io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
+               NTCREATEX_FLAGS_REQUEST_OPLOCK |
                NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
-       io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
        io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
                NTCREATEX_SHARE_ACCESS_WRITE|
                NTCREATEX_SHARE_ACCESS_DELETE;
-       io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
+       io.ntcreatex.in.fname = fname2;
        status = smb_raw_open(cli2->tree, tctx, &io);
        CHECK_STATUS(tctx, status, NT_STATUS_OK);
        fnum2 = io.ntcreatex.out.file.fnum;
        CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
        CHECK_VAL(break_info.count, 1);
        CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+
+       torture_comment(tctx, "setfileinfo rename info should not trigger a break nor a violation\n");
+       ZERO_STRUCT(sfi);
+       sfi.generic.level = RAW_SFILEINFO_RENAME_INFORMATION;
+       sfi.generic.in.file.fnum = fnum;
+       sfi.rename_information.in.overwrite     = 0;
+       sfi.rename_information.in.root_fid      = 0;
+       sfi.rename_information.in.new_name      = fname3+strlen(BASEDIR)+1;
+
+       status = smb_raw_setfileinfo(cli1->tree, &sfi);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_VAL(break_info.count, 1);
+       CHECK_VAL(break_info.failures, 0);
+       CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
+
+       ZERO_STRUCT(qfi);
+       qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+       qfi.generic.in.file.fnum = fnum;
+
+       status = smb_raw_fileinfo(cli1->tree, tctx, &qfi);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
+
+       ZERO_STRUCT(qfi);
+       qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+       qfi.generic.in.file.fnum = fnum2;
+
+       status = smb_raw_fileinfo(cli2->tree, tctx, &qfi);
+       CHECK_STATUS(tctx, status, NT_STATUS_OK);
+       CHECK_STRMATCH(qfi.all_info.out.fname.s, fname3);
 
        smbcli_close(cli1->tree, fnum);
-       smbcli_close(cli2->tree, fnum2);
+
 done:
        smb_raw_exit(cli1->session);
        smb_raw_exit(cli2->session);
@@ -1286,7 +2211,12 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx)
 {
        struct torture_suite *suite = torture_suite_create(mem_ctx, "OPLOCK");
 
-       torture_suite_add_2smb_test(suite, "NORMAL", test_raw_oplock_normal);
+       torture_suite_add_2smb_test(suite, "EXCLUSIVE1", test_raw_oplock_exclusive1);
+       torture_suite_add_2smb_test(suite, "EXCLUSIVE2", test_raw_oplock_exclusive2);
+       torture_suite_add_2smb_test(suite, "EXCLUSIVE3", test_raw_oplock_exclusive3);
+       torture_suite_add_2smb_test(suite, "EXCLUSIVE4", test_raw_oplock_exclusive4);
+       torture_suite_add_2smb_test(suite, "EXCLUSIVE5", test_raw_oplock_exclusive5);
+       torture_suite_add_2smb_test(suite, "EXCLUSIVE6", test_raw_oplock_exclusive6);
        torture_suite_add_2smb_test(suite, "BATCH1", test_raw_oplock_batch1);
        torture_suite_add_2smb_test(suite, "BATCH2", test_raw_oplock_batch2);
        torture_suite_add_2smb_test(suite, "BATCH3", test_raw_oplock_batch3);
@@ -1301,6 +2231,12 @@ struct torture_suite *torture_raw_oplock(TALLOC_CTX *mem_ctx)
        torture_suite_add_2smb_test(suite, "BATCH12", test_raw_oplock_batch12);
        torture_suite_add_2smb_test(suite, "BATCH13", test_raw_oplock_batch13);
        torture_suite_add_2smb_test(suite, "BATCH14", test_raw_oplock_batch14);
+       torture_suite_add_2smb_test(suite, "BATCH15", test_raw_oplock_batch15);
+       torture_suite_add_2smb_test(suite, "BATCH16", test_raw_oplock_batch16);
+       torture_suite_add_2smb_test(suite, "BATCH17", test_raw_oplock_batch17);
+       torture_suite_add_2smb_test(suite, "BATCH18", test_raw_oplock_batch18);
+       torture_suite_add_2smb_test(suite, "BATCH19", test_raw_oplock_batch19);
+       torture_suite_add_2smb_test(suite, "BATCH20", test_raw_oplock_batch20);
 
        return suite;
 }