summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/VERSION2
-rw-r--r--source4/cluster/ctdb/opendb_ctdb.c51
-rw-r--r--source4/heimdal/lib/gssapi/krb5/init_sec_context.c16
-rwxr-xr-xsource4/lib/ldb/tests/python/ldap.py196
-rw-r--r--source4/librpc/idl/opendb.idl2
-rw-r--r--source4/ntvfs/common/opendb.c24
-rw-r--r--source4/ntvfs/common/opendb.h9
-rw-r--r--source4/ntvfs/common/opendb_tdb.c51
-rw-r--r--source4/ntvfs/posix/pvfs_fileinfo.c31
-rw-r--r--source4/ntvfs/posix/pvfs_open.c80
-rw-r--r--source4/ntvfs/posix/pvfs_rename.c8
-rw-r--r--source4/ntvfs/posix/pvfs_resolve.c32
-rw-r--r--source4/ntvfs/posix/pvfs_search.c2
-rw-r--r--source4/ntvfs/posix/pvfs_seek.c2
-rw-r--r--source4/ntvfs/posix/pvfs_setfileinfo.c87
-rw-r--r--source4/ntvfs/posix/pvfs_unlink.c9
-rw-r--r--source4/ntvfs/posix/pvfs_write.c55
-rw-r--r--source4/ntvfs/posix/vfs_posix.c4
-rw-r--r--source4/ntvfs/posix/vfs_posix.h14
-rw-r--r--source4/samba4-knownfail1
-rw-r--r--source4/samba4-skip2
-rwxr-xr-xsource4/selftest/samba4_tests.sh6
-rw-r--r--source4/selftest/target/Samba4.pm3
-rw-r--r--source4/torture/basic/delaywrite.c4
24 files changed, 544 insertions, 147 deletions
diff --git a/source4/VERSION b/source4/VERSION
index d40eba4e8a..7a526c625e 100644
--- a/source4/VERSION
+++ b/source4/VERSION
@@ -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 #
diff --git a/source4/cluster/ctdb/opendb_ctdb.c b/source4/cluster/ctdb/opendb_ctdb.c
index ed09cf0bbc..b1faf9e0e6 100644
--- a/source4/cluster/ctdb/opendb_ctdb.c
+++ b/source4/cluster/ctdb/opendb_ctdb.c
@@ -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
diff --git a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c
index d4482a54b2..ab7624eef0 100644
--- a/source4/heimdal/lib/gssapi/krb5/init_sec_context.c
+++ b/source4/heimdal/lib/gssapi/krb5/init_sec_context.c
@@ -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)
diff --git a/source4/lib/ldb/tests/python/ldap.py b/source4/lib/ldb/tests/python/ldap.py
index c76222c207..aba9581ec5 100755
--- a/source4/lib/ldb/tests/python/ldap.py
+++ b/source4/lib/ldb/tests/python/ldap.py
@@ -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)
diff --git a/source4/librpc/idl/opendb.idl b/source4/librpc/idl/opendb.idl
index 72bf23a9b4..cdbaa6cb1b 100644
--- a/source4/librpc/idl/opendb.idl
+++ b/source4/librpc/idl/opendb.idl
@@ -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];
diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c
index 2913ea8431..6917bad52a 100644
--- a/source4/ntvfs/common/opendb.c
+++ b/source4/ntvfs/common/opendb.c
@@ -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,
diff --git a/source4/ntvfs/common/opendb.h b/source4/ntvfs/common/opendb.h
index 045476337a..179db111ca 100644
--- a/source4/ntvfs/common/opendb.h
+++ b/source4/ntvfs/common/opendb.h
@@ -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,
diff --git a/source4/ntvfs/common/opendb_tdb.c b/source4/ntvfs/common/opendb_tdb.c
index 99c0a95c20..d7531297ed 100644
--- a/source4/ntvfs/common/opendb_tdb.c
+++ b/source4/ntvfs/common/opendb_tdb.c
@@ -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
*/
@@ -785,20 +790,53 @@ static NTSTATUS odb_tdb_set_delete_on_close(struct odb_lock *lck, bool del_on_cl
}
/*
+ 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
diff --git a/source4/ntvfs/posix/pvfs_fileinfo.c b/source4/ntvfs/posix/pvfs_fileinfo.c
index 04f6ad78d0..a14c8f64ae 100644
--- a/source4/ntvfs/posix/pvfs_fileinfo.c
+++ b/source4/ntvfs/posix/pvfs_fileinfo.c
@@ -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;
}
diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c
index dada9f503f..43203086f8 100644
--- a/source4/ntvfs/posix/pvfs_open.c
+++ b/source4/ntvfs/posix/pvfs_open.c
@@ -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;
diff --git a/source4/ntvfs/posix/pvfs_rename.c b/source4/ntvfs/posix/pvfs_rename.c
index 5c2a627084..d8ea5896e5 100644
--- a/source4/ntvfs/posix/pvfs_rename.c
+++ b/source4/ntvfs/posix/pvfs_rename.c
@@ -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)) {
diff --git a/source4/ntvfs/posix/pvfs_resolve.c b/source4/ntvfs/posix/pvfs_resolve.c
index 2e97925c49..0f19788b97 100644
--- a/source4/ntvfs/posix/pvfs_resolve.c
+++ b/source4/ntvfs/posix/pvfs_resolve.c
@@ -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;
}
diff --git a/source4/ntvfs/posix/pvfs_search.c b/source4/ntvfs/posix/pvfs_search.c
index e47406dc09..e0fe4fb64d 100644
--- a/source4/ntvfs/posix/pvfs_search.c
+++ b/source4/ntvfs/posix/pvfs_search.c
@@ -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;
}
diff --git a/source4/ntvfs/posix/pvfs_seek.c b/source4/ntvfs/posix/pvfs_seek.c
index 3ea8b7cb6e..a3c4024ed7 100644
--- a/source4/ntvfs/posix/pvfs_seek.c
+++ b/source4/ntvfs/posix/pvfs_seek.c
@@ -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;
}
diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c
index 1dd2c075d9..2cde5f42aa 100644
--- a/source4/ntvfs/posix/pvfs_setfileinfo.c
+++ b/source4/ntvfs/posix/pvfs_setfileinfo.c
@@ -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;
}
}
diff --git a/source4/ntvfs/posix/pvfs_unlink.c b/source4/ntvfs/posix/pvfs_unlink.c
index 4cb47a4f1f..6a57041770 100644
--- a/source4/ntvfs/posix/pvfs_unlink.c
+++ b/source4/ntvfs/posix/pvfs_unlink.c
@@ -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;
}
diff --git a/source4/ntvfs/posix/pvfs_write.c b/source4/ntvfs/posix/pvfs_write.c
index 1f662f13fc..2da0e4bb3a 100644
--- a/source4/ntvfs/posix/pvfs_write.c
+++ b/source4/ntvfs/posix/pvfs_write.c
@@ -22,7 +22,60 @@
#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,
diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c
index 14b5210fd0..b5dd270346 100644
--- a/source4/ntvfs/posix/vfs_posix.c
+++ b/source4/ntvfs/posix/vfs_posix.c
@@ -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 =
diff --git a/source4/ntvfs/posix/vfs_posix.h b/source4/ntvfs/posix/vfs_posix.h
index c194698b64..cf39bcf0ac 100644
--- a/source4/ntvfs/posix/vfs_posix.h
+++ b/source4/ntvfs/posix/vfs_posix.h
@@ -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
diff --git a/source4/samba4-knownfail b/source4/samba4-knownfail
index 67d4a4f629..ded7922ec9 100644
--- a/source4/samba4-knownfail
+++ b/source4/samba4-knownfail
@@ -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
diff --git a/source4/samba4-skip b/source4/samba4-skip
index 7a6c54e9ec..bf25172c76 100644
--- a/source4/samba4-skip
+++ b/source4/samba4-skip
@@ -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
diff --git a/source4/selftest/samba4_tests.sh b/source4/selftest/samba4_tests.sh
index b73ba55586..1d550cbfe1 100755
--- a/source4/selftest/samba4_tests.sh
+++ b/source4/selftest/samba4_tests.sh
@@ -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`
diff --git a/source4/selftest/target/Samba4.pm b/source4/selftest/target/Samba4.pm
index 9f771ab8a3..bcee926481 100644
--- a/source4/selftest/target/Samba4.pm
+++ b/source4/selftest/target/Samba4.pm
@@ -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
diff --git a/source4/torture/basic/delaywrite.c b/source4/torture/basic/delaywrite.c
index ac4f565a2b..c03e89d36e 100644
--- a/source4/torture/basic/delaywrite.c
+++ b/source4/torture/basic/delaywrite.c
@@ -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();