[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Thu Mar 19 03:06:03 UTC 2020


The branch, master has been updated
       via  81c1a14e327 smbd: let delayed update handler also update on-disk timestamps
       via  53de2da7acf smbd: let mark_file_modified() always call trigger_write_time_update()
       via  60aecca9a72 torture/smb2: delayed timestamp updates test: more then one write
       via  58fa7b4fd7b torture/smb2: delayed timestamp update test: single write
       via  2c19d271130 smbd: remove stat call from mark_file_modified()
       via  6f7d1d8a37b torture/smb2: Windows 2019 15 ms timestamp resolution
       via  7b90fe69a86 smbd: flush pending writetime update when setting timestamps file
       via  d99d5bf2c6d smbd: flush pending writetime update when flushing file
       via  79d7d6b9d01 smbd: always flush pending write time update when setting filesize
       via  4e3c2afbd6f torture/smb2: add a test verifying a setinfo(basicinfo) flushes a pending writetime update
       via  c63d6c9e256 torture/smb2: add a test verifying a flush flushes a pending writetime update
       via  47508c5ecf0 torture/smb2: mtime update logic with 2 handles: write io on handle 1, then set mtime on handle 2
       via  73fedf014bb s4/torture: fix a timestamps test to work on ext filesystem
      from  86dd5a08096 smbd: enforce AIO requests draining

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 81c1a14e3271aeed7ed4fe6311171b19ba963555
Author: Ralph Boehme <slow at samba.org>
Date:   Sun Mar 15 08:30:21 2020 +0100

    smbd: let delayed update handler also update on-disk timestamps
    
    Let delayed update handler also update on-disk timestamps by calling
    trigger_write_time_update_immediate().
    
    trigger_write_time_update_immediate() sets fsp->update_write_time_on_close to
    false which prevents updating the write-time on close if there was ever only one
    write to the file.
    
    Besides resetting fsp->update_write_time_on_close and setting the on-disk timestamps
    trigger_write_time_update_immediate() takes the same steps as the removed code.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14320
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Thu Mar 19 03:05:40 UTC 2020 on sn-devel-184

commit 53de2da7acfc24513082190502d93306c12b7434
Author: Ralph Boehme <slow at samba.org>
Date:   Sun Mar 15 08:30:21 2020 +0100

    smbd: let mark_file_modified() always call trigger_write_time_update()
    
    Preperatory change: the next commit will reset fsp->update_write_time_on_close
    in the event handler, so this change ensures it gets set again for any
    subsequent write.
    
    This will NOT always result in a write-time update because
    trigger_write_time_update() has its own only-once logic using the internal
    variable fsp->update_write_time_triggered.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14320
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 60aecca9a727555847aa1412415c5bbd927df4ff
Author: Ralph Boehme <slow at samba.org>
Date:   Sun Mar 15 16:46:16 2020 +0100

    torture/smb2: delayed timestamp updates test: more then one write
    
    Verify a close updates the write-time for subsequent writes after an initial
    write started the delayed update logic.
    
    This covers a scenario that will become relevant with the two subsequent
    commits. The next commit:
    
      smbd: let mark_file_modified() always call trigger_write_time_update()
    
    ensures that trigger_write_time_update() is not only called for the first write
    on a file. Without that preaparatory change, the second commit:
    
      smbd: let delayed update handler also update on-disk timestamps
    
    alone would cause this test to fail.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14320
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 58fa7b4fd7b53d3100459a0c9c7ef4ca7481b58a
Author: Ralph Boehme <slow at samba.org>
Date:   Sat Mar 14 16:43:48 2020 +0100

    torture/smb2: delayed timestamp update test: single write
    
    Verify close only updates write-time when a delayed update is actually pending.
    
    This scenario is not covered by basic.delaywrite.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14320
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 2c19d27113036d607850f370bb9afd62856d671e
Author: Ralph Boehme <slow at samba.org>
Date:   Sun Mar 15 15:51:18 2020 +0100

    smbd: remove stat call from mark_file_modified()
    
    This stat dates back to d03453864ab1bc5fd3b4a3abaf96176a006c102b where the call
    to trigger_write_time_update() had been to the file IO codepath. It was present
    there for other reasons: to setup the write-cache based on the file's size.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14320
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 6f7d1d8a37bfb877b3f07423cbcffd15710e8d08
Author: Ralph Boehme <slow at samba.org>
Date:   Fri Mar 6 16:21:47 2020 +0100

    torture/smb2: Windows 2019 15 ms timestamp resolution
    
    This test demonstrates that Windows has a timestamp resolution of ~15ms.
    
    When a smaller amount of time than that has passed between modifying operations
    on a file, it's not necessarily detectable on a Windows 2019 server that
    implements immediate timestamp updates (no delayed magic).
    
    Note that this test relies on a low latency SMB connection. Even with a low
    latency connection of eg 1m there's a chance of 1/15 that the first part of the
    test expecting no timestamp change fails as the writetime is updated.
    
    Due to this timing dependency this test is skipped in Samba CI, but it is
    preserved here for future SMB2 timestamps behaviour archealogists.
    
    See also: https://lists.samba.org/archive/cifs-protocol/2019-December/003358.html
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 7b90fe69a865ae8648b6548eabbcf2fa8237ebd8
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Mar 12 19:23:40 2020 +0100

    smbd: flush pending writetime update when setting timestamps file
    
    Cf the explanations in the previous commits.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14150
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit d99d5bf2c6d0a818ef2f3920e0c93fac38761c36
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Mar 12 19:23:40 2020 +0100

    smbd: flush pending writetime update when flushing file
    
    Cf the explanations in the previous commit.
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14150
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 79d7d6b9d01b8547f16b74a62926d0b471f18c39
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Mar 12 16:52:34 2020 +0100

    smbd: always flush pending write time update when setting filesize
    
    We need to flush a pending write time update even when we're setting the
    filesize to current filesize.
    
    Note that we're already doing it this way in the relevant places listed my
    dochelp at MS in
    
    https://lists.samba.org/archive/cifs-protocol/2019-December/003364.html
    
      Cleanup (= Close)
      SetBasicInfo
      SetAllocationInfo
      SetEndOfFileInfo
      SetValidDataLengthInfo
      Flush
      FSCTL_SET_ENCRYPTION
      FSCTL_OFFLOAD_WRITE
    
    Cleanup (= Close):
    
      Already implemented by update_write_time_on_close() and friends.
    
    SetBasicInfo:
    
      Currently doesn't flush pending updates. Fixed by a subsequent commit.
    
    SetAllocationInfo:
    
      smb_set_file_allocation_info() when setting a file's allocation size.
    
    SetEndOfFileInfo:
    
      Currently doesn't flush pending updates. Fixed by a subsequent commit.
    
    SetValidDataLengthInfo:
    
      Not implemented, returns NT_STATUS_NOT_SUPPORTED which seems wrong btw, as
      SetValidDataLengthInfo IS listed in MS-SMB2 2.2.39.
    
    Flush:
    
      Currently doesn't flush pending updates. Fixed by subsequent commit.
    
    FSCTL_SET_ENCRYPTION:
    
      Windows 2016 doesn't flush a pending writetime update, verified with a
      smbtorture test.
    
    FSCTL_OFFLOAD_WRITE:
    
      NT_STATUS_NOT_IMPLEMENTED
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14150
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 4e3c2afbd6f12159252405f6efc6528fa9345f08
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Mar 12 16:48:09 2020 +0100

    torture/smb2: add a test verifying a setinfo(basicinfo) flushes a pending writetime update
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14150
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit c63d6c9e256cdf6a3620373ef0f595e61d43fa97
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Mar 12 16:48:09 2020 +0100

    torture/smb2: add a test verifying a flush flushes a pending writetime update
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14150
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 47508c5ecf0713ef404d5226499a4269651dc020
Author: Ralph Boehme <slow at samba.org>
Date:   Fri Mar 6 11:50:57 2020 +0100

    torture/smb2: mtime update logic with 2 handles: write io on handle 1, then set mtime on handle 2
    
    BUG: https://bugzilla.samba.org/show_bug.cgi?id=14150
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 73fedf014bbe02a408360d48e35bce4a6dbc9c36
Author: Ralph Boehme <slow at samba.org>
Date:   Tue Mar 10 18:26:49 2020 +0100

    s4/torture: fix a timestamps test to work on ext filesystem
    
    ext filesystem has a time_t limit of 15032385535 (0x0x37fffffff). From
    Documentation/filesystems/ext4/inodes.rst:
    
      If the inode structure size ``sb->s_inode_size`` is larger than 128 bytes and
      the ``i_inode_extra`` field is large enough to encompass the respective
      ``i_[cma]time_extra`` field, the ctime, atime, and mtime inode fields are
      widened to 64 bits. Within this “extra” 32-bit field, the lower two bits are
      used to extend the 32-bit seconds field to be 34 bit wide; the upper 30 bits
      are used to provide nanosecond timestamp accuracy. Therefore, timestamps
      should not overflow until May 2446. ...
    
    Changing the test to use the value 0x37fffffff instead of 100000000000 allows
    running the test locally on ext filesytems.
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 selftest/skip                     |   2 +
 source3/smbd/fileio.c             |  17 +-
 source3/smbd/reply.c              |  11 +
 source3/smbd/smb2_flush.c         |   7 +
 source3/smbd/trans2.c             |  32 +-
 source4/torture/smb2/smb2.c       |   1 +
 source4/torture/smb2/timestamps.c | 775 +++++++++++++++++++++++++++++++++++++-
 7 files changed, 820 insertions(+), 25 deletions(-)


Changeset truncated at 500 lines:

diff --git a/selftest/skip b/selftest/skip
index 11bf29599fa..549ba202021 100644
--- a/selftest/skip
+++ b/selftest/skip
@@ -75,6 +75,8 @@
 ^samba3.smb2.durable-open-disconnect    # Not a test, but a way to create a disconnected durable
 ^samba3.smb2.scan                       # No tests
 ^samba3.smb2.oplock.levelii501		# No test yet
+^samba3.smb2.timestamp_resolution       # See the comment on the test
+^samba4.smb2.timestamp_resolution
 ^samba3.rpc.samr.passwords.lockout\(ad_dc\) # No point running this version, it just waits 12 times longer the samba4 version of this test, covering the same code
 ^samba4.base.iometer
 ^samba4.base.casetable
diff --git a/source3/smbd/fileio.c b/source3/smbd/fileio.c
index 029965282f1..31d5b7510b7 100644
--- a/source3/smbd/fileio.c
+++ b/source3/smbd/fileio.c
@@ -104,15 +104,7 @@ void fsp_flush_write_time_update(struct files_struct *fsp)
 
 	DEBUG(5, ("Update write time on %s\n", fsp_str_dbg(fsp)));
 
-	/* change the write time in the open file db. */
-	(void)set_write_time(fsp->file_id, timespec_current());
-
-	/* And notify. */
-        notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED,
-                     FILE_NOTIFY_CHANGE_LAST_WRITE, fsp->fsp_name->base_name);
-
-	/* Remove the timed event handler. */
-	TALLOC_FREE(fsp->update_write_time_event);
+	trigger_write_time_update_immediate(fsp);
 }
 
 static void update_write_time_handler(struct tevent_context *ctx,
@@ -214,17 +206,14 @@ void mark_file_modified(files_struct *fsp)
 {
 	int dosmode;
 
+	trigger_write_time_update(fsp);
+
 	if (fsp->modified) {
 		return;
 	}
 
 	fsp->modified = true;
 
-	if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) != 0) {
-		return;
-	}
-	trigger_write_time_update(fsp);
-
 	if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
 		return;
 	}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index be7c170cd1f..5e2c2669310 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -5714,6 +5714,10 @@ static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
 	}
 	sync_file(conn, fsp, True /* write through */);
 
+	if (fsp->modified) {
+		trigger_write_time_update_immediate(fsp);
+	}
+
 	return NULL;
 }
 
@@ -5752,6 +5756,9 @@ void reply_flush(struct smb_request *req)
 			END_PROFILE(SMBflush);
 			return;
 		}
+		if (fsp->modified) {
+			trigger_write_time_update_immediate(fsp);
+		}
 	}
 
 	reply_outbuf(req, 0, 0);
@@ -9430,6 +9437,10 @@ void reply_setattrE(struct smb_request *req)
 		goto out;
 	}
 
+	if (fsp->modified) {
+		trigger_write_time_update_immediate(fsp);
+	}
+
 	DEBUG( 3, ( "reply_setattrE %s actime=%u modtime=%u "
 	       " createtime=%u\n",
 		fsp_fnum_dbg(fsp),
diff --git a/source3/smbd/smb2_flush.c b/source3/smbd/smb2_flush.c
index 86d5bbc58f0..08539e95807 100644
--- a/source3/smbd/smb2_flush.c
+++ b/source3/smbd/smb2_flush.c
@@ -112,6 +112,7 @@ static void smbd_smb2_request_flush_done(struct tevent_req *subreq)
 
 struct smbd_smb2_flush_state {
 	struct smbd_smb2_request *smb2req;
+	struct files_struct *fsp;
 };
 
 static void smbd_smb2_flush_done(struct tevent_req *subreq);
@@ -132,6 +133,7 @@ static struct tevent_req *smbd_smb2_flush_send(TALLOC_CTX *mem_ctx,
 		return NULL;
 	}
 	state->smb2req = smb2req;
+	state->fsp = fsp;
 
 	DEBUG(10,("smbd_smb2_flush: %s - %s\n",
 		  fsp_str_dbg(fsp), fsp_fnum_dbg(fsp)));
@@ -207,6 +209,8 @@ static void smbd_smb2_flush_done(struct tevent_req *subreq)
 {
 	struct tevent_req *req = tevent_req_callback_data(
 		subreq, struct tevent_req);
+	struct smbd_smb2_flush_state *state = tevent_req_data(
+		req, struct smbd_smb2_flush_state);
 	int ret;
 	struct vfs_aio_state vfs_aio_state;
 
@@ -216,6 +220,9 @@ static void smbd_smb2_flush_done(struct tevent_req *subreq)
 		tevent_req_nterror(req, map_nt_error_from_unix(vfs_aio_state.error));
 		return;
 	}
+	if (state->fsp->modified) {
+		trigger_write_time_update_immediate(state->fsp);
+	}
 	tevent_req_done(req);
 }
 
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index a7a4d32b2c3..5b7333773bb 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -6687,6 +6687,13 @@ static NTSTATUS smb_set_file_size(connection_struct *conn,
 		 get_file_size_stat(psbuf));
 
 	if (size == get_file_size_stat(psbuf)) {
+		if (fsp == NULL) {
+			return NT_STATUS_OK;
+		}
+		if (!fsp->modified) {
+			return NT_STATUS_OK;
+		}
+		trigger_write_time_update_immediate(fsp);
 		return NT_STATUS_OK;
 	}
 
@@ -7829,8 +7836,15 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
 	DEBUG(10, ("smb_set_file_basic_info: file %s\n",
 		   smb_fname_str_dbg(smb_fname)));
 
-	return smb_set_file_time(conn, fsp, smb_fname, &ft,
-				 true);
+	status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	if (fsp != NULL && fsp->modified) {
+		trigger_write_time_update_immediate(fsp);
+	}
+	return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -7867,11 +7881,15 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn,
 		return status;
 	}
 
-        return smb_set_file_time(conn,
-                                fsp,
-				smb_fname,
-				&ft,
-                                true);
+	status = smb_set_file_time(conn, fsp, smb_fname, &ft, true);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	if (fsp != NULL && fsp->modified) {
+		trigger_write_time_update_immediate(fsp);
+	}
+	return NT_STATUS_OK;
 }
 
 /****************************************************************************
diff --git a/source4/torture/smb2/smb2.c b/source4/torture/smb2/smb2.c
index b9a6607e2bf..c860d03102e 100644
--- a/source4/torture/smb2/smb2.c
+++ b/source4/torture/smb2/smb2.c
@@ -198,6 +198,7 @@ NTSTATUS torture_smb2_init(TALLOC_CTX *ctx)
 	torture_suite_add_suite(suite, torture_smb2_multichannel_init(suite));
 	torture_suite_add_suite(suite, torture_smb2_samba3misc_init(suite));
 	torture_suite_add_suite(suite, torture_smb2_timestamps_init(suite));
+	torture_suite_add_suite(suite, torture_smb2_timestamp_resolution_init(suite));
 	torture_suite_add_1smb2_test(suite, "openattr", torture_smb2_openattrtest);
 	torture_suite_add_1smb2_test(suite, "winattr", torture_smb2_winattrtest);
 	torture_suite_add_suite(suite, torture_smb2_readwrite_init(suite));
diff --git a/source4/torture/smb2/timestamps.c b/source4/torture/smb2/timestamps.c
index 9655e5bc164..89b64886e4d 100644
--- a/source4/torture/smb2/timestamps.c
+++ b/source4/torture/smb2/timestamps.c
@@ -27,6 +27,7 @@
 #include "torture/smb2/proto.h"
 
 #define BASEDIR "smb2-timestamps"
+#define FNAME "testfile.dat"
 
 static bool test_time_t(struct torture_context *tctx,
 			struct smb2_tree *tree,
@@ -235,11 +236,11 @@ done:
 	return ret;
 }
 
-static bool test_time_t_100000000000(struct torture_context *tctx,
+static bool test_time_t_15032385535(struct torture_context *tctx,
 				    struct smb2_tree *tree)
 {
-	return test_time_t(tctx, tree, "test_time_t_100000000000.txt",
-			   100000000000 /* >> INT32_MAX */);
+	return test_time_t(tctx, tree, "test_time_t_15032385535.txt",
+			   15032385535 /* >> INT32_MAX, limit on ext */);
 }
 
 static bool test_time_t_10000000000(struct torture_context *tctx,
@@ -287,6 +288,618 @@ static bool test_time_t_1968(struct torture_context *tctx,
 			   -63158400 /* 1968 */);
 }
 
+static bool test_delayed_write_vs_seteof(struct torture_context *tctx,
+					 struct smb2_tree *tree)
+{
+	struct smb2_create cr;
+	struct smb2_handle h1 = {{0}};
+	struct smb2_handle h2 = {{0}};
+	NTTIME create_time;
+	NTTIME set_time;
+	union smb_fileinfo finfo;
+	union smb_setfileinfo setinfo;
+	struct smb2_close c;
+	NTSTATUS status;
+	bool ret = true;
+
+	smb2_deltree(tree, BASEDIR);
+	status = torture_smb2_testdir(tree, BASEDIR, &h1);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"create failed\n");
+	status = smb2_util_close(tree, h1);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"close failed\n");
+
+	torture_comment(tctx, "Open file-handle 1\n");
+
+	cr = (struct smb2_create) {
+		.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED,
+		.in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+		.in.share_access       = NTCREATEX_SHARE_ACCESS_MASK,
+		.in.fname              = BASEDIR "\\" FNAME,
+	};
+	status = smb2_create(tree, tctx, &cr);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"create failed\n");
+	h1 = cr.out.file.handle;
+	create_time = cr.out.create_time;
+	sleep(1);
+
+	torture_comment(tctx, "Write to file-handle 1\n");
+
+	status = smb2_util_write(tree, h1, "s", 0, 1);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"write failed\n");
+
+	torture_comment(tctx, "Check writetime hasn't been updated\n");
+
+	finfo = (union smb_fileinfo) {
+		.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+		.generic.in.file.handle = h1,
+	};
+	status = smb2_getinfo_file(tree, tree, &finfo);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"getinfo failed\n");
+
+	torture_assert_nttime_equal(tctx,
+				    finfo.all_info.out.write_time,
+				    create_time,
+				    "Writetime != set_time (wrong!)\n");
+
+	torture_comment(tctx, "Setinfo EOF on file-handle 1,"
+			" should flush pending writetime update\n");
+
+	setinfo = (union smb_setfileinfo) {
+		.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION,
+	};
+	setinfo.end_of_file_info.in.file.handle = h1;
+	setinfo.end_of_file_info.in.size = 1; /* same size! */
+
+	status = smb2_setinfo_file(tree, &setinfo);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"close failed\n");
+
+	torture_comment(tctx, "Check writetime has been updated "
+			"by the setinfo EOF\n");
+
+	finfo = (union smb_fileinfo) {
+		.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+		.generic.in.file.handle = h1,
+	};
+	status = smb2_getinfo_file(tree, tree, &finfo);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"getinfo failed\n");
+	if (!(finfo.all_info.out.write_time > create_time)) {
+		ret = false;
+		torture_fail_goto(tctx, done, "setinfo EOF hasn't updated writetime\n");
+	}
+
+	torture_comment(tctx, "Open file-handle 2\n");
+
+	cr = (struct smb2_create) {
+		.in.desired_access     = SEC_FILE_WRITE_ATTRIBUTE,
+		.in.create_disposition = NTCREATEX_DISP_OPEN,
+		.in.share_access       = NTCREATEX_SHARE_ACCESS_MASK,
+		.in.fname              = BASEDIR "\\" FNAME,
+	};
+	status = smb2_create(tree, tctx, &cr);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"create failed\n");
+	h2 = cr.out.file.handle;
+
+	torture_comment(tctx, "Set write time on file-handle 2\n");
+
+	setinfo = (union smb_setfileinfo) {
+		.generic.level = RAW_FILEINFO_BASIC_INFORMATION,
+	};
+	setinfo.generic.in.file.handle = h2;
+	unix_to_nt_time(&set_time, time(NULL) + 86400);
+	setinfo.basic_info.in.write_time = set_time;
+
+	status = smb2_setinfo_file(tree, &setinfo);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"close failed\n");
+
+	status = smb2_util_close(tree, h2);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"close failed\n");
+	ZERO_STRUCT(h2);
+
+	torture_comment(tctx, "Close file-handle 1, write-time should not be updated\n");
+
+	c = (struct smb2_close) {
+		.in.file.handle = h1,
+		.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
+	};
+
+	status = smb2_close(tree, &c);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"close failed\n");
+	ZERO_STRUCT(h1);
+
+	torture_assert_nttime_equal(tctx,
+				    c.out.write_time,
+				    set_time,
+				    "Writetime != set_time (wrong!)\n");
+
+done:
+	if (!smb2_util_handle_empty(h1)) {
+		smb2_util_close(tree, h1);
+	}
+	if (!smb2_util_handle_empty(h2)) {
+		smb2_util_close(tree, h2);
+	}
+	smb2_deltree(tree, BASEDIR);
+	return ret;
+}
+
+static bool test_delayed_write_vs_flush(struct torture_context *tctx,
+					struct smb2_tree *tree)
+{
+	struct smb2_create cr;
+	struct smb2_handle h1 = {{0}};
+	union smb_fileinfo finfo;
+	struct smb2_flush f;
+	struct smb2_close c;
+	NTTIME create_time;
+	NTTIME flush_time;
+	NTSTATUS status;
+	bool ret = true;
+
+	smb2_deltree(tree, BASEDIR);
+	status = torture_smb2_testdir(tree, BASEDIR, &h1);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"create failed\n");
+	status = smb2_util_close(tree, h1);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"close failed\n");
+
+	torture_comment(tctx, "Open file-handle 1\n");
+
+	cr = (struct smb2_create) {
+		.in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED,
+		.in.create_disposition = NTCREATEX_DISP_OPEN_IF,
+		.in.share_access       = NTCREATEX_SHARE_ACCESS_MASK,
+		.in.fname              = BASEDIR "\\" FNAME,
+	};
+	status = smb2_create(tree, tctx, &cr);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"create failed\n");
+	h1 = cr.out.file.handle;
+	create_time = cr.out.create_time;
+	sleep(1);
+
+	torture_comment(tctx, "Write to file-handle 1\n");
+
+	status = smb2_util_write(tree, h1, "s", 0, 1);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"write failed\n");
+
+	torture_comment(tctx, "Check writetime hasn't been updated\n");
+
+	finfo = (union smb_fileinfo) {
+		.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+		.generic.in.file.handle = h1,
+	};
+	status = smb2_getinfo_file(tree, tree, &finfo);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"getinfo failed\n");
+
+	torture_assert_nttime_equal(tctx,
+				    finfo.all_info.out.write_time,
+				    create_time,
+				    "Writetime != create_time (wrong!)\n");
+
+	torture_comment(tctx, "Flush file, "
+			"should flush pending writetime update\n");
+
+	f = (struct smb2_flush) {
+		.in.file.handle = h1,
+	};
+
+	status = smb2_flush(tree, &f);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"flush failed\n");
+
+	torture_comment(tctx, "Check writetime has been updated "
+			"by the setinfo EOF\n");
+
+	finfo = (union smb_fileinfo) {
+		.generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
+		.generic.in.file.handle = h1,
+	};
+	status = smb2_getinfo_file(tree, tree, &finfo);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"getinfo failed\n");
+
+	flush_time = finfo.all_info.out.write_time;
+	if (!(flush_time > create_time)) {
+		ret = false;
+		torture_fail_goto(tctx, done, "flush hasn't updated writetime\n");
+	}
+
+	torture_comment(tctx, "Close file-handle 1, write-time should not be updated\n");
+
+	c = (struct smb2_close) {
+		.in.file.handle = h1,
+		.in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
+	};
+
+	status = smb2_close(tree, &c);
+	torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+					"close failed\n");
+	ZERO_STRUCT(h1);
+
+	torture_assert_nttime_equal(tctx,
+				    c.out.write_time,
+				    flush_time,
+				    "writetime != flushtime (wrong!)\n");
+
+done:
+	if (!smb2_util_handle_empty(h1)) {
+		smb2_util_close(tree, h1);
+	}
+	smb2_deltree(tree, BASEDIR);
+	return ret;
+}
+
+static bool test_delayed_write_vs_setbasic_do(struct torture_context *tctx,
+					      struct smb2_tree *tree,
+					      union smb_setfileinfo *setinfo,
+					      bool expect_update)
+{
+	char *path = NULL;
+	struct smb2_create cr;
+	struct smb2_handle h1 = {{0}};
+	NTTIME create_time;
+	union smb_fileinfo finfo;
+	NTSTATUS status;
+	bool ret = true;
+
+	torture_comment(tctx, "Create testfile\n");
+
+	path = talloc_asprintf(tree, BASEDIR "\\" FNAME ".%" PRIu32,


-- 
Samba Shared Repository



More information about the samba-cvs mailing list