summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/build/smb_build/makefile.pm11
-rw-r--r--source4/cluster/ctdb/opendb_ctdb.c57
-rw-r--r--source4/lib/ldb/web/index.html24
-rw-r--r--source4/lib/replace/Makefile.in4
-rw-r--r--source4/lib/replace/configure.ac2
-rw-r--r--source4/lib/replace/getifaddrs.c24
-rw-r--r--source4/lib/replace/getifaddrs.m415
-rw-r--r--source4/lib/replace/libreplace.m41
-rw-r--r--source4/lib/replace/replace.h10
-rw-r--r--source4/lib/replace/socket.c35
-rw-r--r--source4/lib/replace/socket.m440
-rw-r--r--source4/lib/replace/system/network.h20
-rw-r--r--source4/lib/talloc/web/index.html20
-rw-r--r--source4/lib/tdb/web/index.html14
-rw-r--r--source4/ntvfs/common/opendb.c36
-rw-r--r--source4/ntvfs/common/opendb.h20
-rw-r--r--source4/ntvfs/common/opendb_tdb.c373
-rw-r--r--source4/ntvfs/posix/config.mk1
-rw-r--r--source4/ntvfs/posix/pvfs_lock.c16
-rw-r--r--source4/ntvfs/posix/pvfs_notify.c8
-rw-r--r--source4/ntvfs/posix/pvfs_open.c378
-rw-r--r--source4/ntvfs/posix/pvfs_oplock.c239
-rw-r--r--source4/ntvfs/posix/pvfs_qfileinfo.c2
-rw-r--r--source4/ntvfs/posix/pvfs_rename.c11
-rw-r--r--source4/ntvfs/posix/pvfs_setfileinfo.c120
-rw-r--r--source4/ntvfs/posix/pvfs_unlink.c185
-rw-r--r--source4/ntvfs/posix/pvfs_wait.c37
-rw-r--r--source4/ntvfs/posix/pvfs_write.c5
-rw-r--r--source4/ntvfs/posix/vfs_posix.c4
-rw-r--r--source4/ntvfs/posix/vfs_posix.h24
-rw-r--r--source4/pidl/idl.yp2
-rw-r--r--source4/pidl/lib/Parse/Pidl/IDL.pm2
-rw-r--r--source4/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm3
-rw-r--r--source4/rules.mk7
-rw-r--r--source4/samba4-knownfail1
-rw-r--r--source4/samba4-skip6
-rwxr-xr-xsource4/selftest/samba4_tests.sh5
-rw-r--r--source4/selftest/target/Samba4.pm6
-rw-r--r--source4/setup/provision.reg39
-rw-r--r--source4/smbd/server.c2
-rw-r--r--source4/torture/basic/base.c18
-rw-r--r--source4/torture/raw/oplock.c79
42 files changed, 1505 insertions, 401 deletions
diff --git a/source4/build/smb_build/makefile.pm b/source4/build/smb_build/makefile.pm
index 17474db00e..29da771353 100644
--- a/source4/build/smb_build/makefile.pm
+++ b/source4/build/smb_build/makefile.pm
@@ -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($$)
diff --git a/source4/cluster/ctdb/opendb_ctdb.c b/source4/cluster/ctdb/opendb_ctdb.c
index aaab3aa55d..3dfc6819b7 100644
--- a/source4/cluster/ctdb/opendb_ctdb.c
+++ b/source4/cluster/ctdb/opendb_ctdb.c
@@ -133,6 +133,16 @@ static struct odb_lock *odb_ctdb_lock(TALLOC_CTX *mem_ctx,
return lck;
}
+static DATA_BLOB odb_ctdb_get_key(TALLOC_CTX *mem_ctx, struct odb_lock *lck)
+{
+ /*
+ * as this file will went away and isn't used yet,
+ * copy the implementation from the tdb backend
+ * --metze
+ */
+ return data_blob_const(NULL, 0);
+}
+
/*
determine if two odb_entry structures conflict
@@ -269,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;
@@ -440,6 +452,29 @@ static NTSTATUS odb_ctdb_close_file(struct odb_lock *lck, void *file_handle)
return odb_push_record(lck, &file);
}
+/*
+ update the oplock level of the client
+*/
+static NTSTATUS odb_ctdb_update_oplock(struct odb_lock *lck, void *file_handle,
+ uint32_t oplock_level)
+{
+ /*
+ * as this file will went away and isn't used yet,
+ * copy the implementation from the tdb backend
+ * --metze
+ */
+ 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
@@ -561,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;
@@ -576,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;
}
@@ -610,6 +646,7 @@ static NTSTATUS odb_ctdb_can_open(struct odb_lock *lck,
static const struct opendb_ops opendb_ctdb_ops = {
.odb_init = odb_ctdb_init,
.odb_lock = odb_ctdb_lock,
+ .odb_get_key = odb_ctdb_get_key,
.odb_open_file = odb_ctdb_open_file,
.odb_open_file_pending = odb_ctdb_open_file_pending,
.odb_close_file = odb_ctdb_close_file,
@@ -617,7 +654,9 @@ static const struct opendb_ops opendb_ctdb_ops = {
.odb_rename = odb_ctdb_rename,
.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_can_open = odb_ctdb_can_open,
+ .odb_update_oplock = odb_ctdb_update_oplock,
+ .odb_break_oplocks = odb_ctdb_break_oplocks
};
diff --git a/source4/lib/ldb/web/index.html b/source4/lib/ldb/web/index.html
index 76dbbdeafb..26dd344527 100644
--- a/source4/lib/ldb/web/index.html
+++ b/source4/lib/ldb/web/index.html
@@ -42,9 +42,9 @@ The main features that separate ldb from other solutions are:
Currently ldb is completely lacking in programmer or user
documentation. This is your opportunity to make a contribution! Start
with the public functions declared in <a
-href="http://samba.org/ftp/unpacked/samba4/source/lib/ldb/include/ldb.h">ldb.h</a>
+href="http://samba.org/ftp/unpacked/ldb/include/ldb.h">ldb.h</a>
and the example code in the <a
-href="http://samba.org/ftp/unpacked/samba4/source/lib/ldb/tools/">tools
+href="http://samba.org/ftp/unpacked/ldb/tools/">tools
directory</a>. Documentation in the same docbook format used by Samba
would be preferred.
@@ -53,21 +53,17 @@ would be preferred.
ldb does not currently have its own mailing list or bug tracking
system. For now, please use the <a
href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a>
-mailing list, and the <a href="http://bugzilla.samba.org/">Samba
-bugzilla</a> bug tracking system.
+mailing list or the <a href="https://lists.samba.org/mailman/listinfo/ldb">ldb</a>
+mailing list, and the <a href="http://bugzilla.samba.org/">Samba bugzilla</a> bug tracking system.
<h2>Download</h2>
-You can download the latest release either via rsync or anonymous
-svn. To fetch via svn use the following commands:
-
-<pre>
- svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/ldb ldb
- svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/tdb tdb
- svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/talloc talloc
- svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/replace libreplace
-</pre>
-
+You can download the latest release either via rsync or thtough git.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/ldb directory.<br>
+<br>
To fetch via rsync use these commands:
<pre>
diff --git a/source4/lib/replace/Makefile.in b/source4/lib/replace/Makefile.in
index 30f39ac6cb..af9522f3a6 100644
--- a/source4/lib/replace/Makefile.in
+++ b/source4/lib/replace/Makefile.in
@@ -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
diff --git a/source4/lib/replace/configure.ac b/source4/lib/replace/configure.ac
index beeb77e152..f5e054f476 100644
--- a/source4/lib/replace/configure.ac
+++ b/source4/lib/replace/configure.ac
@@ -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
diff --git a/source4/lib/replace/getifaddrs.c b/source4/lib/replace/getifaddrs.c
index 4037d647d7..053657475d 100644
--- a/source4/lib/replace/getifaddrs.c
+++ b/source4/lib/replace/getifaddrs.c
@@ -19,6 +19,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define SOCKET_WRAPPER_NOT_REPLACE
+
#include "replace.h"
#include "system/network.h"
@@ -81,11 +83,11 @@ int rep_getifaddrs(struct ifaddrs **ifap)
char buff[8192];
int fd, i, n;
struct ifreq *ifr=NULL;
- int total = 0;
struct in_addr ipaddr;
struct in_addr nmask;
char *iname;
- struct ifaddrs *curif, *lastif;
+ struct ifaddrs *curif;
+ struct ifaddrs *lastif = NULL;
*ifap = NULL;
@@ -106,7 +108,7 @@ int rep_getifaddrs(struct ifaddrs **ifap)
n = ifc.ifc_len / sizeof(struct ifreq);
/* Loop through interfaces, looking for given IP address */
- for (i=n-1;i>=0 && total < max_interfaces;i--) {
+ for (i=n-1; i>=0; i--) {
if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
freeifaddrs(*ifap);
}
@@ -115,7 +117,7 @@ int rep_getifaddrs(struct ifaddrs **ifap)
if (lastif == NULL) {
*ifap = curif;
} else {
- lastif->ifa_next = (*ifap);
+ lastif->ifa_next = curif;
}
curif->ifa_name = strdup(ifr[i].ifr_name);
@@ -166,11 +168,11 @@ int rep_getifaddrs(struct ifaddrs **ifap)
char buff[8192];
int fd, i, n;
struct ifreq *ifr=NULL;
- int total = 0;
struct in_addr ipaddr;
struct in_addr nmask;
char *iname;
struct ifaddrs *curif;
+ struct ifaddrs *lastif = NULL;
*ifap = NULL;
@@ -201,14 +203,14 @@ int rep_getifaddrs(struct ifaddrs **ifap)
/* Loop through interfaces */
- for (i = 0; i<n && total < max_interfaces; i++) {
+ for (i = 0; i<n; i++) {
ifreq = ifr[i];
curif = calloc(1, sizeof(struct ifaddrs));
if (lastif == NULL) {
*ifap = curif;
} else {
- lastif->ifa_next = (*ifap);
+ lastif->ifa_next = curif;
}
strioctl.ic_cmd = SIOCGIFFLAGS;
@@ -270,8 +272,8 @@ int rep_getifaddrs(struct ifaddrs **ifap)
struct in_addr ipaddr;
struct in_addr nmask;
char *iname;
- int total = 0;
- struct ifaddrs *curif, *lastif;
+ struct ifaddrs *curif;
+ struct ifaddrs *lastif = NULL;
*ifap = NULL;
@@ -306,7 +308,7 @@ int rep_getifaddrs(struct ifaddrs **ifap)
if (lastif == NULL) {
*ifap = curif;
} else {
- lastif->ifa_next = (*ifap);
+ lastif->ifa_next = curif;
}
curif->ifa_name = strdup(ifr->ifr_name);
@@ -363,7 +365,7 @@ int rep_getifaddrs(struct ifaddrs **ifap)
#endif
#ifdef AUTOCONF_TEST
-/* this is the autoconf driver to test get_interfaces() */
+/* this is the autoconf driver to test getifaddrs() */
int main()
{
diff --git a/source4/lib/replace/getifaddrs.m4 b/source4/lib/replace/getifaddrs.m4
index 4cf86d89cc..767797e8d2 100644
--- a/source4/lib/replace/getifaddrs.m4
+++ b/source4/lib/replace/getifaddrs.m4
@@ -44,9 +44,10 @@ iface=no;
iface=no;
AC_CACHE_CHECK([for iface getifaddrs],libreplace_cv_HAVE_IFACE_GETIFADDRS,[
AC_TRY_RUN([
-#define NO_CONFIG_H 1
#define HAVE_IFACE_GETIFADDRS 1
+#define NO_CONFIG_H 1
#define AUTOCONF_TEST 1
+#define SOCKET_WRAPPER_NOT_REPLACE
#include "$libreplacedir/replace.c"
#include "$libreplacedir/getifaddrs.c"],
libreplace_cv_HAVE_IFACE_GETIFADDRS=yes,libreplace_cv_HAVE_IFACE_GETIFADDRS=no,libreplace_cv_HAVE_IFACE_GETIFADDRS=cross)])
@@ -61,12 +62,16 @@ if test $iface = no; then
AC_CACHE_CHECK([for iface AIX],libreplace_cv_HAVE_IFACE_AIX,[
AC_TRY_RUN([
#define HAVE_IFACE_AIX 1
+#define NO_CONFIG_H 1
#define AUTOCONF_TEST 1
#undef _XOPEN_SOURCE_EXTENDED
+#define SOCKET_WRAPPER_NOT_REPLACE
+#include "$libreplacedir/replace.c"
#include "$libreplacedir/getifaddrs.c"],
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
@@ -75,11 +80,15 @@ if test $iface = no; then
AC_CACHE_CHECK([for iface ifconf],libreplace_cv_HAVE_IFACE_IFCONF,[
AC_TRY_RUN([
#define HAVE_IFACE_IFCONF 1
+#define NO_CONFIG_H 1
#define AUTOCONF_TEST 1
+#define SOCKET_WRAPPER_NOT_REPLACE
+#include "$libreplacedir/replace.c"
#include "$libreplacedir/getifaddrs.c"],
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
@@ -87,11 +96,15 @@ if test $iface = no; then
AC_CACHE_CHECK([for iface ifreq],libreplace_cv_HAVE_IFACE_IFREQ,[
AC_TRY_RUN([
#define HAVE_IFACE_IFREQ 1
+#define NO_CONFIG_H 1
#define AUTOCONF_TEST 1
+#define SOCKET_WRAPPER_NOT_REPLACE
+#include "$libreplacedir/replace.c"
#include "$libreplacedir/getifaddrs.c"],
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
diff --git a/source4/lib/replace/libreplace.m4 b/source4/lib/replace/libreplace.m4
index 2e0cd34f4a..e0cc57f4c8 100644
--- a/source4/lib/replace/libreplace.m4
+++ b/source4/lib/replace/libreplace.m4
@@ -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)
diff --git a/source4/lib/replace/replace.h b/source4/lib/replace/replace.h
index 3f91544e97..0d16f4ffd0 100644
--- a/source4/lib/replace/replace.h
+++ b/source4/lib/replace/replace.h
@@ -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
index 0000000000..35e975fce7
--- /dev/null
+++ b/source4/lib/replace/socket.c
@@ -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
index 0000000000..c0c8f93e81
--- /dev/null
+++ b/source4/lib/replace/socket.m4
@@ -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
+
diff --git a/source4/lib/replace/system/network.h b/source4/lib/replace/system/network.h
index d09e3f71f8..410c6d7cca 100644
--- a/source4/lib/replace/system/network.h
+++ b/source4/lib/replace/system/network.h
@@ -83,6 +83,11 @@
#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;
diff --git a/source4/lib/talloc/web/index.html b/source4/lib/talloc/web/index.html
index 628030ad4c..5deab93665 100644
--- a/source4/lib/talloc/web/index.html
+++ b/source4/lib/talloc/web/index.html
@@ -12,7 +12,7 @@ destructors. It is the core memory allocator used in Samba4, and has
made a huge difference in many aspects of Samba4 development.<p>
To get started with talloc, I would recommend you read the <a
-href="http://samba.org/ftp/unpacked/samba_4_0_test/source/lib/talloc/talloc_guide.txt">talloc guide</a>.
+href="http://samba.org/ftp/unpacked/talloc/talloc_guide.txt">talloc guide</a>.
<h2>Discussion and bug reports</h2>
@@ -24,20 +24,16 @@ bugzilla</a> bug tracking system.
<h2>Download</h2>
-You can download the latest release either via rsync or git.
-To fetch via git use the following command:
-
-<pre>
- git-clone git://git.samba.org/samba.git samba
- cd samba
- git checkout -b samba4 origin/v4-0-test
-</pre>
-
+You can download the latest release either via rsync or git.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/talloc directory.<br>
+<br>
To fetch via rsync use this command:
<pre>
- rsync -Pavz samba.org::ftp/unpacked/samba_4_0_test/source/lib/talloc .
- rsync -Pavz samba.org::ftp/unpacked/samba_4_0_test/source/lib/libreplace .
+ rsync -Pavz samba.org::ftp/unpacked/talloc .
</pre>
<hr>
diff --git a/source4/lib/tdb/web/index.html b/source4/lib/tdb/web/index.html
index 979665ae76..a53da6b8f7 100644
--- a/source4/lib/tdb/web/index.html
+++ b/source4/lib/tdb/web/index.html
@@ -22,14 +22,12 @@ bugzilla</a> bug tracking system.
<h2>Download</h2>
-You can download the latest release either via rsync or anonymous
-svn. To fetch via svn use the following commands:
-
-<pre>
- svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/tdb tdb
- svn co svn://svnanon.samba.org/samba/branches/SAMBA_4_0/source/lib/replace libreplace
-</pre>
-
+You can download the latest release either via rsync or git.<br>
+<br>
+To fetch via git see the following guide:<br>
+<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br>
+Once you have cloned the tree switch to the v4-0-test branch and cd into the source/lib/tdb directory.<br>
+<br>
To fetch via rsync use these commands:
<pre>
diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c
index 4826ca5c26..36144d0406 100644
--- a/source4/ntvfs/common/opendb.c
+++ b/source4/ntvfs/common/opendb.c
@@ -81,6 +81,10 @@ _PUBLIC_ struct odb_lock *odb_lock(TALLOC_CTX *mem_ctx,
return ops->odb_lock(mem_ctx, odb, file_key);
}
+_PUBLIC_ DATA_BLOB odb_get_key(TALLOC_CTX *mem_ctx, struct odb_lock *lck)
+{
+ return ops->odb_get_key(mem_ctx, lck);
+}
/*
register an open file in the open files database. This implements the share_access
@@ -89,15 +93,16 @@ _PUBLIC_ struct odb_lock *odb_lock(TALLOC_CTX *mem_ctx,
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);
}
@@ -161,8 +166,21 @@ _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, 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,
+ uint32_t oplock_level)
+{
+ return ops->odb_update_oplock(lck, file_handle, oplock_level);
+}
+
+_PUBLIC_ NTSTATUS odb_break_oplocks(struct odb_lock *lck)
{
- return ops->odb_can_open(lck, share_access, create_options, access_mask);
+ return ops->odb_break_oplocks(lck);
}
diff --git a/source4/ntvfs/common/opendb.h b/source4/ntvfs/common/opendb.h
index 231ae3d7de..9591bcf6b9 100644
--- a/source4/ntvfs/common/opendb.h
+++ b/source4/ntvfs/common/opendb.h
@@ -24,10 +24,12 @@ struct opendb_ops {
struct ntvfs_context *ntvfs_ctx);
struct odb_lock *(*odb_lock)(TALLOC_CTX *mem_ctx,
struct odb_context *odb, DATA_BLOB *file_key);
- NTSTATUS (*odb_open_file)(struct odb_lock *lck, void *file_handle,
- uint32_t stream_id, uint32_t share_access,
+ DATA_BLOB (*odb_get_key)(TALLOC_CTX *mem_ctx, struct odb_lock *lck);
+ 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);
@@ -38,10 +40,18 @@ 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 {
+ void *file_handle;
+ uint8_t level;
+};
void odb_set_ops(const struct opendb_ops *new_ops);
void odb_tdb_init_ops(void);
diff --git a/source4/ntvfs/common/opendb_tdb.c b/source4/ntvfs/common/opendb_tdb.c
index abd9ca708b..fe5a0a8864 100644
--- a/source4/ntvfs/common/opendb_tdb.c
+++ b/source4/ntvfs/common/opendb_tdb.c
@@ -2,7 +2,8 @@
Unix SMB/CIFS implementation.
Copyright (C) Andrew Tridgell 2004
-
+ 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
@@ -134,12 +135,21 @@ static struct odb_lock *odb_tdb_lock(TALLOC_CTX *mem_ctx,
return lck;
}
+static DATA_BLOB odb_tdb_get_key(TALLOC_CTX *mem_ctx, struct odb_lock *lck)
+{
+ return data_blob_talloc(mem_ctx, lck->key.dptr, lck->key.dsize);
+}
+
+
/*
determine if two odb_entry structures conflict
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 */
@@ -150,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;
}
@@ -169,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;
}
@@ -253,12 +263,129 @@ static NTSTATUS odb_push_record(struct odb_lock *lck, struct opendb_file *file)
/*
send an oplock break to a client
*/
-static NTSTATUS odb_oplock_break_send(struct odb_context *odb, struct opendb_entry *e)
+static NTSTATUS odb_oplock_break_send(struct odb_context *odb,
+ struct opendb_entry *e,
+ uint8_t level)
{
+ NTSTATUS status;
+ struct opendb_oplock_break op_break;
+ DATA_BLOB blob;
+
+ ZERO_STRUCT(op_break);
+
/* tell the server handling this open file about the need to send the client
a break */
- return messaging_send_ptr(odb->ntvfs_ctx->msg_ctx, e->server,
- MSG_NTVFS_OPLOCK_BREAK, e->file_handle);
+ op_break.file_handle = e->file_handle;
+ op_break.level = level;
+
+ blob = data_blob_const(&op_break, sizeof(op_break));
+
+ status = messaging_send(odb->ntvfs_ctx->msg_ctx, e->server,
+ MSG_NTVFS_OPLOCK_BREAK, &blob);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ 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) {
+ odb_oplock_break_send(odb, &file->entries[i],
+ OPLOCK_BREAK_TO_NONE);
+ return NT_STATUS_OPLOCK_NOT_GRANTED;
+ }
+ }
+
+ if (_attrs_only) {
+ *_attrs_only = attrs_only;
+ }
+ return NT_STATUS_OK;
}
/*
@@ -268,17 +395,18 @@ 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_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;
@@ -294,6 +422,13 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck, void *file_handle,
}
/* 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;
e.stream_id = stream_id;
@@ -301,59 +436,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]);
- 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]);
- 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_NONE;
+ *oplock_granted = NO_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 */
@@ -439,6 +552,82 @@ static NTSTATUS odb_tdb_close_file(struct odb_lock *lck, void *file_handle)
return odb_push_record(lck, &file);
}
+/*
+ update the oplock level of the client
+*/
+static NTSTATUS odb_tdb_update_oplock(struct odb_lock *lck, void *file_handle,
+ uint32_t oplock_level)
+{
+ struct odb_context *odb = lck->odb;
+ struct opendb_file file;
+ int i;
+ NTSTATUS status;
+
+ status = odb_pull_record(lck, &file);
+ NT_STATUS_NOT_OK_RETURN(status);
+
+ /* find the entry, and update it */
+ for (i=0;i<file.num_entries;i++) {
+ if (file_handle == file.entries[i].file_handle &&
+ cluster_id_equal(&odb->ntvfs_ctx->server_id, &file.entries[i].server)) {
+ file.entries[i].oplock_level = oplock_level;
+ break;
+ }
+ }
+
+ if (i == file.num_entries) {
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ /* send any pending notifications, removing them once sent */
+ for (i=0;i<file.num_pending;i++) {
+ messaging_send_ptr(odb->ntvfs_ctx->msg_ctx,
+ file.pending[i].server,
+ MSG_PVFS_RETRY_OPEN,
+ file.pending[i].notify_ptr);
+ }
+ file.num_pending = 0;
+
+ 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
@@ -560,14 +749,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)) {
@@ -575,32 +764,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;
}
@@ -609,6 +777,7 @@ static NTSTATUS odb_tdb_can_open(struct odb_lock *lck,
static const struct opendb_ops opendb_tdb_ops = {
.odb_init = odb_tdb_init,
.odb_lock = odb_tdb_lock,
+ .odb_get_key = odb_tdb_get_key,
.odb_open_file = odb_tdb_open_file,
.odb_open_file_pending = odb_tdb_open_file_pending,
.odb_close_file = odb_tdb_close_file,
@@ -616,7 +785,9 @@ static const struct opendb_ops opendb_tdb_ops = {
.odb_rename = odb_tdb_rename,
.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_can_open = odb_tdb_can_open,
+ .odb_update_oplock = odb_tdb_update_oplock,
+ .odb_break_oplocks = odb_tdb_break_oplocks
};
diff --git a/source4/ntvfs/posix/config.mk b/source4/ntvfs/posix/config.mk
index 6879940337..88048c2af7 100644
--- a/source4/ntvfs/posix/config.mk
+++ b/source4/ntvfs/posix/config.mk
@@ -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 \
diff --git a/source4/ntvfs/posix/pvfs_lock.c b/source4/ntvfs/posix/pvfs_lock.c
index b9bb58c71d..baa92880f1 100644
--- a/source4/ntvfs/posix/pvfs_lock.c
+++ b/source4/ntvfs/posix/pvfs_lock.c
@@ -53,7 +53,7 @@ struct pvfs_pending_lock {
struct pvfs_file *f;
struct ntvfs_request *req;
int pending_lock;
- void *wait_handle;
+ struct pvfs_wait *wait_handle;
struct timeval end_time;
};
@@ -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;
diff --git a/source4/ntvfs/posix/pvfs_notify.c b/source4/ntvfs/posix/pvfs_notify.c
index 210f949395..06d2bc8e0c 100644
--- a/source4/ntvfs/posix/pvfs_notify.c
+++ b/source4/ntvfs/posix/pvfs_notify.c
@@ -268,9 +268,11 @@ NTSTATUS pvfs_notify(struct ntvfs_module_context *ntvfs,
/* if the buffer is empty then start waiting */
if (f->notify_buffer->num_changes == 0) {
- void *wait_handle =
- pvfs_wait_message(pvfs, req, -1, timeval_zero(),
- pvfs_notify_end, f->notify_buffer);
+ struct pvfs_wait *wait_handle;
+ wait_handle = pvfs_wait_message(pvfs, req, -1,
+ timeval_zero(),
+ pvfs_notify_end,
+ f->notify_buffer);
NT_STATUS_HAVE_NO_MEMORY(wait_handle);
talloc_steal(req, wait_handle);
return NT_STATUS_OK;
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index 8558f0476a..a01352f60c 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -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;
- void *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,21 +1522,38 @@ 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);
}
- if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * 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);
- *lckp = lck;
- } else if (lckp != NULL) {
+ if (lckp) {
+ *lckp = NULL;
+ }
+ } else if (lckp) {
*lckp = lck;
}
@@ -1469,6 +1572,9 @@ 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)) {
@@ -1481,16 +1587,105 @@ 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;
+ access_mask = SEC_STD_DELETE;
+ delete_on_close = false;
- if (!NT_STATUS_IS_OK(status)) {
+ 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;
- } else if (lckp != NULL) {
+ }
+
+ 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)) {
+ 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 |
+ 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
+ * 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;
}
@@ -1508,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)) {
@@ -1520,10 +1718,18 @@ 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);
+ }
return status;
}
diff --git a/source4/ntvfs/posix/pvfs_oplock.c b/source4/ntvfs/posix/pvfs_oplock.c
new file mode 100644
index 0000000000..cf30ddbc59
--- /dev/null
+++ b/source4/ntvfs/posix/pvfs_oplock.c
@@ -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;
+}
diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c
index 2f01c08fb0..8d23d707a4 100644
--- a/source4/ntvfs/posix/pvfs_qfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_qfileinfo.c
@@ -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,
diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c
index 65755e05cb..17c073ccab 100644
--- a/source4/ntvfs/posix/pvfs_rename.c
+++ b/source4/ntvfs/posix/pvfs_rename.c
@@ -192,8 +192,8 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
{
struct pvfs_filename *name1, *name2;
TALLOC_CTX *mem_ctx = talloc_new(req);
+ struct odb_lock *lck = NULL;
NTSTATUS status;
- struct odb_lock *lck, *lck2;
/* resolve the wildcard pattern for this name */
fname2 = pvfs_resolve_wildcard(mem_ctx, lp_iconv_convenience(pvfs->ntvfs->ctx->lp_ctx), fname1, fname2);
@@ -216,6 +216,7 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
status = pvfs_can_rename(pvfs, req, name1, &lck);
if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(lck);
goto failed;
}
@@ -223,7 +224,7 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
status = pvfs_resolve_partial(pvfs, mem_ctx,
dir_path, fname2, &name2);
if (NT_STATUS_IS_OK(status)) {
- status = pvfs_can_delete(pvfs, req, name2, &lck2);
+ status = pvfs_can_delete(pvfs, req, name2, NULL);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
@@ -311,7 +312,7 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
struct pvfs_state *pvfs = ntvfs->private_data;
NTSTATUS status;
struct pvfs_filename *name1, *name2;
- struct odb_lock *lck;
+ struct odb_lock *lck = NULL;
/* resolve the cifs name to a posix name */
status = pvfs_resolve_name(pvfs, req, ren->rename.in.pattern1,
@@ -354,6 +355,7 @@ static NTSTATUS pvfs_rename_mv(struct ntvfs_module_context *ntvfs,
status = pvfs_can_rename(pvfs, req, name1, &lck);
if (!NT_STATUS_IS_OK(status)) {
+ talloc_free(lck);
return status;
}
@@ -375,7 +377,6 @@ 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;
switch (ren->ntrename.in.flags) {
case RENAME_FLAG_RENAME:
@@ -421,7 +422,7 @@ static NTSTATUS pvfs_rename_nt(struct ntvfs_module_context *ntvfs,
return status;
}
- status = pvfs_can_rename(pvfs, req, name1, &lck);
+ status = pvfs_can_rename(pvfs, req, name1, NULL);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c
index 9c78699edb..da1e31e639 100644
--- a/source4/ntvfs/posix/pvfs_setfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_setfileinfo.c
@@ -142,8 +142,6 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
/* if the destination exists, then check the rename is allowed */
if (name2->exists) {
- struct odb_lock *lck;
-
if (strcmp(name2->full_name, name->full_name) == 0) {
/* rename to same name is null-op */
return NT_STATUS_OK;
@@ -153,7 +151,10 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs,
return NT_STATUS_OBJECT_NAME_COLLISION;
}
- status = pvfs_can_delete(pvfs, req, name2, &lck);
+ 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;
}
@@ -354,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;
@@ -364,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;
@@ -465,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
@@ -479,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,
@@ -553,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 */
@@ -568,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;
diff --git a/source4/ntvfs/posix/pvfs_unlink.c b/source4/ntvfs/posix/pvfs_unlink.c
index ef56d99fb5..7a2d964b9d 100644
--- a/source4/ntvfs/posix/pvfs_unlink.c
+++ b/source4/ntvfs/posix/pvfs_unlink.c
@@ -23,71 +23,94 @@
#include "vfs_posix.h"
#include "system/dir.h"
-
/*
- unlink a stream
- */
-static NTSTATUS pvfs_unlink_stream(struct pvfs_state *pvfs,
- struct ntvfs_request *req,
- struct pvfs_filename *name,
- uint16_t attrib)
+ 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)
{
- NTSTATUS status;
- struct odb_lock *lck;
+ 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;
+ }
- if (!name->stream_exists) {
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ /* re-mark it async, just in case someone up the chain does
+ paranoid checking */
+ req->async_states->state |= NTVFS_ASYNC_STATE_ASYNC;
+ break;
}
- /* make sure its matches the given attributes */
- status = pvfs_match_attrib(pvfs, name, attrib, 0);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
+ /* send the reply up the chain */
+ req->async_states->status = status;
+ req->async_states->send_fn(req);
+}
- status = pvfs_can_delete(pvfs, req, name, &lck);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+/*
+ 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_stream_delete(pvfs, name, -1);
+ return pvfs_odb_retry_setup(ntvfs, req, lck, end_time, io, NULL,
+ pvfs_retry_unlink);
}
/*
- unlink one file
+ unlink a file
*/
-static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
- struct ntvfs_request *req,
- const char *unix_path,
- const char *fname, uint32_t attrib)
+static NTSTATUS pvfs_unlink_file(struct pvfs_state *pvfs,
+ struct pvfs_filename *name)
{
- struct pvfs_filename *name;
NTSTATUS status;
- struct odb_lock *lck;
-
- /* get a pvfs_filename object */
- status = pvfs_resolve_partial(pvfs, req,
- unix_path, fname, &name);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- /* make sure its matches the given attributes */
- status = pvfs_match_attrib(pvfs, name, attrib, 0);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(name);
- return status;
- }
-
- status = pvfs_can_delete(pvfs, req, name, &lck);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(name);
- return status;
- }
if (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) {
- talloc_free(name);
return NT_STATUS_FILE_IS_A_DIRECTORY;
}
@@ -110,12 +133,57 @@ static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
name->full_name);
}
- talloc_free(name);
-
return status;
}
/*
+ unlink one file
+*/
+static NTSTATUS pvfs_unlink_one(struct pvfs_state *pvfs,
+ struct ntvfs_request *req,
+ union smb_unlink *unl,
+ struct pvfs_filename *name)
+{
+ NTSTATUS status;
+ struct odb_lock *lck = NULL;
+
+ /* make sure its matches the given attributes */
+ status = pvfs_match_attrib(pvfs, name,
+ unl->unlink.in.attrib, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ 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;
+ }
+
+ if (name->stream_name) {
+ if (!name->stream_exists) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ return pvfs_stream_delete(pvfs, name, -1);
+ }
+
+ return pvfs_unlink_file(pvfs, name);
+}
+
+/*
delete a file - the dirtype specifies the file types to include in the search.
The name can contain CIFS wildcards, but rarely does (except with OS/2 clients)
*/
@@ -147,8 +215,8 @@ NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
return NT_STATUS_FILE_IS_A_DIRECTORY;
}
- if (name->stream_name) {
- return pvfs_unlink_stream(pvfs, req, name, unl->unlink.in.attrib);
+ if (!name->has_wildcard) {
+ return pvfs_unlink_one(pvfs, req, unl, name);
}
/* get list of matching files */
@@ -158,6 +226,7 @@ NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
}
status = NT_STATUS_NO_SUCH_FILE;
+ talloc_free(name);
ofs = 0;
@@ -168,10 +237,20 @@ NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
return NT_STATUS_OBJECT_NAME_INVALID;
}
- status = pvfs_unlink_one(pvfs, req, pvfs_list_unix_path(dir), fname, unl->unlink.in.attrib);
+ /* get a pvfs_filename object */
+ status = pvfs_resolve_partial(pvfs, req,
+ pvfs_list_unix_path(dir),
+ fname, &name);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = pvfs_unlink_one(pvfs, req, unl, name);
if (NT_STATUS_IS_OK(status)) {
total_deleted++;
}
+
+ talloc_free(name);
}
if (total_deleted > 0) {
diff --git a/source4/ntvfs/posix/pvfs_wait.c b/source4/ntvfs/posix/pvfs_wait.c
index 989985a033..291250befd 100644
--- a/source4/ntvfs/posix/pvfs_wait.c
+++ b/source4/ntvfs/posix/pvfs_wait.c
@@ -31,7 +31,7 @@ struct pvfs_wait {
struct pvfs_wait *next, *prev;
struct pvfs_state *pvfs;
void (*handler)(void *, enum pvfs_wait_notice);
- void *private;
+ void *private_data;
int msg_type;
struct messaging_context *msg_ctx;
struct event_context *ev;
@@ -45,20 +45,23 @@ struct pvfs_wait {
previous ntvfs handlers in the chain (such as security context)
*/
NTSTATUS pvfs_async_setup(struct ntvfs_module_context *ntvfs,
- struct ntvfs_request *req, void *private)
+ struct ntvfs_request *req, void *private_data)
{
- struct pvfs_wait *pwait = private;
- pwait->handler(pwait->private, pwait->reason);
+ struct pvfs_wait *pwait = talloc_get_type(private_data,
+ struct pvfs_wait);
+ pwait->handler(pwait->private_data, pwait->reason);
return NT_STATUS_OK;
}
/*
receive a completion message for a wait
*/
-static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uint32_t msg_type,
+static void pvfs_wait_dispatch(struct messaging_context *msg,
+ void *private_data, uint32_t msg_type,
struct server_id src, DATA_BLOB *data)
{
- struct pvfs_wait *pwait = private;
+ struct pvfs_wait *pwait = talloc_get_type(private_data,
+ struct pvfs_wait);
struct ntvfs_request *req;
void *p = NULL;
@@ -70,7 +73,7 @@ static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uin
pp = (void **)data->data;
p = *pp;
}
- if (p == NULL || p != pwait->private) {
+ if (p == NULL || p != pwait->private_data) {
return;
}
@@ -91,9 +94,11 @@ static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uin
receive a timeout on a message wait
*/
static void pvfs_wait_timeout(struct event_context *ev,
- struct timed_event *te, struct timeval t, void *private)
+ struct timed_event *te, struct timeval t,
+ void *private_data)
{
- struct pvfs_wait *pwait = talloc_get_type(private, struct pvfs_wait);
+ struct pvfs_wait *pwait = talloc_get_type(private_data,
+ struct pvfs_wait);
struct ntvfs_request *req = pwait->req;
pwait->reason = PVFS_WAIT_TIMEOUT;
@@ -126,12 +131,12 @@ static int pvfs_wait_destructor(struct pvfs_wait *pwait)
if msg_type == -1 then no message is registered, and it is assumed
that the caller handles any messaging setup needed
*/
-void *pvfs_wait_message(struct pvfs_state *pvfs,
- struct ntvfs_request *req,
- int msg_type,
- struct timeval end_time,
- void (*fn)(void *, enum pvfs_wait_notice),
- void *private)
+struct pvfs_wait *pvfs_wait_message(struct pvfs_state *pvfs,
+ struct ntvfs_request *req,
+ int msg_type,
+ struct timeval end_time,
+ void (*fn)(void *, enum pvfs_wait_notice),
+ void *private_data)
{
struct pvfs_wait *pwait;
@@ -140,7 +145,7 @@ void *pvfs_wait_message(struct pvfs_state *pvfs,
return NULL;
}
- pwait->private = private;
+ pwait->private_data = private_data;
pwait->handler = fn;
pwait->msg_ctx = pvfs->ntvfs->ctx->msg_ctx;
pwait->ev = pvfs->ntvfs->ctx->event_ctx;
diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c
index 5a11f01952..dda8c83407 100644
--- a/source4/ntvfs/posix/pvfs_write.c
+++ b/source4/ntvfs/posix/pvfs_write.c
@@ -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,
diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c
index e058e6f546..ca874d1db1 100644
--- a/source4/ntvfs/posix/vfs_posix.c
+++ b/source4/ntvfs/posix/vfs_posix.c
@@ -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 =
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index a660da329a..4d22a91714 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -28,6 +28,9 @@
#include "ntvfs/common/ntvfs_common.h"
#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 */
struct pvfs_state {
@@ -49,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;
@@ -152,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;
@@ -228,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"
@@ -239,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
diff --git a/source4/pidl/idl.yp b/source4/pidl/idl.yp
index 028b628e18..c7ca0c7604 100644
--- a/source4/pidl/idl.yp
+++ b/source4/pidl/idl.yp
@@ -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'");
diff --git a/source4/pidl/lib/Parse/Pidl/IDL.pm b/source4/pidl/lib/Parse/Pidl/IDL.pm
index aeee69e306..4adb4dcea8 100644
--- a/source4/pidl/lib/Parse/Pidl/IDL.pm
+++ b/source4/pidl/lib/Parse/Pidl/IDL.pm
@@ -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'");
diff --git a/source4/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm b/source4/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
index ef3eb3dbcf..a959dc84f6 100644
--- a/source4/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
+++ b/source4/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
@@ -775,8 +775,7 @@ sub ParseElementPrint($$$$)
$self->pidl("for ($counter=0;$counter<$length;$counter++) {");
$self->indent;
$self->pidl("char *idx_$l->{LEVEL_INDEX}=NULL;");
- $self->pidl("asprintf(&idx_$l->{LEVEL_INDEX}, \"[\%d]\", $counter);");
- $self->pidl("if (idx_$l->{LEVEL_INDEX}) {");
+ $self->pidl("if (asprintf(&idx_$l->{LEVEL_INDEX}, \"[\%d]\", $counter) != -1) {");
$self->indent;
$var_name = get_array_element($var_name, $counter);
diff --git a/source4/rules.mk b/source4/rules.mk
index b6a54fae25..9791466712 100644
--- a/source4/rules.mk
+++ b/source4/rules.mk
@@ -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
###############################################################################
diff --git a/source4/samba4-knownfail b/source4/samba4-knownfail
index 18fb4b914b..4d850caae5 100644
--- a/source4/samba4-knownfail
+++ b/source4/samba4-knownfail
@@ -3,7 +3,6 @@ local.iconv.*.next_codepoint()
base.delaywrite.finfo update on close
base.delete.*.deltest20a
base.delete.*.deltest20b
-raw.oplock.*.OPLOCK
rpc.winreg
local.registry.*.security # Not implemented yet
rpc.wkssvc
diff --git a/source4/samba4-skip b/source4/samba4-skip
index e3d2b182d1..4d2da6ed64 100644
--- a/source4/samba4-skip
+++ b/source4/samba4-skip
@@ -1,13 +1,10 @@
-base.defer_open
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
@@ -18,7 +15,6 @@ base.smb
smb2.notify
smb2.scan
ntvfs.cifs.base.charset
-ntvfs.cifs.base.defer_open
ntvfs.cifs.base.delaywrite
ntvfs.cifs.base.iometer
ntvfs.cifs.base.casetable
@@ -27,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
diff --git a/source4/selftest/samba4_tests.sh b/source4/selftest/samba4_tests.sh
index c57ec4d6bd..32386e5b9e 100755
--- a/source4/selftest/samba4_tests.sh
+++ b/source4/selftest/samba4_tests.sh
@@ -216,12 +216,13 @@ done
plantest "rpc.echo on ncacn_np over smb2" dc $smb4torture ncacn_np:"\$SERVER[smb2]" -U"\$USERNAME"%"\$PASSWORD" -W \$DOMAIN RPC-ECHO "$*"
# Tests against the NTVFS POSIX backend
+NTVFSARGS="--option=torture:sharedelay=100000"
smb2=`$smb4torture --list | grep "^SMB2-" | xargs`
raw=`$smb4torture --list | grep "^RAW-" | xargs`
base=`$smb4torture --list | grep "^BASE-" | xargs`
for t in $base $raw $smb2; do
- plansmbtorturetest "$t" dc $ADDARGS //\$SERVER/tmp -U"\$USERNAME"%"\$PASSWORD"
+ plansmbtorturetest "$t" dc $ADDARGS //\$SERVER/tmp -U"\$USERNAME"%"\$PASSWORD" $NTVFSARGS
done
rap=`$smb4torture --list | grep "^RAP-" | xargs`
@@ -231,7 +232,7 @@ done
# Tests against the NTVFS CIFS backend
for t in $base $raw; do
- plantest "ntvfs.cifs.`normalize_testname $t`" dc $VALGRIND $smb4torture //\$NETBIOSNAME/cifs -U"\$USERNAME"%"\$PASSWORD" $t
+ plantest "ntvfs.cifs.`normalize_testname $t`" dc $VALGRIND $smb4torture //\$NETBIOSNAME/cifs -U"\$USERNAME"%"\$PASSWORD" $NTVFSARGS $t
done
# Local tests
diff --git a/source4/selftest/target/Samba4.pm b/source4/selftest/target/Samba4.pm
index 37e3cbe354..e0be8048a0 100644
--- a/source4/selftest/target/Samba4.pm
+++ b/source4/selftest/target/Samba4.pm
@@ -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
diff --git a/source4/setup/provision.reg b/source4/setup/provision.reg
index 892b5ec50c..b80db09c09 100644
--- a/source4/setup/provision.reg
+++ b/source4/setup/provision.reg
@@ -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]
diff --git a/source4/smbd/server.c b/source4/smbd/server.c
index 8ad3e030ff..fe38a4e5ab 100644
--- a/source4/smbd/server.c
+++ b/source4/smbd/server.c
@@ -253,7 +253,7 @@ static int binary_smbd_main(const char *binary_name, int argc, const char *argv[
umask(0);
DEBUG(0,("%s version %s started.\n", binary_name, SAMBA_VERSION_STRING));
- DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2007\n"));
+ DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2008\n"));
if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) {
DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n"));
diff --git a/source4/torture/basic/base.c b/source4/torture/basic/base.c
index aa729ec0df..66f9359744 100644
--- a/source4/torture/basic/base.c
+++ b/source4/torture/basic/base.c
@@ -633,6 +633,13 @@ static bool run_deferopen(struct torture_context *tctx, struct smbcli_state *cli
int retries=4;
int i = 0;
bool correct = true;
+ int nsec;
+ int msec;
+ double sec;
+
+ nsec = torture_setting_int(tctx, "sharedelay", 1000000);
+ msec = nsec / 1000;
+ sec = ((double)nsec) / ((double) 1000000);
if (retries <= 0) {
torture_comment(tctx, "failed to connect\n");
@@ -657,9 +664,10 @@ 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 || e > 1.5) {
- torture_comment(tctx,"Timing incorrect %.2f violation\n",
- e);
+ 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;
}
}
} while (NT_STATUS_EQUAL(smbcli_nt_error(cli->tree),NT_STATUS_SHARING_VIOLATION));
@@ -671,13 +679,13 @@ static bool run_deferopen(struct torture_context *tctx, struct smbcli_state *cli
torture_comment(tctx, "pid %u open %d\n", (unsigned)getpid(), i);
- sleep(10);
+ msleep(10 * msec);
i++;
if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnum))) {
torture_comment(tctx,"Failed to close %s, error=%s\n", fname, smbcli_errstr(cli->tree));
return false;
}
- sleep(2);
+ msleep(2 * msec);
}
if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
diff --git a/source4/torture/raw/oplock.c b/source4/torture/raw/oplock.c
index 952088e46c..e81b634161 100644
--- a/source4/torture/raw/oplock.c
+++ b/source4/torture/raw/oplock.c
@@ -914,7 +914,7 @@ static bool test_raw_oplock_batch10(struct torture_context *tctx, struct smbcli_
CHECK_VAL(break_info.failures, 0);
CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
- smbcli_oplock_handler(cli2->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 |
@@ -1058,7 +1058,7 @@ static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_
bool ret = true;
union smb_open io;
union smb_setfileinfo sfi;
- uint16_t fnum=0, fnum2=0;
+ uint16_t fnum=0;
if (!torture_setup_dir(cli1, BASEDIR)) {
return false;
@@ -1118,7 +1118,6 @@ static bool test_raw_oplock_batch12(struct torture_context *tctx, struct smbcli_
CHECK_VAL(break_info.level, 0);
smbcli_close(cli1->tree, fnum);
- smbcli_close(cli2->tree, fnum2);
done:
smb_raw_exit(cli1->session);
@@ -1280,6 +1279,79 @@ done:
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");
+
+ 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.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);
+ 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(qfi);
+ qfi.generic.level = RAW_FILEINFO_ALL_INFORMATION;
+ qfi.generic.in.file.path = fname;
+
+ status = smb_raw_pathinfo(cli2->tree, tctx, &qfi);
+
+ CHECK_STATUS(tctx, status, NT_STATUS_OK);
+ 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;
+}
+
/*
basic testing of oplocks
*/
@@ -1302,6 +1374,7 @@ 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);
return suite;
}