Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into v4-0-test
authorAndrew Tridgell <tridge@samba.org>
Tue, 3 Jun 2008 22:11:42 +0000 (15:11 -0700)
committerAndrew Tridgell <tridge@samba.org>
Tue, 3 Jun 2008 22:11:42 +0000 (15:11 -0700)
(This used to be commit 9d74201e462f2f95ed5bd91200681db3bd2a9277)

27 files changed:
README [deleted file]
WHATSNEW.txt
source4/VERSION
source4/cluster/ctdb/opendb_ctdb.c
source4/heimdal/lib/gssapi/krb5/init_sec_context.c
source4/lib/ldb/tests/python/ldap.py
source4/librpc/idl/opendb.idl
source4/ntvfs/common/opendb.c
source4/ntvfs/common/opendb.h
source4/ntvfs/common/opendb_tdb.c
source4/ntvfs/posix/pvfs_fileinfo.c
source4/ntvfs/posix/pvfs_open.c
source4/ntvfs/posix/pvfs_rename.c
source4/ntvfs/posix/pvfs_resolve.c
source4/ntvfs/posix/pvfs_search.c
source4/ntvfs/posix/pvfs_seek.c
source4/ntvfs/posix/pvfs_setfileinfo.c
source4/ntvfs/posix/pvfs_unlink.c
source4/ntvfs/posix/pvfs_write.c
source4/ntvfs/posix/vfs_posix.c
source4/ntvfs/posix/vfs_posix.h
source4/samba4-knownfail
source4/samba4-skip
source4/selftest/samba4_tests.sh
source4/selftest/target/Samba4.pm
source4/torture/basic/delaywrite.c
testprogs/ejs/ldap.js

diff --git a/README b/README
deleted file mode 100644 (file)
index 5501998..0000000
--- a/README
+++ /dev/null
@@ -1,140 +0,0 @@
-Readme for Samba 4
-==================
-
-Samba 4 is the ambitious next version of the Samba suite that is being
-developed in parallel to the stable 3.0 series. The main emphasis in
-this branch is support for the Active Directory logon protocols used
-by Windows 2000 and above.
-
-While we welcome your interest in Samba 4, we don't want you to run your
-network with it quite yet. Please note the WARNINGS below, and the
-STATUS file, which aims to document what should and should not work.
-
-With 4 years of development under our belt since Tridge first proposed
-a new Virtual File System (VFS) layer for Samba3 (a project which
-eventually lead to our Active Directory efforts), we felt that we
-should create something we could 'show off' to our users.  This is a
-Technology Preview (TP), aimed at allowing you, our users, managers and
-developers to see how we have progressed, and to invite your feedback and
-support.
-
-Warnings
---------
-
-Samba4 is currently at alpha stage.  That is more a reference to
-Samba4's lack of the features we expect you will need than a statement
-of code quality, but clearly it hasn't seen a broad deployment yet.  If
-you were to upgrade Samba3 (or indeed Windows) to Samba4, you would find
-many things work, but that other key features you may have relied on
-simply are not there yet.
-
-For example, while Samba 3.0 is an excellent member of a Active
-Directory domain, Samba4 is happier as a domain controller: (This is
-where we have done most of the research and development).
-
-While Samba4 is subjected to an awesome battery of tests on an
-automated basis, and we have found Samba4 to be very stable in it's
-behaviour, we have to recommend against upgrading production servers
-from Samba 3 to Samba 4 at this stage.  If you are upgrading an
-experimental server, or looking to develop and test Samba, you should
-backup all configuration and data.
-
-As we research the needs of Active Directory integration more closely,
-we may need to change the format of the user database, in particular
-as we begin to understand how the attributes are generated and stored.
-At a worst case, we expect users will be able to extract the stored
-data as LDIF and hand munge it, but until we make an alpha release, we
-won't do this automatically.  Indeed, many module changes are simply
-easier to cope with if you just re-provision after the upgrade.
-
-We value the security of your computers, and so we must warn you that
-Samba 4 Technology Preview includes basic Access Control List (ACL)
-protection on the main user database, but due to time constraints,
-none on the registry at this stage.  We also do not currently have
-ACLs on the SWAT web-based management tool. This means that Samba 4
-Technology Preview is not secure, and should not be exposed to
-untrusted networks.
-
-Within the above proviso, file system access should occur as the
-logged in user, much as Samba3 does.
-
-As such, we must strongly recommend against using Samba4 in a
-production environment at this stage.
-
-New Features
-------------
-
-Samba4 supports the server-side of the Active Directory logon environment
-used by Windows 2000 and later, so we can do full domain join
-and domain logon operations with these clients.
-
-Our Domain Controller (DC) implementation includes our own built-in
-LDAP server and Kerberos Key Distribution Centre (KDC) as well as the
-Samba3-like logon services provided over CIFS.  We correctly generate
-the infamous Kerberos PAC, and include it with the Kerberos tickets we
-issue.
-
-SWAT is now integrated into Samba 4 as the user-friendly interface to
-Samba server management. SWAT provides easy access to our
-setup and migration tools.  Using SWAT, you can migrate windows
-domains in Samba 4, allowing easy setup of initial user databases, and
-upgrades from Samba 3.
-
-The new VFS features in Samba 4 adapts the file-system on the server to
-match the Windows client semantics, allowing Samba 4 to better match
-windows behaviour and application expectations.  This includes file
-annotation information (in streams) and NT ACLs in particular.  The
-VFS is backed with an extensive automated test suite.
-
-A new scripting interface has been added to Samba 4, allowing
-JavaScript programs to interface to Samba's internals.
-
-The Samba 4 architecture is based around an LDAP-like database that
-can use a range of modular backends.  One of the backends supports
-standards compliant LDAP servers (including OpenLDAP), and we are
-working on modules to map between AD-like behaviours and this back-end.
-We are aiming for Samba 4 to be powerful front-end to large
-directories.
-
-Changes
--------
-
-Those familiar with Samba 3 can find a list of user-visible changes
-since that release series in the NEWS file.
-
-- An optional password is no longer supported as the second argument to
-  smbclient.
-
-- The default location of smb.conf in non-FHS builds has changed from the
-  PREFIX/lib directory to the PREFIX/etc directory.
-
-Known issues
-------------
-
-- Standalone server and domain member roles are not currently
-  supported.  While we have much of the infrastructure required, we
-  have not collected these pieces together.
-
-- There is no printing support in the current release.
-
-- SWAT can be painful with <TAB> and forms.  Just use the mouse, as
-  the JavaScript layer doing this will change.
-
-Running Samba4
---------------
-
-A short guide to setting up Samba 4 can be found in the howto.txt file
-in root of the tarball.
-
-Development and feedback
-------------------------
-
-Bugs can be filed at https://bugzilla.samba.org/. Please
-look at the STATUS file before filing a bug to see if a particular
-is supposed to work yet.
-
-Development and general discussion about Samba 4 happens mainly on
-the #samba-technical IRC channel (on irc.freenode.net) and
-the samba-technical mailing list (see http://lists.samba.org/ for
-details).
-
index f58df497f5e0cb5422daee00cdb1570acd768846..e4c4ea80877f305420905b69fa1853681d0ae341 100644 (file)
@@ -1,4 +1,4 @@
-What's new in Samba 4 alpha3
+What's new in Samba 4 alpha4
 ============================
 
 Samba 4 is the ambitious next version of the Samba suite that is being
@@ -10,14 +10,13 @@ Samba 4 is currently not yet in a state where it is usable in
 production environments. Note the WARNINGS below, and the STATUS file,
 which aims to document what should and should not work.
 
-Samba4 alpha3 follows on from our second alpha release (made in
-December), the first alpha release (made in September), and the
-Technology Preview series we have offered for some time now. 
+Samba4 alpha4 follows on from the alpha release series we have been
+publishing since September last year.
 
 WARNINGS
 ========
 
-Samba4 alpha3 is not a final Samba release.  That is more a reference
+Samba4 alpha4 is not a final Samba release.  That is more a reference
 to Samba4's lack of the features we expect you will need than a
 statement of code quality, but clearly it hasn't seen a broad
 deployment yet.  If you were to upgrade Samba3 (or indeed Windows) to
@@ -64,43 +63,47 @@ working on modules to map between AD-like behaviours and this backend.
 We are aiming for Samba 4 to be powerful frontend to large
 directories.
 
-CHANGES SINCE Alpha2
+CHANGES SINCE Alpha3
 =====================
 
 In the time since Samba4 Alpha2 was released in December 2007, Samba has
 continued to evolve, but you may particularly notice these areas:
 
-  Python Bindings: Bindings for Python are now in place, and used for
-  Samba's provision script, slowly displacing EJS as the embedded
-  scripting language.  With its increased use, Python is no longer
-  optional, and configure will generate an error if it cannot locate
-  an appropriate Python installation.
+  Python Bindings: Bindings for Python are now used for all internal
+  scripting, and the system python installation is used to run all
+  Samba python scripts (in place of smbpython found in the previous
+  alpha).
 
-  SWAT Disabled: Due to a lack of developer time and without a
-  long-term web developer to maintain it, the SWAT web UI has been
-  disabled.
+  As such Python is no longer optional, and configure will generate an
+  error if it cannot locate an appropriate Python installation.
 
-  Oplock support: Samba4's file server now supports oplocks
+  SWAT Remains Disabled: Due to a lack of developer time and without a
+  long-term web developer to maintain it, the SWAT web UI remains been
+  disabled (and would need to be rewritten in python in any case).
 
   GNU Make: To try and simplfy our build system, we rely on GNU Make
   to avoid autogenerating a massive single makefile. 
 
-  Account Expiry: Samba4 now better handles installations over 30 days
-  old (thanks to our long-suffering testers for keeping installations
-  around that long!)
+  Registry: Samba4's registry library has continued to improve.
 
-  Registry: Samba4 registry interoperability has been improved in
-  both the client utilities and in the registry service exposed by
-  the Samba4 server itself.
+  ID mapping: Samba4 uses the internal ID mapping in winbind for all
+  but a few core users.  Samba users should not appear in /etc/passwd,
+  as Samba will generate new user and group IDs regradless. 
 
-  Administrative Tools: Many enhancements have been made that allow
-  better integration with Windows administrative tools, especially
-  Active Directory Users and Computers.
+  NTP: Samba4 can act as a signing server for the ntp.org NTP deamon,
+  allowing NTPd to reply using Microsoft's non-standard signing
+  scheme.  A patch to make NTPd talk to Samba for this purpose has
+  been submitted to the ntp.org project.
 
-  ID mapping: Samba4 now handles ID mapping via winbind. The mappings
-  are stored in a central ldb that could be shared across multiple
-  machines using LDAP. Internal callers access this interface via a new
-  wbclient library.
+  CLDAP: Users should experience less arbitary delays and more success with
+  group policy, domain joins and logons due to an improved
+  implementation of CLDAP and the 'netlogon' mailslot datagrams.
+
+  SMB2: The Samba4 SMB2 server and testsuite have been greatly
+  improved, but the SMB2 server remains off by default.
+
+  Secure DNS update: Configuration for GSS-TSIG updates of DNS records
+  is now generated by the provision script.
 
 These are just some of the highlights of the work done in the past few
 months.  More details can be found in our GIT history.
@@ -120,12 +123,22 @@ KNOWN ISSUES
 
 - There is no printing support in the current release.
 
+- There is no netbios browsing support in the current release
+
 - The Samba4 port of the CTDB clustering support is not yet complete
 
 - Clock Synchronisation is critical.  Many 'wrong password' errors are
   actually due to Kerberos objecting to a clock skew between client
-  and server.  
+  and server.  (The NTP work is partly to assist with this problem).
+
+- Samba4 alpha4 is currently only portable to recent Linux
+  distributions.  Work to return support for other Unix varients is
+  expected during the next alpha cycle
 
+- Samba4 alpha4 is incompatible with GnuTLS 2.0, found in Fedora 9 and
+  recent Ubuntu releases.  Please remove the
+  gnutls-devel/libgnutls-dev package before compiling (otherwise 'make
+  test' and LDAPS operations will hang).
 
 RUNNING Samba4
 ==============
index d40eba4e8ad5402f030887fd1b0a3c661269304e..7a526c625e48c2c4e63671861b4bbf5942ae93e6 100644 (file)
@@ -57,7 +57,7 @@ SAMBA_VERSION_TP_RELEASE=
 # e.g. SAMBA_VERSION_ALPHA_RELEASE=1                   #
 #  ->  "4.0.0alpha1"                                   #
 ########################################################
-SAMBA_VERSION_ALPHA_RELEASE=4
+SAMBA_VERSION_ALPHA_RELEASE=5
 
 ########################################################
 # For 'pre' releases the version will be               #
index ed09cf0bbcc9efd0e1a00f58a5c12cc02ae8c126..b1faf9e0e645f5127e14f592a2e28f23d7a4fc73 100644 (file)
@@ -283,7 +283,8 @@ static NTSTATUS odb_oplock_break_send(struct odb_context *odb, struct opendb_ent
 */
 static NTSTATUS odb_ctdb_open_file(struct odb_lock *lck,
                                   void *file_handle, const char *path,
-                                  int *fd, bool allow_level_II_oplock,
+                                  int *fd, NTTIME open_write_time,
+                                  bool allow_level_II_oplock,
                                   uint32_t oplock_level, uint32_t *oplock_granted)
 
 {
@@ -492,37 +493,30 @@ static NTSTATUS odb_ctdb_set_delete_on_close(struct odb_lock *lck, bool del_on_c
        return odb_push_record(lck, &file);
 }
 
+static NTSTATUS odb_ctdb_set_write_time(struct odb_lock *lck,
+                                       NTTIME write_time, bool force)
+{
+       /*
+        * as this file will went away and isn't used yet,
+        * copy the implementation from the tdb backend
+        * --metze
+        */
+       return NT_STATUS_FOOBAR;
+}
+
 /*
   return the current value of the delete_on_close bit, and how many
   people still have the file open
 */
-static NTSTATUS odb_ctdb_get_delete_on_close(struct odb_context *odb, 
-                                           DATA_BLOB *key, bool *del_on_close)
+static NTSTATUS odb_ctdb_get_file_infos(struct odb_context *odb, DATA_BLOB *key,
+                                       bool *del_on_close, NTTIME *write_time)
 {
-       NTSTATUS status;
-       struct opendb_file file;
-       struct odb_lock *lck;
-
-       (*del_on_close) = false;
-
-       lck = odb_lock(odb, odb, key);
-       NT_STATUS_HAVE_NO_MEMORY(lck);
-
-       status = odb_pull_record(lck, &file);
-       if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) {
-               talloc_free(lck);
-               return NT_STATUS_OK;
-       }
-       if (!NT_STATUS_IS_OK(status)) {
-               talloc_free(lck);
-               return status;
-       }
-
-       (*del_on_close) = file.delete_on_close;
-
-       talloc_free(lck);
-
-       return NT_STATUS_OK;
+       /*
+        * as this file will went away and isn't used yet,
+        * copy the implementation from the tdb backend
+        * --metze
+        */
+       return NT_STATUS_FOOBAR;
 }
 
 
@@ -589,7 +583,8 @@ static const struct opendb_ops opendb_ctdb_ops = {
        .odb_rename              = odb_ctdb_rename,
        .odb_get_path            = odb_ctdb_get_path,
        .odb_set_delete_on_close = odb_ctdb_set_delete_on_close,
-       .odb_get_delete_on_close = odb_ctdb_get_delete_on_close,
+       .odb_set_write_time      = odb_ctdb_set_write_time,
+       .odb_get_file_infos      = odb_ctdb_get_file_infos,
        .odb_can_open            = odb_ctdb_can_open,
        .odb_update_oplock       = odb_ctdb_update_oplock,
        .odb_break_oplocks       = odb_ctdb_break_oplocks
index d4482a54b275243ca8414d4c069c001c42544b4a..ab7624eef0e4bbd63d204b070804e6b09f3c998f 100644 (file)
@@ -540,12 +540,18 @@ init_auth
        goto failure;
     }
 
-    ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token,
-                                  (u_char *)"\x01\x00", GSS_KRB5_MECHANISM);
-    if (ret)
-       goto failure;
+    if (flags & GSS_C_DCE_STYLE) {
+       output_token->value = outbuf.data;
+       output_token->length = outbuf.length;
+    } else {
+        ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token,
+                                   (u_char *)"\x01\x00", GSS_KRB5_MECHANISM);
+       if (ret)
+           goto failure;
+
+       krb5_data_free (&outbuf);
+    }
 
-    krb5_data_free (&outbuf);
     krb5_free_creds(context, kcred);
     free_Checksum(&cksum);
     if (cred == NULL)
index c76222c207d721379c35f29f7d32272ada02cd49..aba9581ec5775844c0c62cc5ffcac00be1ab24f2 100755 (executable)
@@ -14,7 +14,7 @@ from samba.auth import system_session
 from ldb import (SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError,
                  LDB_ERR_NO_SUCH_OBJECT, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
                  LDB_ERR_ENTRY_ALREADY_EXISTS, LDB_ERR_UNWILLING_TO_PERFORM,
-                 LDB_ERR_NOT_ALLOWED_ON_NON_LEAF, LDB_ERR_OTHER)
+                 LDB_ERR_NOT_ALLOWED_ON_NON_LEAF, LDB_ERR_OTHER, LDB_ERR_INVALID_DN_SYNTAX)
 from samba import Ldb
 from subunit import SubunitTestRunner
 from samba import param
@@ -115,6 +115,86 @@ class BasicTests(unittest.TestCase):
             "userAccountControl": "4096",
             "displayname": "ldap testy"})
 
+        self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
+        try:
+            ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
+                     "objectClass": "computer",
+                     "cn": "LDAPtest2COMPUTER"
+                     })
+            self.fail()
+        except LdbError, (num, _): 
+            self.assertEquals(num, LDB_ERR_INVALID_DN_SYNTAX)
+            
+        self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
+        try:
+            ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
+                     "objectClass": "computer",
+                     "cn": "ldaptestcomputer3",
+                     "sAMAccountType": "805306368"
+                })
+            self.fail()
+        except LdbError, (num, _): 
+            self.assertEquals(num, LDB_ERR_UNWILLING_TO_PERFORM)
+            
+        self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
+        try:
+            ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
+                     "objectClass": "computer",
+                     "cn": "ldaptestcomputer3",
+                     "userAccountControl": "0"
+                })
+            self.fail()
+        except LdbError, (num, _): 
+            self.assertEquals(num, LDB_ERR_UNWILLING_TO_PERFORM)
+            
+        self.delete_force(self.ldb, "cn=ldaptestuser7,cn=users," + self.base_dn)
+        try:
+            ldb.add({"dn": "cn=ldaptestuser7,cn=users," + self.base_dn,
+                     "objectClass": "user",
+                     "cn": "LDAPtestuser7",
+                     "userAccountControl": "0"
+                })
+            self.fail()
+        except LdbError, (num, _): 
+            self.assertEquals(num, LDB_ERR_UNWILLING_TO_PERFORM)
+            
+        self.delete_force(self.ldb, "cn=ldaptestuser7,cn=users," + self.base_dn)
+
+        ldb.add({"dn": "cn=ldaptestuser7,cn=users," + self.base_dn,
+                 "objectClass": "user",
+                 "cn": "LDAPtestuser7",
+                 "userAccountControl": "2"
+                 })
+            
+        self.delete_force(self.ldb, "cn=ldaptestuser7,cn=users," + self.base_dn)
+
+        self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
+        ldb.add({"dn": "cn=ldaptestcomputer3,cn=computers," + self.base_dn,
+                 "objectClass": "computer",
+                 "cn": "LDAPtestCOMPUTER3"
+                 })
+            
+       print "Testing ldb.search for (&(cn=ldaptestcomputer3)(objectClass=user))";
+        res = ldb.search(self.base_dn, expression="(&(cn=ldaptestcomputer3)(objectClass=user))");
+        self.assertEquals(len(res), 1, "Found only %d for (&(cn=ldaptestcomputer3)(objectClass=user))" % len(res))
+
+       self.assertEquals(str(res[0].dn), ("CN=ldaptestcomputer3,CN=Computers," + self.base_dn));
+       self.assertEquals(res[0]["cn"][0], "ldaptestcomputer3");
+       self.assertEquals(res[0]["name"][0], "ldaptestcomputer3");
+       self.assertEquals(res[0]["objectClass"][0], "top");
+       self.assertEquals(res[0]["objectClass"][1], "person");
+       self.assertEquals(res[0]["objectClass"][2], "organizationalPerson");
+       self.assertEquals(res[0]["objectClass"][3], "user");
+       self.assertEquals(res[0]["objectClass"][4], "computer");
+        self.assertTrue("objectGUID" in res[0])
+        self.assertTrue("whenCreated" in res[0])
+       self.assertEquals(res[0]["objectCategory"][0], ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn));
+       self.assertEquals(int(res[0]["primaryGroupID"][0]), 513);
+       self.assertEquals(int(res[0]["sAMAccountType"][0]), 805306368);
+       self.assertEquals(int(res[0]["userAccountControl"][0]), 546);
+
+        self.delete_force(self.ldb, "cn=ldaptestcomputer3,cn=computers," + self.base_dn)
+
         print "Testing attribute or value exists behaviour"
         try:
             ldb.modify_ldif("""
@@ -125,34 +205,36 @@ servicePrincipalName: host/ldaptest2computer
 servicePrincipalName: host/ldaptest2computer
 servicePrincipalName: cifs/ldaptest2computer
 """)
+            self.fail()
         except LdbError, (num, msg):
             self.assertEquals(num, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS)
 
-            ldb.modify_ldif("""
+        ldb.modify_ldif("""
 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
 changetype: modify
 replace: servicePrincipalName
 servicePrincipalName: host/ldaptest2computer
 servicePrincipalName: cifs/ldaptest2computer
 """)
-            try:
-                ldb.modify_ldif("""
+        try:
+            ldb.modify_ldif("""
 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
 changetype: modify
 add: servicePrincipalName
 servicePrincipalName: host/ldaptest2computer
 """)
-            except LdbError, (num, msg):
-                self.assertEquals(num, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS)
-            
-            print "Testing ranged results"
-            ldb.modify_ldif("""
+            self.fail()
+        except LdbError, (num, msg):
+            self.assertEquals(num, LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS)
+
+        print "Testing ranged results"
+        ldb.modify_ldif("""
 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
 changetype: modify
 replace: servicePrincipalName
 """)
             
-            ldb.modify_ldif("""
+        ldb.modify_ldif("""
 dn: cn=ldaptest2computer,cn=computers,""" + self.base_dn + """
 changetype: modify
 add: servicePrincipalName
@@ -188,53 +270,53 @@ servicePrincipalName: host/ldaptest2computer28
 servicePrincipalName: host/ldaptest2computer29
 """)
 
-            res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, 
-                             attrs=["servicePrincipalName;range=0-*"])
-            self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
-            #print len(res[0]["servicePrincipalName;range=0-*"])
-            self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
+        res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, 
+                         attrs=["servicePrincipalName;range=0-*"])
+        self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
+        #print len(res[0]["servicePrincipalName;range=0-*"])
+        self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
 
-            res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-19"])
-            self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
+        res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-19"])
+        self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
             # print res[0]["servicePrincipalName;range=0-19"].length
-            self.assertEquals(len(res[0]["servicePrincipalName;range=0-19"]), 20)
+        self.assertEquals(len(res[0]["servicePrincipalName;range=0-19"]), 20)
 
             
-            res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-30"])
-            self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
-            self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
+        res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-30"])
+        self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
+        self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
 
-            res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-40"])
-            self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
-            self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
+        res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=0-40"])
+        self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
+        self.assertEquals(len(res[0]["servicePrincipalName;range=0-*"]), 30)
 
-            res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=30-40"])
-            self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
-            self.assertEquals(len(res[0]["servicePrincipalName;range=30-*"]), 0)
+        res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=30-40"])
+        self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
+        self.assertEquals(len(res[0]["servicePrincipalName;range=30-*"]), 0)
 
             
-            res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=10-40"])
-            self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
-            self.assertEquals(len(res[0]["servicePrincipalName;range=10-*"]), 20)
-            # pos_11 = res[0]["servicePrincipalName;range=10-*"][18]
-
-            res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-40"])
-            self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
-            self.assertEquals(len(res[0]["servicePrincipalName;range=11-*"]), 19)
+        res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=10-40"])
+        self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
+        self.assertEquals(len(res[0]["servicePrincipalName;range=10-*"]), 20)
+        # pos_11 = res[0]["servicePrincipalName;range=10-*"][18]
+
+        res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-40"])
+        self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
+        self.assertEquals(len(res[0]["servicePrincipalName;range=11-*"]), 19)
             # print res[0]["servicePrincipalName;range=11-*"][18]
             # print pos_11
             # self.assertEquals((res[0]["servicePrincipalName;range=11-*"][18]), pos_11)
 
-            res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-15"])
-            self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
-            self.assertEquals(len(res[0]["servicePrincipalName;range=11-15"]), 5)
+        res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName;range=11-15"])
+        self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
+        self.assertEquals(len(res[0]["servicePrincipalName;range=11-15"]), 5)
             # self.assertEquals(res[0]["servicePrincipalName;range=11-15"][4], pos_11)
 
-            res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName"])
-            self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
+        res = ldb.search(self.base_dn, expression="(cn=ldaptest2computer))", scope=SCOPE_SUBTREE, attrs=["servicePrincipalName"])
+        self.assertEquals(len(res), 1, "Could not find (cn=ldaptest2computer)")
             # print res[0]["servicePrincipalName"][18]
             # print pos_11
-            self.assertEquals(len(res[0]["servicePrincipalName"]), 30)
+        self.assertEquals(len(res[0]["servicePrincipalName"]), 30)
             # self.assertEquals(res[0]["servicePrincipalName"][18], pos_11)
 
         self.delete_force(self.ldb, "cn=ldaptestuser2,cn=users," + self.base_dn)
@@ -322,6 +404,10 @@ servicePrincipalName: host/ldaptest2computer29
         res = ldb.search(expression="(&(anr=not ldap user2)(objectClass=user))")
         self.assertEquals(len(res), 0, "Must not find (&(anr=not ldap user2)(objectClass=user))")
 
+        # Testing ldb.search for (&(anr="testy ldap")(objectClass=user)) (ie, with quotes)
+        res = ldb.search(expression="(&(anr==\"testy ldap\")(objectClass=user))")
+        self.assertEquals(len(res), 0, "Found (&(anr==\"testy ldap\")(objectClass=user))")
+
         print "Testing Group Modifies"
         ldb.modify_ldif("""
 dn: cn=ldaptestgroup,cn=users,""" + self.base_dn + """
@@ -361,6 +447,26 @@ member: cn=ldaptestuser3,cn=users,""" + self.base_dn + """
         self.assertEquals(res[0]["cn"], "ldaptestUSER3")
         self.assertEquals(res[0]["name"], "ldaptestUSER3")
 
+       #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))"
+       res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
+        self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=*))(objectClass=user))")
+
+        self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
+        self.assertEquals(res[0]["cn"], "ldaptestUSER3")
+        self.assertEquals(res[0]["name"], "ldaptestUSER3")
+
+       #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))"
+       res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
+        self.assertEquals(len(res), 1, "(&(&(cn=ldaptestuser3)(userAccountControl=546))(objectClass=user))")
+
+        self.assertEquals(str(res[0].dn), ("CN=ldaptestUSER3,CN=Users," + self.base_dn))
+        self.assertEquals(res[0]["cn"], "ldaptestUSER3")
+        self.assertEquals(res[0]["name"], "ldaptestUSER3")
+
+       #"Testing ldb.search for (&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))"
+       res = ldb.search(expression="(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
+        self.assertEquals(len(res), 0, "(&(&(cn=ldaptestuser3)(userAccountControl=547))(objectClass=user))")
+
         # This is a Samba special, and does not exist in real AD
         #    print "Testing ldb.search for (dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")"
         #    res = ldb.search("(dn=CN=ldaptestUSER3,CN=Users," + self.base_dn + ")")
@@ -534,7 +640,7 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
         self.assertTrue("whenCreated" in res[0])
         self.assertEquals(res[0]["objectCategory"], ("CN=Person,CN=Schema,CN=Configuration," + self.base_dn))
         self.assertEquals(int(res[0]["sAMAccountType"][0]), 805306368)
-        # self.assertEquals(res[0].userAccountControl, 546)
+        self.assertEquals(int(res[0]["userAccountControl"][0]), 546)
         self.assertEquals(res[0]["memberOf"][0], ("CN=ldaptestgroup2,CN=Users," + self.base_dn))
         self.assertEquals(len(res[0]["memberOf"]), 1)
      
@@ -578,8 +684,8 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
         self.assertTrue("whenCreated" in res[0])
         self.assertEquals(res[0]["objectCategory"], ("CN=Computer,CN=Schema,CN=Configuration," + self.base_dn))
         self.assertEquals(int(res[0]["primaryGroupID"][0]), 513)
-        # self.assertEquals(res[0].sAMAccountType, 805306368)
-        # self.assertEquals(res[0].userAccountControl, 546)
+        self.assertEquals(int(res[0]["sAMAccountType"][0]), 805306368)
+        self.assertEquals(int(res[0]["userAccountControl"][0]), 546)
         self.assertEquals(res[0]["memberOf"][0], "CN=ldaptestgroup2,CN=Users," + self.base_dn)
         self.assertEquals(len(res[0]["memberOf"]), 1)
 
@@ -641,7 +747,7 @@ member: cn=ldaptestuser4,cn=ldaptestcontainer,""" + self.base_dn + """
         self.assertTrue("whenCreated" in res[0])
         self.assertEquals(res[0]["objectCategory"][0], "CN=Computer,CN=Schema,CN=Configuration," + self.base_dn)
         self.assertEquals(int(res[0]["sAMAccountType"][0]), 805306369)
-    #    self.assertEquals(res[0].userAccountControl, 4098)
+        self.assertEquals(int(res[0]["userAccountControl"][0]), 4096)
 
         ldb.delete(res[0].dn)
 
index 72bf23a9b4b143d4a3d12049bc69c7782cf378d1..cdbaa6cb1b51e5d69d2c3525be8814bf7ccfb177 100644 (file)
@@ -35,6 +35,8 @@ interface opendb
 
        typedef [public] struct {
                boolean8 delete_on_close;
+               NTTIME open_write_time;
+               NTTIME changed_write_time;
                utf8string path;
                uint32 num_entries;
                opendb_entry entries[num_entries];
index 2913ea8431c0d9025bc486744d6d081379df3c25..6917bad52ab9bc7ca82f0a68499889445a63f7a8 100644 (file)
@@ -97,11 +97,13 @@ 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,
-                               int *fd, bool allow_level_II_oplock,
+                               int *fd, NTTIME open_write_time,
+                               bool allow_level_II_oplock,
                                uint32_t oplock_level, uint32_t *oplock_granted)
 {
        return ops->odb_open_file(lck, file_handle, path,
-                                 fd, allow_level_II_oplock,
+                                 fd, open_write_time,
+                                 allow_level_II_oplock,
                                  oplock_level, oplock_granted);
 }
 
@@ -159,15 +161,23 @@ NTSTATUS odb_set_delete_on_close(struct odb_lock *lck, bool del_on_close)
 }
 
 /*
-  return the current value of the delete_on_close bit, and how many
-  people still have the file open
+  update the write time on an open file
 */
-NTSTATUS odb_get_delete_on_close(struct odb_context *odb, 
-                                         DATA_BLOB *key, bool *del_on_close)
+NTSTATUS odb_set_write_time(struct odb_lock *lck,
+                           NTTIME write_time, bool force)
 {
-       return ops->odb_get_delete_on_close(odb, key, del_on_close);
+       return ops->odb_set_write_time(lck, write_time, force);
 }
 
+/*
+  return the current value of the delete_on_close bit,
+  and the current write time.
+*/
+NTSTATUS odb_get_file_infos(struct odb_context *odb, DATA_BLOB *key,
+                           bool *del_on_close, NTTIME *write_time)
+{
+       return ops->odb_get_file_infos(odb, key, del_on_close, write_time);
+}
 
 /*
   determine if a file can be opened with the given share_access,
index 045476337abbb2bfd1acfbbd2825f3dbd6bc0a95..179db111ca06dd6e60190c996b2948a4348469e8 100644 (file)
@@ -27,7 +27,8 @@ struct opendb_ops {
        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,
-                                 int *fd, bool allow_level_II_oplock,
+                                 int *fd, NTTIME open_write_time,
+                                 bool allow_level_II_oplock,
                                  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,
@@ -36,8 +37,10 @@ struct opendb_ops {
        NTSTATUS (*odb_rename)(struct odb_lock *lck, const char *path);
        NTSTATUS (*odb_get_path)(struct odb_lock *lck, const char **path);
        NTSTATUS (*odb_set_delete_on_close)(struct odb_lock *lck, bool del_on_close);
-       NTSTATUS (*odb_get_delete_on_close)(struct odb_context *odb, 
-                                           DATA_BLOB *key, bool *del_on_close);
+       NTSTATUS (*odb_set_write_time)(struct odb_lock *lck,
+                                      NTTIME write_time, bool force);
+       NTSTATUS (*odb_get_file_infos)(struct odb_context *odb, DATA_BLOB *key,
+                                      bool *del_on_close, NTTIME *write_time);
        NTSTATUS (*odb_can_open)(struct odb_lock *lck,
                                 uint32_t stream_id, uint32_t share_access,
                                 uint32_t access_mask, bool delete_on_close,
index 99c0a95c20a4cac21853e6b50cd1a6f9b5e60af7..d7531297eda774e85f5bcda06f200461b2ad221f 100644 (file)
@@ -452,7 +452,8 @@ static NTSTATUS odb_tdb_open_can_internal(struct odb_context *odb,
 */
 static NTSTATUS odb_tdb_open_file(struct odb_lock *lck,
                                  void *file_handle, const char *path,
-                                 int *fd, bool allow_level_II_oplock,
+                                 int *fd, NTTIME open_write_time,
+                                 bool allow_level_II_oplock,
                                  uint32_t oplock_level, uint32_t *oplock_granted)
 {
        struct odb_context *odb = lck->odb;
@@ -474,6 +475,10 @@ static NTSTATUS odb_tdb_open_file(struct odb_lock *lck,
                NT_STATUS_HAVE_NO_MEMORY(lck->file.path);
        }
 
+       if (lck->file.open_write_time == 0) {
+               lck->file.open_write_time = open_write_time;
+       }
+
        /*
          possibly grant an exclusive, batch or level2 oplock
        */
@@ -784,21 +789,54 @@ static NTSTATUS odb_tdb_set_delete_on_close(struct odb_lock *lck, bool del_on_cl
        return odb_push_record(lck, &lck->file);
 }
 
+/*
+  update the write time on an open file
+*/
+static NTSTATUS odb_tdb_set_write_time(struct odb_lock *lck,
+                                      NTTIME write_time, bool force)
+{
+       if (lck->file.path == NULL) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       if (lck->file.changed_write_time != 0 && !force) {
+               return NT_STATUS_OK;
+       }
+
+       lck->file.changed_write_time = write_time;
+
+       return odb_push_record(lck, &lck->file);
+}
+
 /*
   return the current value of the delete_on_close bit, and how many
   people still have the file open
 */
-static NTSTATUS odb_tdb_get_delete_on_close(struct odb_context *odb, 
-                                           DATA_BLOB *key, bool *del_on_close)
+static NTSTATUS odb_tdb_get_file_infos(struct odb_context *odb, DATA_BLOB *key,
+                                      bool *del_on_close, NTTIME *write_time)
 {
        struct odb_lock *lck;
 
-       (*del_on_close) = false;
+       if (del_on_close) {
+               *del_on_close = false;
+       }
+       if (write_time) {
+               *write_time = 0;
+       }
 
        lck = odb_lock(odb, odb, key);
        NT_STATUS_HAVE_NO_MEMORY(lck);
 
-       (*del_on_close) = lck->file.delete_on_close;
+       if (del_on_close) {
+               *del_on_close = lck->file.delete_on_close;
+       }
+       if (write_time) {
+               if (lck->file.changed_write_time == 0) {
+                       *write_time = lck->file.open_write_time;
+               } else {
+                       *write_time = lck->file.changed_write_time;
+               }
+       }
 
        talloc_free(lck);
 
@@ -852,7 +890,8 @@ static const struct opendb_ops opendb_tdb_ops = {
        .odb_rename              = odb_tdb_rename,
        .odb_get_path            = odb_tdb_get_path,
        .odb_set_delete_on_close = odb_tdb_set_delete_on_close,
-       .odb_get_delete_on_close = odb_tdb_get_delete_on_close,
+       .odb_set_write_time      = odb_tdb_set_write_time,
+       .odb_get_file_infos      = odb_tdb_get_file_infos,
        .odb_can_open            = odb_tdb_can_open,
        .odb_update_oplock       = odb_tdb_update_oplock,
        .odb_break_oplocks       = odb_tdb_break_oplocks
index 04f6ad78d0f8e44e1ca32cd3970e5a7602dcd23f..a14c8f64ae0c5fd5a98da7d1e0faac3a42f4b890 100644 (file)
@@ -52,8 +52,13 @@ static uint32_t dos_mode_from_stat(struct pvfs_state *pvfs, struct stat *st)
 /*
   fill in the dos file attributes for a file
 */
-NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name, int fd)
+NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name,
+                           uint_t flags, int fd)
 {
+       NTSTATUS status;
+       DATA_BLOB lkey;
+       NTTIME write_time;
+
        /* make directories appear as size 0 with 1 link */
        if (S_ISDIR(name->st.st_mode)) {
                name->st.st_size = 0;
@@ -85,7 +90,29 @@ NTSTATUS pvfs_fill_dos_info(struct pvfs_state *pvfs, struct pvfs_filename *name,
        name->dos.file_id = (((uint64_t)name->st.st_dev)<<32) | name->st.st_ino;
        name->dos.flags = 0;
 
-       return pvfs_dosattrib_load(pvfs, name, fd);
+       status = pvfs_dosattrib_load(pvfs, name, fd);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       if (flags & PVFS_RESOLVE_NO_OPENDB) {
+               return NT_STATUS_OK;
+       }
+
+       status = pvfs_locking_key(name, name, &lkey);
+       NT_STATUS_NOT_OK_RETURN(status);
+
+       status = odb_get_file_infos(pvfs->odb_context, &lkey,
+                                   NULL, &write_time);
+       data_blob_free(&lkey);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1,("WARNING: odb_get_file_infos: %s\n", nt_errstr(status)));
+               return status;
+       }
+
+       if (!null_time(write_time)) {
+               name->dos.write_time = write_time;
+       }
+
+       return NT_STATUS_OK;
 }
 
 
index dada9f503f5334ce9b2b1e86b34cc2120cbdbd84..43203086f8711de7859cad828aa2388c6f81e7eb 100644 (file)
@@ -280,6 +280,7 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
        f->handle->position          = 0;
        f->handle->mode              = 0;
        f->handle->oplock            = NULL;
+       ZERO_STRUCT(f->handle->write_time);
        f->handle->open_completed    = false;
 
        if ((create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
@@ -317,7 +318,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
 
                /* now really mark the file as open */
                status = odb_open_file(lck, f->handle, name->full_name,
-                                      NULL, false, OPLOCK_NONE, NULL);
+                                      NULL, name->dos.write_time,
+                                      false, OPLOCK_NONE, NULL);
 
                if (!NT_STATUS_IS_OK(status)) {
                        talloc_free(lck);
@@ -377,7 +379,8 @@ static NTSTATUS pvfs_open_directory(struct pvfs_state *pvfs,
                }
 
                status = odb_open_file(lck, f->handle, name->full_name,
-                                      NULL, false, OPLOCK_NONE, NULL);
+                                      NULL, name->dos.write_time,
+                                      false, OPLOCK_NONE, NULL);
 
                if (!NT_STATUS_IS_OK(status)) {
                        goto cleanup_delete;
@@ -433,6 +436,9 @@ cleanup_delete:
 */
 static int pvfs_handle_destructor(struct pvfs_file_handle *h)
 {
+       talloc_free(h->write_time.update_event);
+       h->write_time.update_event = NULL;
+
        if ((h->create_options & NTCREATEX_OPTIONS_DELETE_ON_CLOSE) &&
            h->name->stream_name) {
                NTSTATUS status;
@@ -451,6 +457,14 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h)
                h->fd = -1;
        }
 
+       if (!h->write_time.update_forced &&
+           h->write_time.update_on_close &&
+           h->write_time.close_time == 0) {
+               struct timeval tv;
+               tv = timeval_current();
+               h->write_time.close_time = timeval_to_nttime(&tv);
+       }
+
        if (h->have_opendb_entry) {
                struct odb_lock *lck;
                NTSTATUS status;
@@ -462,6 +476,26 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h)
                        return 0;
                }
 
+               if (h->write_time.update_forced) {
+                       status = odb_get_file_infos(h->pvfs->odb_context,
+                                                   &h->odb_locking_key,
+                                                   NULL,
+                                                   &h->write_time.close_time);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(0,("Unable get write time for '%s' - %s\n",
+                                        h->name->full_name, nt_errstr(status)));
+                       }
+
+                       h->write_time.update_forced = false;
+                       h->write_time.update_on_close = true;
+               } else if (h->write_time.update_on_close) {
+                       status = odb_set_write_time(lck, h->write_time.close_time, true);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(0,("Unable set write time for '%s' - %s\n",
+                                        h->name->full_name, nt_errstr(status)));
+                       }
+               }
+
                status = odb_close_file(lck, h, &delete_path);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0,("Unable to remove opendb entry for '%s' - %s\n", 
@@ -484,11 +518,26 @@ static int pvfs_handle_destructor(struct pvfs_file_handle *h)
                                               FILE_NOTIFY_CHANGE_FILE_NAME,
                                               delete_path);
                        }
+                       h->write_time.update_on_close = false;
                }
 
                talloc_free(lck);
        }
 
+       if (h->write_time.update_on_close) {
+               struct timeval tv[2];
+
+               nttime_to_timeval(&tv[0], h->name->dos.access_time);
+               nttime_to_timeval(&tv[1], h->write_time.close_time);
+
+               if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
+                       if (utimes(h->name->full_name, tv) == -1) {
+                               DEBUG(0,("pvfs_handle_destructor: utimes() failed '%s' - %s\n",
+                                        h->name->full_name, strerror(errno)));
+                       }
+               }
+       }
+
        return 0;
 }
 
@@ -594,8 +643,8 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
                DATA_BLOB locking_key;
                status = pvfs_locking_key(parent, req, &locking_key);
                NT_STATUS_NOT_OK_RETURN(status);
-               status = odb_get_delete_on_close(pvfs->odb_context, &locking_key, 
-                                                &del_on_close);
+               status = odb_get_file_infos(pvfs->odb_context, &locking_key,
+                                           &del_on_close, NULL);
                NT_STATUS_NOT_OK_RETURN(status);
                if (del_on_close) {
                        return NT_STATUS_DELETE_PENDING;
@@ -638,7 +687,7 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        }
 
        /* re-resolve the open fd */
-       status = pvfs_resolve_name_fd(pvfs, fd, name);
+       status = pvfs_resolve_name_fd(pvfs, fd, name, 0);
        if (!NT_STATUS_IS_OK(status)) {
                close(fd);
                return status;
@@ -730,10 +779,12 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs,
        f->handle->mode              = 0;
        f->handle->oplock            = NULL;
        f->handle->have_opendb_entry = true;
+       ZERO_STRUCT(f->handle->write_time);
        f->handle->open_completed    = false;
 
        status = odb_open_file(lck, f->handle, name->full_name,
-                              &f->handle->fd, allow_level_II_oplock,
+                              &f->handle->fd, name->dos.write_time,
+                              allow_level_II_oplock,
                               oplock_level, &oplock_granted);
        talloc_free(lck);
        if (!NT_STATUS_IS_OK(status)) {
@@ -1334,6 +1385,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        f->handle->mode              = 0;
        f->handle->oplock            = NULL;
        f->handle->have_opendb_entry = false;
+       ZERO_STRUCT(f->handle->write_time);
        f->handle->open_completed    = false;
 
        /* form the lock context used for byte range locking and
@@ -1437,7 +1489,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
 
        /* now really mark the file as open */
        status = odb_open_file(lck, f->handle, name->full_name,
-                              &f->handle->fd, allow_level_II_oplock,
+                              &f->handle->fd, name->dos.write_time,
+                              allow_level_II_oplock,
                               oplock_level, &oplock_granted);
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -1476,7 +1529,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs,
        }
 
        /* re-resolve the open fd */
-       status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name);
+       status = pvfs_resolve_name_fd(f->pvfs, fd, f->handle->name, PVFS_RESOLVE_NO_OPENDB);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(lck);
                return status;
@@ -1538,7 +1591,6 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
        struct pvfs_file *f;
-       struct utimbuf unix_times;
 
        if (io->generic.level == RAW_CLOSE_SPLCLOSE) {
                return NT_STATUS_DOS(ERRSRV, ERRerror);
@@ -1554,9 +1606,9 @@ NTSTATUS pvfs_close(struct ntvfs_module_context *ntvfs,
        }
 
        if (!null_time(io->generic.in.write_time)) {
-               unix_times.actime = 0;
-               unix_times.modtime = io->close.in.write_time;
-               utime(f->handle->name->full_name, &unix_times);
+               f->handle->write_time.update_forced = false;
+               f->handle->write_time.update_on_close = true;
+               unix_to_nt_time(&f->handle->write_time.close_time, io->generic.in.write_time);
        }
 
        if (io->generic.in.flags & SMB2_CLOSE_FLAGS_FULL_INFORMATION) {
@@ -1915,8 +1967,8 @@ bool pvfs_delete_on_close_set(struct pvfs_state *pvfs, struct pvfs_file_handle *
        NTSTATUS status;
        bool del_on_close;
 
-       status = odb_get_delete_on_close(pvfs->odb_context, &h->odb_locking_key, 
-                                        &del_on_close);
+       status = odb_get_file_infos(pvfs->odb_context, &h->odb_locking_key, 
+                                   &del_on_close, NULL);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1,("WARNING: unable to determine delete on close status for open file\n"));
                return false;
index 5c2a627084c6c98bdeddfc9d8e51623d1139a1a1..d8ea5896e560f417870d9709e8dc76559ac0743d 100644 (file)
@@ -287,7 +287,9 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
 
        /* get a pvfs_filename source object */
        status = pvfs_resolve_partial(pvfs, mem_ctx, 
-                                     dir_path, fname1, &name1);
+                                     dir_path, fname1,
+                                     PVFS_RESOLVE_NO_OPENDB,
+                                     &name1);
        if (!NT_STATUS_IS_OK(status)) {
                goto failed;
        }
@@ -306,7 +308,9 @@ static NTSTATUS pvfs_rename_one(struct pvfs_state *pvfs,
 
        /* get a pvfs_filename dest object */
        status = pvfs_resolve_partial(pvfs, mem_ctx, 
-                                     dir_path, fname2, &name2);
+                                     dir_path, fname2,
+                                     PVFS_RESOLVE_NO_OPENDB,
+                                     &name2);
        if (NT_STATUS_IS_OK(status)) {
                status = pvfs_can_delete(pvfs, req, name2, NULL);
                if (!NT_STATUS_IS_OK(status)) {
index 2e97925c494e735557980eda4d809030e8963998..0f19788b9731d0587f5d3e6b50bb7f7aefd326c1 100644 (file)
@@ -57,7 +57,9 @@ static int component_compare(struct pvfs_state *pvfs, const char *comp, const ch
   TODO: add a cache for previously resolved case-insensitive names
   TODO: add mangled name support
 */
-static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, struct pvfs_filename *name)
+static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs,
+                                struct pvfs_filename *name,
+                                uint_t flags)
 {
        /* break into a series of components */
        int num_components;
@@ -175,7 +177,7 @@ static NTSTATUS pvfs_case_search(struct pvfs_state *pvfs, struct pvfs_filename *
        name->full_name = partial_name;
 
        if (name->exists) {
-               return pvfs_fill_dos_info(pvfs, name, -1);
+               return pvfs_fill_dos_info(pvfs, name, flags, -1);
        }
 
        return NT_STATUS_OK;
@@ -515,7 +517,7 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
                /* we need to search for a matching name */
                saved_name = (*name)->full_name;
                (*name)->full_name = dir_name;
-               status = pvfs_case_search(pvfs, *name);
+               status = pvfs_case_search(pvfs, *name, flags);
                if (!NT_STATUS_IS_OK(status)) {
                        /* the directory doesn't exist */
                        (*name)->full_name = saved_name;
@@ -536,11 +538,11 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
        /* if we can stat() the full name now then we are done */
        if (stat((*name)->full_name, &(*name)->st) == 0) {
                (*name)->exists = true;
-               return pvfs_fill_dos_info(pvfs, *name, -1);
+               return pvfs_fill_dos_info(pvfs, *name, flags, -1);
        }
 
        /* search for a matching filename */
-       status = pvfs_case_search(pvfs, *name);
+       status = pvfs_case_search(pvfs, *name, flags);
 
        return status;
 }
@@ -556,7 +558,7 @@ NTSTATUS pvfs_resolve_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
 */
 NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
                              const char *unix_dir, const char *fname,
-                             struct pvfs_filename **name)
+                             uint_t flags, struct pvfs_filename **name)
 {
        NTSTATUS status;
 
@@ -581,7 +583,7 @@ NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
        (*name)->stream_name = NULL;
        (*name)->stream_id = 0;
 
-       status = pvfs_fill_dos_info(pvfs, *name, -1);
+       status = pvfs_fill_dos_info(pvfs, *name, flags, -1);
 
        return status;
 }
@@ -593,7 +595,7 @@ NTSTATUS pvfs_resolve_partial(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
   to update the pvfs_filename stat information, and by pvfs_open()
 */
 NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd,
-                             struct pvfs_filename *name)
+                             struct pvfs_filename *name, uint_t flags)
 {
        dev_t device = (dev_t)0;
        ino_t inode = 0;
@@ -626,7 +628,7 @@ NTSTATUS pvfs_resolve_name_fd(struct pvfs_state *pvfs, int fd,
 
        name->exists = true;
        
-       return pvfs_fill_dos_info(pvfs, name, fd);
+       return pvfs_fill_dos_info(pvfs, name, flags, fd);
 }
 
 /*
@@ -703,9 +705,17 @@ NTSTATUS pvfs_resolve_name_handle(struct pvfs_state *pvfs,
                talloc_free(lck);
        }
 
-       status = pvfs_resolve_name_fd(pvfs, h->fd, h->name);
+       /*
+        * TODO: pass PVFS_RESOLVE_NO_OPENDB and get
+        *       the write time from odb_lock() above.
+        */
+       status = pvfs_resolve_name_fd(pvfs, h->fd, h->name, 0);
        NT_STATUS_NOT_OK_RETURN(status);
 
+       if (!null_nttime(h->write_time.close_time)) {
+               h->name->dos.write_time = h->write_time.close_time;
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -755,7 +765,7 @@ NTSTATUS pvfs_resolve_parent(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx,
        (*name)->stream_name = NULL;
        (*name)->stream_id = 0;
 
-       status = pvfs_fill_dos_info(pvfs, *name, -1);
+       status = pvfs_fill_dos_info(pvfs, *name, PVFS_RESOLVE_NO_OPENDB, -1);
 
        return status;
 }
index e47406dc09e46a116fe4e809075eee4f93af5882..e0fe4fb64d9ca5ebe84c2f6c1c6974652d0c2606 100644 (file)
@@ -84,7 +84,7 @@ static NTSTATUS fill_search_info(struct pvfs_state *pvfs,
                                                      in pvfs_list_seek_ofs() for 
                                                      how we cope with this */
 
-       status = pvfs_resolve_partial(pvfs, file, unix_path, fname, &name);
+       status = pvfs_resolve_partial(pvfs, file, unix_path, fname, 0, &name);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
index 3ea8b7cb6ecbf95d139b05fa941cc78715c43dcd..a3c4024ed7ea532bc8512280470dea68a8a34792 100644 (file)
@@ -52,7 +52,7 @@ NTSTATUS pvfs_seek(struct ntvfs_module_context *ntvfs,
                break;
 
        case SEEK_MODE_END:
-               status = pvfs_resolve_name_fd(pvfs, h->fd, h->name);
+               status = pvfs_resolve_name_fd(pvfs, h->fd, h->name, PVFS_RESOLVE_NO_OPENDB);
                h->seek_offset = h->name->st.st_size + io->lseek.in.offset;
                break;
        }
index 1dd2c075d9abf57254552f399ecfdee4c9763e12..2cde5f42aae3172a3c707c3dd4e0f95c93973ee4 100644 (file)
@@ -273,7 +273,6 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
                          union smb_setfileinfo *info)
 {
        struct pvfs_state *pvfs = ntvfs->private_data;
-       struct utimbuf unix_times;
        struct pvfs_file *f;
        struct pvfs_file_handle *h;
        struct pvfs_filename newstats;
@@ -437,23 +436,54 @@ NTSTATUS pvfs_setfileinfo(struct ntvfs_module_context *ntvfs,
        }
 
        /* possibly change the file timestamps */
-       ZERO_STRUCT(unix_times);
        if (newstats.dos.create_time != h->name->dos.create_time) {
                change_mask |= FILE_NOTIFY_CHANGE_CREATION;
        }
        if (newstats.dos.access_time != h->name->dos.access_time) {
-               unix_times.actime = nt_time_to_unix(newstats.dos.access_time);
                change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
        }
        if (newstats.dos.write_time != h->name->dos.write_time) {
-               unix_times.modtime = nt_time_to_unix(newstats.dos.write_time);
                change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE;
        }
-       if (unix_times.actime != 0 || unix_times.modtime != 0) {
-               if (utime(h->name->full_name, &unix_times) == -1) {
-                       return pvfs_map_errno(pvfs, errno);
+       if ((change_mask & FILE_NOTIFY_CHANGE_LAST_ACCESS) ||
+           (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE)) {
+               struct timeval tv[2];
+
+               nttime_to_timeval(&tv[0], newstats.dos.access_time);
+               nttime_to_timeval(&tv[1], newstats.dos.write_time);
+
+               if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
+                       if (utimes(h->name->full_name, tv) == -1) {
+                               DEBUG(0,("pvfs_setfileinfo: utimes() failed '%s' - %s\n",
+                                        h->name->full_name, strerror(errno)));
+                               return pvfs_map_errno(pvfs, errno);
+                       }
                }
        }
+       if (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE) {
+               struct odb_lock *lck;
+
+               lck = odb_lock(req, h->pvfs->odb_context, &h->odb_locking_key);
+               if (lck == NULL) {
+                       DEBUG(0,("Unable to lock opendb for write time update\n"));
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+
+               status = odb_set_write_time(lck, newstats.dos.write_time, true);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,("Unable to update write time: %s\n",
+                               nt_errstr(status)));
+                       talloc_free(lck);
+                       return status;
+               }
+
+               talloc_free(lck);
+
+               h->write_time.update_forced = true;
+               h->write_time.update_on_close = false;
+               talloc_free(h->write_time.update_event);
+               h->write_time.update_event = NULL;
+       }
 
        /* possibly change the attribute */
        if (newstats.dos.attrib != h->name->dos.attrib) {
@@ -570,7 +600,6 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
        struct pvfs_filename *name;
        struct pvfs_filename newstats;
        NTSTATUS status;
-       struct utimbuf unix_times;
        uint32_t access_needed;
        uint32_t change_mask = 0;
        struct odb_lock *lck = NULL;
@@ -736,21 +765,51 @@ NTSTATUS pvfs_setpathinfo(struct ntvfs_module_context *ntvfs,
        }
 
        /* possibly change the file timestamps */
-       ZERO_STRUCT(unix_times);
        if (newstats.dos.create_time != name->dos.create_time) {
                change_mask |= FILE_NOTIFY_CHANGE_CREATION;
        }
        if (newstats.dos.access_time != name->dos.access_time) {
-               unix_times.actime = nt_time_to_unix(newstats.dos.access_time);
                change_mask |= FILE_NOTIFY_CHANGE_LAST_ACCESS;
        }
        if (newstats.dos.write_time != name->dos.write_time) {
-               unix_times.modtime = nt_time_to_unix(newstats.dos.write_time);
                change_mask |= FILE_NOTIFY_CHANGE_LAST_WRITE;
        }
-       if (unix_times.actime != 0 || unix_times.modtime != 0) {
-               if (utime(name->full_name, &unix_times) == -1) {
-                       return pvfs_map_errno(pvfs, errno);
+       if ((change_mask & FILE_NOTIFY_CHANGE_LAST_ACCESS) ||
+           (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE)) {
+               struct timeval tv[2];
+
+               nttime_to_timeval(&tv[0], newstats.dos.access_time);
+               nttime_to_timeval(&tv[1], newstats.dos.write_time);
+
+               if (!timeval_is_zero(&tv[0]) || !timeval_is_zero(&tv[1])) {
+                       if (utimes(name->full_name, tv) == -1) {
+                               DEBUG(0,("pvfs_setpathinfo: utimes() failed '%s' - %s\n",
+                                        name->full_name, strerror(errno)));
+                               return pvfs_map_errno(pvfs, errno);
+                       }
+               }
+       }
+       if (change_mask & FILE_NOTIFY_CHANGE_LAST_WRITE) {
+               if (lck == NULL) {
+                       DATA_BLOB lkey;
+                       status = pvfs_locking_key(name, name, &lkey);
+                       NT_STATUS_NOT_OK_RETURN(status);
+
+                       lck = odb_lock(req, pvfs->odb_context, &lkey);
+                       data_blob_free(&lkey);
+                       if (lck == NULL) {
+                               DEBUG(0,("Unable to lock opendb for write time update\n"));
+                               return NT_STATUS_INTERNAL_ERROR;
+                       }
+               }
+
+               status = odb_set_write_time(lck, newstats.dos.write_time, true);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+                       /* it could be that nobody has opened the file */
+               } else if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0,("Unable to update write time: %s\n",
+                               nt_errstr(status)));
+                       return status;
                }
        }
 
index 4cb47a4f1fa330c4bb113909412e705c87dfa12a..6a5704177041ea9b1b808fa7bda36d9f3bd29ef6 100644 (file)
@@ -201,7 +201,10 @@ NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
 
        /* resolve the cifs name to a posix name */
        status = pvfs_resolve_name(pvfs, req, unl->unlink.in.pattern, 
-                                  PVFS_RESOLVE_WILDCARD | PVFS_RESOLVE_STREAMS, &name);
+                                  PVFS_RESOLVE_WILDCARD |
+                                  PVFS_RESOLVE_STREAMS |
+                                  PVFS_RESOLVE_NO_OPENDB,
+                                  &name);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -246,7 +249,9 @@ NTSTATUS pvfs_unlink(struct ntvfs_module_context *ntvfs,
                /* get a pvfs_filename object */
                status = pvfs_resolve_partial(pvfs, req,
                                              pvfs_list_unix_path(dir),
-                                             fname, &name);
+                                             fname,
+                                             PVFS_RESOLVE_NO_OPENDB,
+                                             &name);
                if (!NT_STATUS_IS_OK(status)) {
                        return status;
                }
index 1f662f13fcdab52618bb4c5f07d8357dc9c57ef2..2da0e4bb3afc4f02c6915d5c967aca3414126551 100644 (file)
 #include "includes.h"
 #include "vfs_posix.h"
 #include "librpc/gen_ndr/security.h"
+#include "lib/events/events.h"
 
+static void pvfs_write_time_update_handler(struct event_context *ev,
+                                          struct timed_event *te,
+                                          struct timeval tv,
+                                          void *private_data)
+{
+       struct pvfs_file_handle *h = talloc_get_type(private_data,
+                                    struct pvfs_file_handle);
+       struct odb_lock *lck;
+       NTSTATUS status;
+       NTTIME write_time;
+
+       lck = odb_lock(h, h->pvfs->odb_context, &h->odb_locking_key);
+       if (lck == NULL) {
+               DEBUG(0,("Unable to lock opendb for write time update\n"));
+               return;
+       }
+
+       write_time = timeval_to_nttime(&tv);
+
+       status = odb_set_write_time(lck, write_time, false);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("Unable to update write time: %s\n",
+                       nt_errstr(status)));
+               return;
+       }
+
+       talloc_free(lck);
+
+       h->write_time.update_event = NULL;
+}
+
+static void pvfs_trigger_write_time_update(struct pvfs_file_handle *h)
+{
+       struct pvfs_state *pvfs = h->pvfs;
+       struct timeval tv;
+
+       if (h->write_time.update_triggered) {
+               return;
+       }
+
+       tv = timeval_current_ofs(0, pvfs->writetime_delay);
+
+       h->write_time.update_triggered = true;
+       h->write_time.update_on_close = true;
+       h->write_time.update_event = event_add_timed(pvfs->ntvfs->ctx->event_ctx,
+                                                    h, tv,
+                                                    pvfs_write_time_update_handler,
+                                                    h);
+       if (!h->write_time.update_event) {
+               DEBUG(0,("Failed event_add_timed\n"));
+       }
+}
 
 /*
   write to a file
@@ -61,6 +114,8 @@ NTSTATUS pvfs_write(struct ntvfs_module_context *ntvfs,
        status = pvfs_break_level2_oplocks(f);
        NT_STATUS_NOT_OK_RETURN(status);
 
+       pvfs_trigger_write_time_update(f->handle);
+
        if (f->handle->name->stream_name) {
                ret = pvfs_stream_write(pvfs,
                                        f->handle,
index 14b5210fd0e6ced1db9d99cd944b5cf13a2e984b..b5dd270346122ab5b169d28fdcf601fbce50d8ca 100644 (file)
@@ -95,6 +95,10 @@ static void pvfs_setup_options(struct pvfs_state *pvfs)
                                                      PVFS_OPLOCK_TIMEOUT,
                                                      PVFS_OPLOCK_TIMEOUT_DEFAULT);
 
+       pvfs->writetime_delay = share_int_option(scfg,
+                                                PVFS_WRITETIME_DELAY,
+                                                PVFS_WRITETIME_DELAY_DEFAULT);
+
        pvfs->share_name = talloc_strdup(pvfs, scfg->name);
 
        pvfs->fs_attribs = 
index c194698b64e23510ee486791702d284500b6520a..cf39bcf0ac0db318f0246dec8a65638b71f105db 100644 (file)
@@ -59,6 +59,9 @@ struct pvfs_state {
        /* the oplock break timeout (secs) */
        uint_t oplock_break_timeout;
 
+       /* the write time update delay (nsecs) */
+       uint_t writetime_delay;
+
        /* filesystem attributes (see FS_ATTR_*) */
        uint32_t fs_attribs;
 
@@ -169,6 +172,14 @@ struct pvfs_file_handle {
        /* we need this hook back to our parent for lock destruction */
        struct pvfs_state *pvfs;
 
+       struct {
+               bool update_triggered;
+               struct timed_event *update_event;
+               bool update_on_close;
+               NTTIME close_time;
+               bool update_forced;
+       } write_time;
+
        /* the open went through to completion */
        bool open_completed;
 };
@@ -220,6 +231,7 @@ struct pvfs_search_state {
 /* flags to pvfs_resolve_name() */
 #define PVFS_RESOLVE_WILDCARD    (1<<0)
 #define PVFS_RESOLVE_STREAMS     (1<<1)
+#define PVFS_RESOLVE_NO_OPENDB   (1<<2)
 
 /* flags in pvfs->flags */
 #define PVFS_FLAG_CI_FILESYSTEM  (1<<0) /* the filesystem is case insensitive */
@@ -249,6 +261,7 @@ struct pvfs_odb_retry;
 #define PVFS_FAKE_OPLOCKS              "posix:fakeoplocks"
 #define PVFS_SHARE_DELAY               "posix:sharedelay"
 #define PVFS_OPLOCK_TIMEOUT            "posix:oplocktimeout"
+#define PVFS_WRITETIME_DELAY           "posix:writetimeupdatedelay"
 #define PVFS_ALLOCATION_ROUNDING       "posix:allocationrounding"
 #define PVFS_SEARCH_INACTIVITY         "posix:searchinactivity"
 #define PVFS_ACL                       "posix:acl"
@@ -258,6 +271,7 @@ struct pvfs_odb_retry;
 #define PVFS_FAKE_OPLOCKS_DEFAULT              false
 #define PVFS_SHARE_DELAY_DEFAULT               1000000 /* nsecs */
 #define PVFS_OPLOCK_TIMEOUT_DEFAULT            30 /* secs */
+#define PVFS_WRITETIME_DELAY_DEFAULT           2000000 /* nsecs */
 #define PVFS_ALLOCATION_ROUNDING_DEFAULT       512
 #define PVFS_SEARCH_INACTIVITY_DEFAULT         300
 
index 67d4a4f62981cf5b571a9a31b563aca8d6928258..ded7922ec98ba054a0ca4a8fafedc32957161003 100644 (file)
@@ -5,7 +5,6 @@
 # a successful run for any of these tests an error.
 local.resolve.*.async
 local.iconv.*.next_codepoint()
-base.delaywrite.finfo update on close
 base.delete.*.deltest20a
 base.delete.*.deltest20b
 rpc.winreg.*security
index 7a6c54e9ec144e1b4dfb1e1532072a30adb6485f..bf25172c76f134198bff2ea357516012f77512ca 100644 (file)
@@ -14,7 +14,6 @@
 #
 # Please add a comment for each testsuite you disable explaining why 
 # it is being skipped.
-base.delaywrite
 raw.composite
 base.iometer
 base.casetable
@@ -28,7 +27,6 @@ samba4.ntvfs.cifs.raw.qfileinfo.ipc
 smb2.notify
 smb2.scan
 ntvfs.cifs.base.charset
-ntvfs.cifs.base.delaywrite
 ntvfs.cifs.base.iometer
 ntvfs.cifs.base.casetable
 ntvfs.cifs.base.nttrans
index b73ba5558687614fe6fb4496b63ab8af75251e32..1d550cbfe15dc145a6b5e3a63e60a539904a1da1 100755 (executable)
@@ -213,7 +213,11 @@ 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 --option=torture:oplocktimeout=3"
+NTVFSARGS=""
+NTVFSARGS="${NTVFSARGS} --option=torture:sharedelay=100000"
+NTVFSARGS="${NTVFSARGS} --option=torture:oplocktimeout=3"
+NTVFSARGS="${NTVFSARGS} --option=torture:writetimeupdatedelay=500000"
+
 smb2=`$smb4torture --list | grep "^SMB2-" | xargs`
 #The QFILEINFO-IPC test needs to be on ipc$
 raw=`$smb4torture --list | grep "^RAW-" | grep -v "RAW-QFILEINFO-IPC"| xargs`
index 9f771ab8a3ee57118fdb622910d870a48d05eb6a..bcee9264818aa6a6fd6db8fe1f5280734f64faae 100644 (file)
@@ -581,6 +581,7 @@ sub provision($$$$$$)
        posix:sharedelay = 100000
        posix:eadb = $lockdir/eadb.tdb
        posix:oplocktimeout = 3
+       posix:writetimeupdatedelay = 500000
 
 [test1]
        path = $tmpdir/test1
@@ -589,6 +590,7 @@ sub provision($$$$$$)
        posix:sharedelay = 100000
        posix:eadb = $lockdir/eadb.tdb
        posix:oplocktimeout = 3
+       posix:writetimeupdatedelay = 500000
 
 [test2]
        path = $tmpdir/test2
@@ -597,6 +599,7 @@ sub provision($$$$$$)
        posix:sharedelay = 100000
        posix:eadb = $lockdir/eadb.tdb
        posix:oplocktimeout = 3
+       posix:writetimeupdatedelay = 500000
 
 [cifs]
        read only = no
index ac4f565a2ba207139599801b2b2ff3b01bdcac86..c03e89d36eb72738ea14ed639f597bc1b5ecde6e 100644 (file)
@@ -641,7 +641,7 @@ static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_s
        bool err = false; \
        if (strict && (g cmp c)) { \
                err = true; \
-       } else if (gr cmp cr) { \
+       } else if ((g cmp c) && (gr cmp cr)) { \
                /* handle filesystem without high resolution timestamps */ \
                err = true; \
        } \
@@ -816,6 +816,7 @@ static bool test_delayed_write_update3(struct torture_context *tctx,
        }
 
        GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
 
        /* sure any further write doesn't update the write time */
        start = timeval_current();
@@ -970,6 +971,7 @@ static bool test_delayed_write_update4(struct torture_context *tctx,
        }
 
        GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
 
        /* sure any further write doesn't update the write time */
        start = timeval_current();
index 44e4c83e671bca20d07729335516fe1ac4ce2fd6..a5e6ab37c4cc187508030727df5e79a52f83e724 100755 (executable)
@@ -486,11 +486,11 @@ sn: ldap user2
                assert(res.msgs.length == 2);
        }
 
-       var res = ldb.search("(&(anr=testy ldap)(objectClass=user))");
-       if (res.error != 0 || res.msgs.length != 2) {
-               println("Found only " + res.msgs.length + " for (&(anr=\"testy ldap\")(objectClass=user))");
+       var res = ldb.search("(&(anr=\"testy ldap\")(objectClass=user))");
+       if (res.error != 0 || res.msgs.length != 0) {
+               println("Found " + res.msgs.length + " for (&(anr=\"testy ldap\")(objectClass=user))");
                assert(res.error == 0);
-               assert(res.msgs.length == 2);
+               assert(res.msgs.length == 0);
        }
 
 // Testing ldb.search for (&(anr=ldap)(objectClass=user))