[PATCH] file change time
Jeremy Allison
jra at samba.org
Sat Sep 26 05:14:08 UTC 2015
On Fri, Sep 25, 2015 at 07:12:22PM -0700, slow at samba.org wrote:
> Hi,
>
> just came across this one. Looks like we don't handle ctime properly,
> patch with test attached.
>
> The test passes with Windows but fails with Samba without the fix.
Looks completely correct to me ! Mod times can be tricky though,
so I hope it passes a full make test :-).
Did you check if the ntvfs server passes this test or do you
have to mark it skip ?
If so, mark it 'Reviewed-by: Jeremy Allison <jra at samba.org>
Cheers,
Jeremy.
> From 506464ca114d9fdcd5f2c35f73e51b40a2a18e2d Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Sat, 26 Sep 2015 01:59:05 +0200
> Subject: [PATCH 1/2] smbd: dosmode: fix change time
>
> According to [MS-FSSA] 2.1.1.3 the last changed time for a file is
> defined as
>
> LastChangeTime: The time that identifies when the file metadata or
> contents were last changed ...
>
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
> source3/smbd/dosmode.c | 7 ++++++-
> 1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
> index 72acd4e..bf6fbd4 100644
> --- a/source3/smbd/dosmode.c
> +++ b/source3/smbd/dosmode.c
> @@ -1098,7 +1098,12 @@ struct timespec get_change_timespec(connection_struct *conn,
> struct files_struct *fsp,
> const struct smb_filename *smb_fname)
> {
> - return smb_fname->st.st_ex_mtime;
> + if (timespec_compare(&smb_fname->st.st_ex_mtime,
> + &smb_fname->st.st_ex_ctime) > 0)
> + {
> + return smb_fname->st.st_ex_mtime;
> + }
> + return smb_fname->st.st_ex_ctime;
> }
>
> /****************************************************************************
> --
> 2.1.0
>
>
> From 9bd1dcc6193eae70575d926bd1623bf2399c7eb6 Mon Sep 17 00:00:00 2001
> From: Ralph Boehme <slow at samba.org>
> Date: Sat, 26 Sep 2015 03:01:35 +0200
> Subject: [PATCH 2/2] s4:torture: smb2 rename ctime test
>
> According to [MS-FSSA] 2.1.1.3 the last changed time for a file is
> defined as
>
> LastChangeTime: The time that identifies when the file metadata or
> contents were last changed ...
>
> Signed-off-by: Ralph Boehme <slow at samba.org>
> ---
> source4/torture/smb2/rename.c | 130 ++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 130 insertions(+)
>
> diff --git a/source4/torture/smb2/rename.c b/source4/torture/smb2/rename.c
> index 23fe4f9..8599802 100755
> --- a/source4/torture/smb2/rename.c
> +++ b/source4/torture/smb2/rename.c
> @@ -20,6 +20,7 @@
> */
>
> #include "includes.h"
> +#include <unistd.h>
> #include "libcli/smb2/smb2.h"
> #include "libcli/smb2/smb2_calls.h"
> #include "lib/tevent/tevent.h"
> @@ -1392,6 +1393,131 @@ static bool torture_smb2_rename_dir_bench(struct torture_context *tctx,
> }
>
>
> +static bool torture_smb2_rename_ctime(struct torture_context *torture,
> + struct smb2_tree *tree1)
> +{
> + bool ret = true;
> + NTSTATUS status;
> + union smb_open io;
> + union smb_close cl;
> + union smb_setfileinfo sinfo;
> + union smb_fileinfo fi;
> + struct smb2_handle h1;
> + NTTIME ctime1, ctime2;
> +
> + smb2_deltree(tree1, BASEDIR);
> + smb2_util_rmdir(tree1, BASEDIR);
> +
> + torture_comment(torture, "Creating base directory\n");
> +
> + smb2_util_mkdir(tree1, BASEDIR);
> +
> + torture_comment(torture, "Creating test file\n");
> +
> + ZERO_STRUCT(io.smb2);
> + io.generic.level = RAW_OPEN_SMB2;
> + io.smb2.in.create_flags = 0;
> + io.smb2.in.desired_access = SEC_FILE_ALL|SEC_STD_DELETE;
> + io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
> + io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
> + io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
> + NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
> + io.smb2.in.alloc_size = 0;
> + io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE;
> + io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
> + io.smb2.in.security_flags = 0;
> + io.smb2.in.fname = BASEDIR "\\file.txt";
> +
> + status = smb2_create(tree1, torture, &(io.smb2));
> + torture_assert_ntstatus_ok_goto(torture, status, ret, done,
> + "smb2_create failed\n");
> + h1 = io.smb2.out.file.handle;
> +
> + ZERO_STRUCT(fi);
> + fi.generic.level = RAW_FILEINFO_NETWORK_OPEN_INFORMATION;
> + fi.generic.in.file.handle = h1;
> + status = smb2_getinfo_file(tree1, torture, &fi);
> + torture_assert_ntstatus_ok_goto(torture, status, ret, done,
> + "smb2_getinfo failed\n");
> +
> + ctime1 = fi.network_open_information.out.change_time;
> + torture_comment(torture, "ctime: %jd\n",
> + (uintmax_t)nt_time_to_unix(ctime1));
> +
> + sleep(1);
> +
> + torture_comment(torture, "Renaming test file\n");
> +
> + ZERO_STRUCT(sinfo);
> + sinfo.rename_information.level = RAW_SFILEINFO_RENAME_INFORMATION;
> + sinfo.rename_information.in.file.handle = io.smb2.out.file.handle;
> + sinfo.rename_information.in.overwrite = 0;
> + sinfo.rename_information.in.root_fid = 0;
> + sinfo.rename_information.in.new_name =
> + BASEDIR "\\newname.txt";
> + status = smb2_setinfo_file(tree1, &sinfo);
> + torture_assert_ntstatus_ok_goto(torture, status, ret, done,
> + "smb2_setinfo failed\n");
> +
> + ZERO_STRUCT(cl.smb2);
> + cl.smb2.level = RAW_CLOSE_SMB2;
> + cl.smb2.in.file.handle = h1;
> + status = smb2_close(tree1, &(cl.smb2));
> + torture_assert_ntstatus_ok_goto(torture, status, ret, done,
> + "smb2_close failed\n");
> +
> + torture_comment(torture, "Checking for new filename\n");
> +
> + sleep(2);
> +
> + ZERO_STRUCT(io.smb2);
> + io.generic.level = RAW_OPEN_SMB2;
> + io.smb2.in.create_flags = 0;
> + io.smb2.in.desired_access = SEC_FILE_ALL|SEC_STD_DELETE;
> + io.smb2.in.create_options = NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
> + io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
> + io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ |
> + NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE;
> + io.smb2.in.alloc_size = 0;
> + io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN;
> + io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
> + io.smb2.in.security_flags = 0;
> + io.smb2.in.fname = BASEDIR "\\newname.txt";
> +
> + status = smb2_create(tree1, torture, &(io.smb2));
> + torture_assert_ntstatus_ok_goto(torture, status, ret, done,
> + "smb2_create failed\n");
> + h1 = io.smb2.out.file.handle;
> +
> + ZERO_STRUCT(fi);
> + fi.generic.level = RAW_FILEINFO_NETWORK_OPEN_INFORMATION;
> + fi.generic.in.file.handle = h1;
> + status = smb2_getinfo_file(tree1, torture, &fi);
> + torture_assert_ntstatus_ok_goto(torture, status, ret, done,
> + "smb2_getinfo failed\n");
> +
> + ctime2 = fi.network_open_information.out.change_time;
> + torture_comment(torture, "ctime: %jd\n",
> + (uintmax_t)nt_time_to_unix(ctime2));
> + torture_assert_goto(torture, ctime2 > ctime1, ret, done,
> + "rename didn't update ctime");
> +
> + torture_comment(torture, "Closing test file\n");
> +
> + ZERO_STRUCT(cl.smb2);
> + cl.smb2.level = RAW_CLOSE_SMB2;
> + cl.smb2.in.file.handle = h1;
> + status = smb2_close(tree1, &(cl.smb2));
> + torture_assert_ntstatus_ok_goto(torture, status, ret, done,
> + "smb2_close failed\n");
> +
> + ZERO_STRUCT(h1);
> +
> +done:
> + smb2_deltree(tree1, BASEDIR);
> + return ret;
> +}
> +
> /*
> basic testing of SMB2 rename
> */
> @@ -1437,6 +1563,10 @@ struct torture_suite *torture_smb2_rename_init(void)
> "rename_dir_bench",
> torture_smb2_rename_dir_bench);
>
> + torture_suite_add_1smb2_test(suite,
> + "rename_ctime",
> + torture_smb2_rename_ctime);
> +
> suite->description = talloc_strdup(suite, "smb2.rename tests");
>
> return suite;
> --
> 2.1.0
>
More information about the samba-technical
mailing list