LCOV - code coverage report
Current view: top level - source4/torture/smb2 - timestamps.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 24 525 4.6 %
Date: 2024-06-13 04:01:37 Functions: 2 20 10.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    test timestamps
       5             : 
       6             :    Copyright (C) Ralph Boehme 2019
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "libcli/smb2/smb2.h"
      24             : #include "libcli/smb2/smb2_calls.h"
      25             : #include "torture/torture.h"
      26             : #include "torture/util.h"
      27             : #include "torture/smb2/proto.h"
      28             : 
      29             : #define BASEDIR "smb2-timestamps"
      30             : #define FNAME "testfile.dat"
      31             : 
      32           0 : static bool test_close_no_attrib(struct torture_context *tctx,
      33             :                                  struct smb2_tree *tree)
      34             : {
      35           0 :         const char *filename = BASEDIR "/" FNAME;
      36             :         struct smb2_create cr;
      37           0 :         struct smb2_handle handle = {{0}};
      38           0 :         struct smb2_handle testdirh = {{0}};
      39             :         struct smb2_close c;
      40             :         NTSTATUS status;
      41           0 :         bool ret = true;
      42             : 
      43           0 :         smb2_deltree(tree, BASEDIR);
      44             : 
      45           0 :         status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
      46           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
      47             :                                         "torture_smb2_testdir failed\n");
      48           0 :         smb2_util_close(tree, testdirh);
      49             : 
      50           0 :         cr = (struct smb2_create) {
      51             :                 .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
      52             :                 .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
      53             :                 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
      54             :                 .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
      55             :                 .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
      56             :                 .in.fname = filename,
      57             :         };
      58             : 
      59           0 :         status = smb2_create(tree, tctx, &cr);
      60           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
      61             :                                         "smb2_create failed\n");
      62           0 :         handle = cr.out.file.handle;
      63             : 
      64           0 :         c = (struct smb2_close) {
      65             :                 .in.file.handle = handle,
      66             :         };
      67             : 
      68           0 :         status = smb2_close(tree, &c);
      69           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
      70             :                                         "close failed\n");
      71           0 :         ZERO_STRUCT(handle);
      72             : 
      73           0 :         torture_assert_u64_equal_goto(tctx, c.out.create_time, NTTIME_OMIT,
      74             :                                       ret, done, "Unexpected create time\n");
      75           0 :         torture_assert_u64_equal_goto(tctx, c.out.access_time, NTTIME_OMIT,
      76             :                                       ret, done, "Unexpected access time\n");
      77           0 :         torture_assert_u64_equal_goto(tctx, c.out.write_time, NTTIME_OMIT,
      78             :                                       ret, done, "Unexpected write time\n");
      79           0 :         torture_assert_u64_equal_goto(tctx, c.out.change_time, NTTIME_OMIT,
      80             :                                       ret, done, "Unexpected change time\n");
      81           0 :         torture_assert_u64_equal_goto(tctx, c.out.alloc_size, 0,
      82             :                                       ret, done, "Unexpected allocation size\n");
      83           0 :         torture_assert_u64_equal_goto(tctx, c.out.size, 0,
      84             :                                       ret, done, "Unexpected size\n");
      85           0 :         torture_assert_u64_equal_goto(tctx, c.out.file_attr, 0,
      86             :                                       ret, done, "Unexpected attributes\n");
      87             : 
      88           0 : done:
      89           0 :         if (!smb2_util_handle_empty(handle)) {
      90           0 :                 smb2_util_close(tree, handle);
      91             :         }
      92           0 :         smb2_deltree(tree, BASEDIR);
      93           0 :         return ret;
      94             : }
      95             : 
      96           0 : static bool test_time_t(struct torture_context *tctx,
      97             :                         struct smb2_tree *tree,
      98             :                         const char *fname,
      99             :                         time_t t)
     100             : {
     101           0 :         char *filename = NULL;
     102             :         struct smb2_create cr;
     103           0 :         struct smb2_handle handle = {{0}};
     104           0 :         struct smb2_handle testdirh = {{0}};
     105           0 :         struct timespec ts = { .tv_sec = t };
     106             :         uint64_t nttime;
     107             :         union smb_fileinfo gi;
     108             :         union smb_setfileinfo si;
     109             :         struct smb2_find find;
     110             :         unsigned int count;
     111             :         union smb_search_data *d;
     112             :         NTSTATUS status;
     113           0 :         bool ret = true;
     114             : 
     115           0 :         smb2_deltree(tree, BASEDIR);
     116             : 
     117           0 :         status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
     118           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     119             :                                         "torture_smb2_testdir failed\n");
     120             : 
     121           0 :         filename = talloc_asprintf(tctx, "%s\\%s", BASEDIR, fname);
     122           0 :         torture_assert_not_null_goto(tctx, filename, ret, done,
     123             :                                      "talloc_asprintf failed\n");
     124             : 
     125           0 :         cr = (struct smb2_create) {
     126             :                 .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
     127             :                 .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
     128             :                 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
     129             :                 .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
     130             :                 .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
     131             :                 .in.fname = filename,
     132             :         };
     133             : 
     134           0 :         status = smb2_create(tree, tctx, &cr);
     135           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     136             :                                         "smb2_create failed\n");
     137           0 :         handle = cr.out.file.handle;
     138             : 
     139           0 :         si = (union smb_setfileinfo) {
     140             :                 .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
     141             :                 .basic_info.in.file.handle = handle,
     142             :         };
     143             : 
     144           0 :         nttime = full_timespec_to_nt_time(&ts);
     145           0 :         si.basic_info.in.create_time = nttime;
     146           0 :         si.basic_info.in.write_time = nttime;
     147           0 :         si.basic_info.in.change_time = nttime;
     148             : 
     149           0 :         status = smb2_setinfo_file(tree, &si);
     150           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     151             :                                         "smb2_setinfo_file failed\n");
     152             : 
     153           0 :         gi = (union smb_fileinfo) {
     154             :                 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
     155             :                 .generic.in.file.handle = handle,
     156             :         };
     157             : 
     158           0 :         status = smb2_getinfo_file(tree, tctx, &gi);
     159           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     160             :                                         "smb2_getinfo_file failed\n");
     161             : 
     162           0 :         torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
     163             :                         nt_time_string(tctx, gi.basic_info.out.create_time),
     164             :                         nt_time_string(tctx, gi.basic_info.out.write_time),
     165             :                         nt_time_string(tctx, gi.basic_info.out.change_time));
     166             : 
     167           0 :         torture_assert_u64_equal_goto(tctx,
     168             :                                       nttime,
     169             :                                       gi.basic_info.out.create_time,
     170             :                                       ret, done,
     171             :                                       "Wrong create time\n");
     172           0 :         torture_assert_u64_equal_goto(tctx,
     173             :                                       nttime,
     174             :                                       gi.basic_info.out.write_time,
     175             :                                       ret, done,
     176             :                                       "Wrong write time\n");
     177           0 :         torture_assert_u64_equal_goto(tctx,
     178             :                                       nttime,
     179             :                                       gi.basic_info.out.change_time,
     180             :                                       ret, done,
     181             :                                       "Wrong change time\n");
     182             : 
     183           0 :         find = (struct smb2_find) {
     184             :                 .in.file.handle = testdirh,
     185             :                 .in.pattern = fname,
     186             :                 .in.max_response_size = 0x1000,
     187             :                 .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
     188             :         };
     189             : 
     190           0 :         status = smb2_find_level(tree, tree, &find, &count, &d);
     191           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     192             :                                         "smb2_find_level failed\n");
     193             : 
     194           0 :         torture_assert_u64_equal_goto(tctx,
     195             :                                       nttime,
     196             :                                       d[0].id_both_directory_info.create_time,
     197             :                                       ret, done,
     198             :                                       "Wrong create time\n");
     199           0 :         torture_assert_u64_equal_goto(tctx,
     200             :                                       nttime,
     201             :                                       d[0].id_both_directory_info.write_time,
     202             :                                       ret, done,
     203             :                                       "Wrong write time\n");
     204           0 :         torture_assert_u64_equal_goto(tctx,
     205             :                                       nttime,
     206             :                                       d[0].id_both_directory_info.change_time,
     207             :                                       ret, done,
     208             :                                       "Wrong change time\n");
     209             : 
     210           0 :         status = smb2_util_close(tree, handle);
     211           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     212             :                                         "smb2_util_close failed\n");
     213           0 :         ZERO_STRUCT(handle);
     214             : 
     215           0 :         cr = (struct smb2_create) {
     216             :                 .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
     217             :                 .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
     218             :                 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
     219             :                 .in.create_disposition = NTCREATEX_DISP_OPEN,
     220             :                 .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
     221             :                 .in.fname = filename,
     222             :         };
     223             : 
     224           0 :         status = smb2_create(tree, tctx, &cr);
     225           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     226             :                                         "smb2_create failed\n");
     227           0 :         handle = cr.out.file.handle;
     228             : 
     229           0 :         gi = (union smb_fileinfo) {
     230             :                 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
     231             :                 .generic.in.file.handle = handle,
     232             :         };
     233             : 
     234           0 :         status = smb2_getinfo_file(tree, tctx, &gi);
     235           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     236             :                                         "smb2_getinfo_file failed\n");
     237             : 
     238           0 :         torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
     239             :                         nt_time_string(tctx, gi.basic_info.out.create_time),
     240             :                         nt_time_string(tctx, gi.basic_info.out.write_time),
     241             :                         nt_time_string(tctx, gi.basic_info.out.change_time));
     242             : 
     243           0 :         torture_assert_u64_equal_goto(tctx,
     244             :                                       nttime,
     245             :                                       gi.basic_info.out.create_time,
     246             :                                       ret, done,
     247             :                                       "Wrong create time\n");
     248           0 :         torture_assert_u64_equal_goto(tctx,
     249             :                                       nttime,
     250             :                                       gi.basic_info.out.write_time,
     251             :                                       ret, done,
     252             :                                       "Wrong write time\n");
     253           0 :         torture_assert_u64_equal_goto(tctx,
     254             :                                       nttime,
     255             :                                       gi.basic_info.out.change_time,
     256             :                                       ret, done,
     257             :                                       "Wrong change time\n");
     258             : 
     259           0 :         find = (struct smb2_find) {
     260             :                 .in.continue_flags = SMB2_CONTINUE_FLAG_RESTART,
     261             :                 .in.file.handle = testdirh,
     262             :                 .in.pattern = fname,
     263             :                 .in.max_response_size = 0x1000,
     264             :                 .in.level = SMB2_FIND_ID_BOTH_DIRECTORY_INFO,
     265             :         };
     266             : 
     267           0 :         status = smb2_find_level(tree, tree, &find, &count, &d);
     268           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     269             :                                         "smb2_find_level failed\n");
     270             : 
     271           0 :         torture_assert_u64_equal_goto(tctx,
     272             :                                       nttime,
     273             :                                       d[0].id_both_directory_info.create_time,
     274             :                                       ret, done,
     275             :                                       "Wrong create time\n");
     276           0 :         torture_assert_u64_equal_goto(tctx,
     277             :                                       nttime,
     278             :                                       d[0].id_both_directory_info.write_time,
     279             :                                       ret, done,
     280             :                                       "Wrong write time\n");
     281           0 :         torture_assert_u64_equal_goto(tctx,
     282             :                                       nttime,
     283             :                                       d[0].id_both_directory_info.change_time,
     284             :                                       ret, done,
     285             :                                       "Wrong change time\n");
     286             : 
     287           0 :         status = smb2_util_close(tree, handle);
     288           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     289             :                                         "smb2_util_close failed\n");
     290           0 :         ZERO_STRUCT(handle);
     291             : 
     292           0 : done:
     293           0 :         if (!smb2_util_handle_empty(handle)) {
     294           0 :                 smb2_util_close(tree, handle);
     295             :         }
     296           0 :         if (!smb2_util_handle_empty(testdirh)) {
     297           0 :                 smb2_util_close(tree, testdirh);
     298             :         }
     299           0 :         smb2_deltree(tree, BASEDIR);
     300           0 :         return ret;
     301             : }
     302             : 
     303           0 : static bool test_time_t_15032385535(struct torture_context *tctx,
     304             :                                     struct smb2_tree *tree)
     305             : {
     306           0 :         return test_time_t(tctx, tree, "test_time_t_15032385535.txt",
     307             :                            15032385535 /* >> INT32_MAX, limit on ext */);
     308             : }
     309             : 
     310           0 : static bool test_time_t_10000000000(struct torture_context *tctx,
     311             :                                     struct smb2_tree *tree)
     312             : {
     313           0 :         return test_time_t(tctx, tree, "test_time_t_10000000000.txt",
     314             :                            10000000000 /* >> INT32_MAX */);
     315             : }
     316             : 
     317           0 : static bool test_time_t_4294967295(struct torture_context *tctx,
     318             :                                    struct smb2_tree *tree)
     319             : {
     320           0 :         return test_time_t(tctx, tree, "test_time_t_4294967295.txt",
     321             :                            4294967295 /* INT32_MAX */);
     322             : }
     323             : 
     324           0 : static bool test_time_t_1(struct torture_context *tctx,
     325             :                           struct smb2_tree *tree)
     326             : {
     327           0 :         return test_time_t(tctx, tree, "test_time_t_1.txt", 1);
     328             : }
     329             : 
     330           0 : static bool test_time_t_0(struct torture_context *tctx,
     331             :                           struct smb2_tree *tree)
     332             : {
     333           0 :         return test_time_t(tctx, tree, "test_time_t_0.txt", 0);
     334             : }
     335             : 
     336           0 : static bool test_time_t_minus_1(struct torture_context *tctx,
     337             :                                 struct smb2_tree *tree)
     338             : {
     339           0 :         return test_time_t(tctx, tree, "test_time_t_-1.txt", -1);
     340             : }
     341             : 
     342           0 : static bool test_time_t_minus_2(struct torture_context *tctx,
     343             :                                 struct smb2_tree *tree)
     344             : {
     345           0 :         return test_time_t(tctx, tree, "test_time_t_-2.txt", -2);
     346             : }
     347             : 
     348           0 : static bool test_time_t_1968(struct torture_context *tctx,
     349             :                              struct smb2_tree *tree)
     350             : {
     351           0 :         return test_time_t(tctx, tree, "test_time_t_1968.txt",
     352             :                            -63158400 /* 1968 */);
     353             : }
     354             : 
     355           0 : static bool test_freeze_thaw(struct torture_context *tctx,
     356             :                              struct smb2_tree *tree)
     357             : {
     358           0 :         const char *filename = BASEDIR "\\test_freeze_thaw";
     359             :         struct smb2_create cr;
     360           0 :         struct smb2_handle handle = {{0}};
     361           0 :         struct smb2_handle testdirh = {{0}};
     362           0 :         struct timespec ts = { .tv_sec = time(NULL) };
     363             :         uint64_t nttime;
     364             :         union smb_fileinfo gi;
     365             :         union smb_setfileinfo si;
     366             :         NTSTATUS status;
     367           0 :         bool ret = true;
     368             : 
     369           0 :         smb2_deltree(tree, BASEDIR);
     370             : 
     371           0 :         status = torture_smb2_testdir(tree, BASEDIR, &testdirh);
     372           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     373             :                                         "torture_smb2_testdir failed\n");
     374             : 
     375           0 :         cr = (struct smb2_create) {
     376             :                 .in.desired_access = SEC_FLAG_MAXIMUM_ALLOWED,
     377             :                 .in.file_attributes = FILE_ATTRIBUTE_NORMAL,
     378             :                 .in.share_access = NTCREATEX_SHARE_ACCESS_MASK,
     379             :                 .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
     380             :                 .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS,
     381             :                 .in.fname = filename,
     382             :         };
     383             : 
     384           0 :         status = smb2_create(tree, tctx, &cr);
     385           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     386             :                                         "smb2_create failed\n");
     387           0 :         handle = cr.out.file.handle;
     388             : 
     389           0 :         si = (union smb_setfileinfo) {
     390             :                 .basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION,
     391             :                 .basic_info.in.file.handle = handle,
     392             :         };
     393             : 
     394             :         /*
     395             :          * Step 1:
     396             :          * First set timestamps of testfile to current time
     397             :          */
     398             : 
     399           0 :         nttime = full_timespec_to_nt_time(&ts);
     400           0 :         si.basic_info.in.create_time = nttime;
     401           0 :         si.basic_info.in.write_time = nttime;
     402           0 :         si.basic_info.in.change_time = nttime;
     403             : 
     404           0 :         status = smb2_setinfo_file(tree, &si);
     405           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     406             :                                         "smb2_setinfo_file failed\n");
     407             : 
     408           0 :         gi = (union smb_fileinfo) {
     409             :                 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
     410             :                 .generic.in.file.handle = handle,
     411             :         };
     412             : 
     413             :         /*
     414             :          * Step 2:
     415             :          * Verify timestamps are indeed set to the value in "nttime".
     416             :          */
     417             : 
     418           0 :         status = smb2_getinfo_file(tree, tctx, &gi);
     419           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     420             :                                         "smb2_getinfo_file failed\n");
     421             : 
     422           0 :         torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
     423             :                         nt_time_string(tctx, gi.basic_info.out.create_time),
     424             :                         nt_time_string(tctx, gi.basic_info.out.write_time),
     425             :                         nt_time_string(tctx, gi.basic_info.out.change_time));
     426             : 
     427           0 :         torture_assert_u64_equal_goto(tctx,
     428             :                                       nttime,
     429             :                                       gi.basic_info.out.create_time,
     430             :                                       ret, done,
     431             :                                       "Wrong create time\n");
     432           0 :         torture_assert_u64_equal_goto(tctx,
     433             :                                       nttime,
     434             :                                       gi.basic_info.out.write_time,
     435             :                                       ret, done,
     436             :                                       "Wrong write time\n");
     437           0 :         torture_assert_u64_equal_goto(tctx,
     438             :                                       nttime,
     439             :                                       gi.basic_info.out.change_time,
     440             :                                       ret, done,
     441             :                                       "Wrong change time\n");
     442             : 
     443             :         /*
     444             :          * Step 3:
     445             :          * First set timestamps with NTTIME_FREEZE, must not change any
     446             :          * timestamp value.
     447             :          */
     448             : 
     449           0 :         si.basic_info.in.create_time = NTTIME_FREEZE;
     450           0 :         si.basic_info.in.write_time = NTTIME_FREEZE;
     451           0 :         si.basic_info.in.change_time = NTTIME_FREEZE;
     452             : 
     453           0 :         status = smb2_setinfo_file(tree, &si);
     454           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     455             :                                         "smb2_setinfo_file failed\n");
     456             : 
     457           0 :         gi = (union smb_fileinfo) {
     458             :                 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
     459             :                 .generic.in.file.handle = handle,
     460             :         };
     461             : 
     462             :         /*
     463             :          * Step 4:
     464             :          * Verify timestamps are unmodified from step 2.
     465             :          */
     466             : 
     467           0 :         gi = (union smb_fileinfo) {
     468             :                 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
     469             :                 .generic.in.file.handle = handle,
     470             :         };
     471             : 
     472           0 :         status = smb2_getinfo_file(tree, tctx, &gi);
     473           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     474             :                                         "smb2_getinfo_file failed\n");
     475             : 
     476           0 :         torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
     477             :                         nt_time_string(tctx, gi.basic_info.out.create_time),
     478             :                         nt_time_string(tctx, gi.basic_info.out.write_time),
     479             :                         nt_time_string(tctx, gi.basic_info.out.change_time));
     480             : 
     481           0 :         torture_assert_u64_equal_goto(tctx,
     482             :                                       nttime,
     483             :                                       gi.basic_info.out.create_time,
     484             :                                       ret, done,
     485             :                                       "Wrong create time\n");
     486           0 :         torture_assert_u64_equal_goto(tctx,
     487             :                                       nttime,
     488             :                                       gi.basic_info.out.write_time,
     489             :                                       ret, done,
     490             :                                       "Wrong write time\n");
     491           0 :         torture_assert_u64_equal_goto(tctx,
     492             :                                       nttime,
     493             :                                       gi.basic_info.out.change_time,
     494             :                                       ret, done,
     495             :                                       "Wrong change time\n");
     496             : 
     497             :         /*
     498             :          * Step 5:
     499             :          * First set timestamps with NTTIME_THAW, must not change any timestamp
     500             :          * value.
     501             :          */
     502             : 
     503           0 :         si.basic_info.in.create_time = NTTIME_THAW;
     504           0 :         si.basic_info.in.write_time = NTTIME_THAW;
     505           0 :         si.basic_info.in.change_time = NTTIME_THAW;
     506             : 
     507           0 :         status = smb2_setinfo_file(tree, &si);
     508           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     509             :                                         "smb2_setinfo_file failed\n");
     510             : 
     511           0 :         gi = (union smb_fileinfo) {
     512             :                 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
     513             :                 .generic.in.file.handle = handle,
     514             :         };
     515             : 
     516             :         /*
     517             :          * Step 6:
     518             :          * Verify timestamps are unmodified from step 2.
     519             :          */
     520             : 
     521           0 :         gi = (union smb_fileinfo) {
     522             :                 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
     523             :                 .generic.in.file.handle = handle,
     524             :         };
     525             : 
     526           0 :         status = smb2_getinfo_file(tree, tctx, &gi);
     527           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     528             :                                         "smb2_getinfo_file failed\n");
     529             : 
     530           0 :         torture_comment(tctx, "Got: create: %s, write: %s, change: %s\n",
     531             :                         nt_time_string(tctx, gi.basic_info.out.create_time),
     532             :                         nt_time_string(tctx, gi.basic_info.out.write_time),
     533             :                         nt_time_string(tctx, gi.basic_info.out.change_time));
     534             : 
     535           0 :         torture_assert_u64_equal_goto(tctx,
     536             :                                       nttime,
     537             :                                       gi.basic_info.out.create_time,
     538             :                                       ret, done,
     539             :                                       "Wrong create time\n");
     540           0 :         torture_assert_u64_equal_goto(tctx,
     541             :                                       nttime,
     542             :                                       gi.basic_info.out.write_time,
     543             :                                       ret, done,
     544             :                                       "Wrong write time\n");
     545           0 :         torture_assert_u64_equal_goto(tctx,
     546             :                                       nttime,
     547             :                                       gi.basic_info.out.change_time,
     548             :                                       ret, done,
     549             :                                       "Wrong change time\n");
     550             : 
     551           0 : done:
     552           0 :         if (!smb2_util_handle_empty(handle)) {
     553           0 :                 smb2_util_close(tree, handle);
     554             :         }
     555           0 :         if (!smb2_util_handle_empty(testdirh)) {
     556           0 :                 smb2_util_close(tree, testdirh);
     557             :         }
     558           0 :         smb2_deltree(tree, BASEDIR);
     559           0 :         return ret;
     560             : }
     561             : 
     562           0 : static bool test_delayed_write_vs_seteof(struct torture_context *tctx,
     563             :                                          struct smb2_tree *tree)
     564             : {
     565             :         struct smb2_create cr;
     566           0 :         struct smb2_handle h1 = {{0}};
     567           0 :         struct smb2_handle h2 = {{0}};
     568             :         NTTIME create_time;
     569             :         NTTIME set_time;
     570             :         union smb_fileinfo finfo;
     571             :         union smb_setfileinfo setinfo;
     572             :         struct smb2_close c;
     573             :         NTSTATUS status;
     574           0 :         bool ret = true;
     575             : 
     576           0 :         smb2_deltree(tree, BASEDIR);
     577           0 :         status = torture_smb2_testdir(tree, BASEDIR, &h1);
     578           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     579             :                                         "create failed\n");
     580           0 :         status = smb2_util_close(tree, h1);
     581           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     582             :                                         "close failed\n");
     583             : 
     584           0 :         torture_comment(tctx, "Open file-handle 1\n");
     585             : 
     586           0 :         cr = (struct smb2_create) {
     587             :                 .in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED,
     588             :                 .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
     589             :                 .in.share_access       = NTCREATEX_SHARE_ACCESS_MASK,
     590             :                 .in.fname              = BASEDIR "\\" FNAME,
     591             :         };
     592           0 :         status = smb2_create(tree, tctx, &cr);
     593           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     594             :                                         "create failed\n");
     595           0 :         h1 = cr.out.file.handle;
     596           0 :         create_time = cr.out.create_time;
     597           0 :         sleep(1);
     598             : 
     599           0 :         torture_comment(tctx, "Write to file-handle 1\n");
     600             : 
     601           0 :         status = smb2_util_write(tree, h1, "s", 0, 1);
     602           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     603             :                                         "write failed\n");
     604             : 
     605           0 :         torture_comment(tctx, "Check writetime hasn't been updated\n");
     606             : 
     607           0 :         finfo = (union smb_fileinfo) {
     608             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
     609             :                 .generic.in.file.handle = h1,
     610             :         };
     611           0 :         status = smb2_getinfo_file(tree, tree, &finfo);
     612           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     613             :                                         "getinfo failed\n");
     614             : 
     615           0 :         torture_assert_nttime_equal(tctx,
     616             :                                     finfo.all_info.out.write_time,
     617             :                                     create_time,
     618             :                                     "Writetime != set_time (wrong!)\n");
     619             : 
     620           0 :         torture_comment(tctx, "Setinfo EOF on file-handle 1,"
     621             :                         " should flush pending writetime update\n");
     622             : 
     623           0 :         setinfo = (union smb_setfileinfo) {
     624             :                 .generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION,
     625             :         };
     626           0 :         setinfo.end_of_file_info.in.file.handle = h1;
     627           0 :         setinfo.end_of_file_info.in.size = 1; /* same size! */
     628             : 
     629           0 :         status = smb2_setinfo_file(tree, &setinfo);
     630           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     631             :                                         "close failed\n");
     632             : 
     633           0 :         torture_comment(tctx, "Check writetime has been updated "
     634             :                         "by the setinfo EOF\n");
     635             : 
     636           0 :         finfo = (union smb_fileinfo) {
     637             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
     638             :                 .generic.in.file.handle = h1,
     639             :         };
     640           0 :         status = smb2_getinfo_file(tree, tree, &finfo);
     641           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     642             :                                         "getinfo failed\n");
     643           0 :         if (!(finfo.all_info.out.write_time > create_time)) {
     644           0 :                 ret = false;
     645           0 :                 torture_fail_goto(tctx, done, "setinfo EOF hasn't updated writetime\n");
     646             :         }
     647             : 
     648           0 :         torture_comment(tctx, "Open file-handle 2\n");
     649             : 
     650           0 :         cr = (struct smb2_create) {
     651             :                 .in.desired_access     = SEC_FILE_WRITE_ATTRIBUTE,
     652             :                 .in.create_disposition = NTCREATEX_DISP_OPEN,
     653             :                 .in.share_access       = NTCREATEX_SHARE_ACCESS_MASK,
     654             :                 .in.fname              = BASEDIR "\\" FNAME,
     655             :         };
     656           0 :         status = smb2_create(tree, tctx, &cr);
     657           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     658             :                                         "create failed\n");
     659           0 :         h2 = cr.out.file.handle;
     660             : 
     661           0 :         torture_comment(tctx, "Set write time on file-handle 2\n");
     662             : 
     663           0 :         setinfo = (union smb_setfileinfo) {
     664             :                 .generic.level = SMB_QFILEINFO_BASIC_INFORMATION,
     665             :         };
     666           0 :         setinfo.generic.in.file.handle = h2;
     667           0 :         unix_to_nt_time(&set_time, time(NULL) + 86400);
     668           0 :         setinfo.basic_info.in.write_time = set_time;
     669             : 
     670           0 :         status = smb2_setinfo_file(tree, &setinfo);
     671           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     672             :                                         "close failed\n");
     673             : 
     674           0 :         status = smb2_util_close(tree, h2);
     675           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     676             :                                         "close failed\n");
     677           0 :         ZERO_STRUCT(h2);
     678             : 
     679           0 :         torture_comment(tctx, "Close file-handle 1, write-time should not be updated\n");
     680             : 
     681           0 :         c = (struct smb2_close) {
     682             :                 .in.file.handle = h1,
     683             :                 .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
     684             :         };
     685             : 
     686           0 :         status = smb2_close(tree, &c);
     687           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     688             :                                         "close failed\n");
     689           0 :         ZERO_STRUCT(h1);
     690             : 
     691           0 :         torture_assert_nttime_equal(tctx,
     692             :                                     c.out.write_time,
     693             :                                     set_time,
     694             :                                     "Writetime != set_time (wrong!)\n");
     695             : 
     696           0 : done:
     697           0 :         if (!smb2_util_handle_empty(h1)) {
     698           0 :                 smb2_util_close(tree, h1);
     699             :         }
     700           0 :         if (!smb2_util_handle_empty(h2)) {
     701           0 :                 smb2_util_close(tree, h2);
     702             :         }
     703           0 :         smb2_deltree(tree, BASEDIR);
     704           0 :         return ret;
     705             : }
     706             : 
     707           0 : static bool test_delayed_write_vs_flush(struct torture_context *tctx,
     708             :                                         struct smb2_tree *tree)
     709             : {
     710             :         struct smb2_create cr;
     711           0 :         struct smb2_handle h1 = {{0}};
     712             :         union smb_fileinfo finfo;
     713             :         struct smb2_flush f;
     714             :         struct smb2_close c;
     715             :         NTTIME create_time;
     716             :         NTTIME flush_time;
     717             :         NTSTATUS status;
     718           0 :         bool ret = true;
     719             : 
     720           0 :         smb2_deltree(tree, BASEDIR);
     721           0 :         status = torture_smb2_testdir(tree, BASEDIR, &h1);
     722           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     723             :                                         "create failed\n");
     724           0 :         status = smb2_util_close(tree, h1);
     725           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     726             :                                         "close failed\n");
     727             : 
     728           0 :         torture_comment(tctx, "Open file-handle 1\n");
     729             : 
     730           0 :         cr = (struct smb2_create) {
     731             :                 .in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED,
     732             :                 .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
     733             :                 .in.share_access       = NTCREATEX_SHARE_ACCESS_MASK,
     734             :                 .in.fname              = BASEDIR "\\" FNAME,
     735             :         };
     736           0 :         status = smb2_create(tree, tctx, &cr);
     737           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     738             :                                         "create failed\n");
     739           0 :         h1 = cr.out.file.handle;
     740           0 :         create_time = cr.out.create_time;
     741           0 :         sleep(1);
     742             : 
     743           0 :         torture_comment(tctx, "Write to file-handle 1\n");
     744             : 
     745           0 :         status = smb2_util_write(tree, h1, "s", 0, 1);
     746           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     747             :                                         "write failed\n");
     748             : 
     749           0 :         torture_comment(tctx, "Check writetime hasn't been updated\n");
     750             : 
     751           0 :         finfo = (union smb_fileinfo) {
     752             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
     753             :                 .generic.in.file.handle = h1,
     754             :         };
     755           0 :         status = smb2_getinfo_file(tree, tree, &finfo);
     756           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     757             :                                         "getinfo failed\n");
     758             : 
     759           0 :         torture_assert_nttime_equal(tctx,
     760             :                                     finfo.all_info.out.write_time,
     761             :                                     create_time,
     762             :                                     "Writetime != create_time (wrong!)\n");
     763             : 
     764           0 :         torture_comment(tctx, "Flush file, "
     765             :                         "should flush pending writetime update\n");
     766             : 
     767           0 :         f = (struct smb2_flush) {
     768             :                 .in.file.handle = h1,
     769             :         };
     770             : 
     771           0 :         status = smb2_flush(tree, &f);
     772           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     773             :                                         "flush failed\n");
     774             : 
     775           0 :         torture_comment(tctx, "Check writetime has been updated "
     776             :                         "by the setinfo EOF\n");
     777             : 
     778           0 :         finfo = (union smb_fileinfo) {
     779             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
     780             :                 .generic.in.file.handle = h1,
     781             :         };
     782           0 :         status = smb2_getinfo_file(tree, tree, &finfo);
     783           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     784             :                                         "getinfo failed\n");
     785             : 
     786           0 :         flush_time = finfo.all_info.out.write_time;
     787           0 :         if (!(flush_time > create_time)) {
     788           0 :                 ret = false;
     789           0 :                 torture_fail_goto(tctx, done, "flush hasn't updated writetime\n");
     790             :         }
     791             : 
     792           0 :         torture_comment(tctx, "Close file-handle 1, write-time should not be updated\n");
     793             : 
     794           0 :         c = (struct smb2_close) {
     795             :                 .in.file.handle = h1,
     796             :                 .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
     797             :         };
     798             : 
     799           0 :         status = smb2_close(tree, &c);
     800           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     801             :                                         "close failed\n");
     802           0 :         ZERO_STRUCT(h1);
     803             : 
     804           0 :         torture_assert_nttime_equal(tctx,
     805             :                                     c.out.write_time,
     806             :                                     flush_time,
     807             :                                     "writetime != flushtime (wrong!)\n");
     808             : 
     809           0 : done:
     810           0 :         if (!smb2_util_handle_empty(h1)) {
     811           0 :                 smb2_util_close(tree, h1);
     812             :         }
     813           0 :         smb2_deltree(tree, BASEDIR);
     814           0 :         return ret;
     815             : }
     816             : 
     817           0 : static bool test_delayed_write_vs_setbasic_do(struct torture_context *tctx,
     818             :                                               struct smb2_tree *tree,
     819             :                                               union smb_setfileinfo *setinfo,
     820             :                                               bool expect_update)
     821             : {
     822           0 :         char *path = NULL;
     823             :         struct smb2_create cr;
     824           0 :         struct smb2_handle h1 = {{0}};
     825             :         NTTIME create_time;
     826             :         union smb_fileinfo finfo;
     827             :         NTSTATUS status;
     828           0 :         bool ret = true;
     829             : 
     830           0 :         torture_comment(tctx, "Create testfile\n");
     831             : 
     832           0 :         path = talloc_asprintf(tree, BASEDIR "\\" FNAME ".%" PRIu32,
     833             :                                generate_random());
     834           0 :         torture_assert_not_null_goto(tctx, path, ret, done, "OOM\n");
     835             : 
     836           0 :         cr = (struct smb2_create) {
     837             :                 .in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED,
     838             :                 .in.create_disposition = NTCREATEX_DISP_CREATE,
     839             :                 .in.share_access       = NTCREATEX_SHARE_ACCESS_MASK,
     840             :                 .in.fname              = path,
     841             :         };
     842           0 :         status = smb2_create(tree, tctx, &cr);
     843           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     844             :                                         "create failed\n");
     845           0 :         h1 = cr.out.file.handle;
     846           0 :         create_time = cr.out.create_time;
     847             : 
     848           0 :         torture_comment(tctx, "Write to file\n");
     849             : 
     850           0 :         status = smb2_util_write(tree, h1, "s", 0, 1);
     851           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     852             :                                         "write failed\n");
     853             : 
     854           0 :         torture_comment(tctx, "Get timestamps\n");
     855             : 
     856           0 :         finfo = (union smb_fileinfo) {
     857             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
     858             :                 .generic.in.file.handle = h1,
     859             :         };
     860           0 :         status = smb2_getinfo_file(tree, tree, &finfo);
     861           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     862             :                                         "getinfo failed\n");
     863             : 
     864           0 :         torture_assert_nttime_equal(tctx,
     865             :                                     finfo.all_info.out.write_time,
     866             :                                     create_time,
     867             :                                     "Writetime != create_time (wrong!)\n");
     868             : 
     869           0 :         torture_comment(tctx, "Set timestamps\n");
     870             : 
     871           0 :         setinfo->end_of_file_info.in.file.handle = h1;
     872           0 :         status = smb2_setinfo_file(tree, setinfo);
     873           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     874             :                                         "close failed\n");
     875             : 
     876           0 :         torture_comment(tctx, "Check timestamps\n");
     877             : 
     878           0 :         finfo = (union smb_fileinfo) {
     879             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
     880             :                 .generic.in.file.handle = h1,
     881             :         };
     882           0 :         status = smb2_getinfo_file(tree, tree, &finfo);
     883           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     884             :                                         "getinfo failed\n");
     885             : 
     886           0 :         if (expect_update) {
     887           0 :                 if (!(finfo.all_info.out.write_time > create_time)) {
     888           0 :                         ret = false;
     889           0 :                         torture_fail_goto(tctx, done, "setinfo basicinfo "
     890             :                                           "hasn't updated writetime\n");
     891             :                 }
     892             :         } else {
     893           0 :                 if (finfo.all_info.out.write_time != create_time) {
     894           0 :                         ret = false;
     895           0 :                         torture_fail_goto(tctx, done, "setinfo basicinfo "
     896             :                                           "hasn't updated writetime\n");
     897             :                 }
     898             :         }
     899             : 
     900           0 :         status = smb2_util_close(tree, h1);
     901           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     902             :                                         "close failed\n");
     903           0 :         ZERO_STRUCT(h1);
     904             : 
     905           0 :         status = smb2_util_unlink(tree, path);
     906           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     907             :                                         "close failed\n");
     908             : 
     909           0 : done:
     910           0 :         TALLOC_FREE(path);
     911           0 :         if (!smb2_util_handle_empty(h1)) {
     912           0 :                 smb2_util_close(tree, h1);
     913             :         }
     914           0 :         return ret;
     915             : }
     916             : 
     917           0 : static bool test_delayed_write_vs_setbasic(struct torture_context *tctx,
     918             :                                            struct smb2_tree *tree)
     919             : {
     920           0 :         struct smb2_handle h1 = {{0}};
     921             :         union smb_setfileinfo setinfo;
     922           0 :         time_t t = time(NULL) - 86400;
     923             :         NTSTATUS status;
     924           0 :         bool ret = true;
     925             : 
     926           0 :         smb2_deltree(tree, BASEDIR);
     927           0 :         status = torture_smb2_testdir(tree, BASEDIR, &h1);
     928           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     929             :                                         "create failed\n");
     930           0 :         status = smb2_util_close(tree, h1);
     931           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     932             :                                         "close failed\n");
     933             : 
     934             :         /*
     935             :          * Yes, this is correct, tested against Windows 2016: even if all
     936             :          * timestamp fields are 0, a pending write time is flushed.
     937             :          */
     938           0 :         torture_comment(tctx, "Test: setting all-0 timestamps flushes?\n");
     939             : 
     940           0 :         setinfo = (union smb_setfileinfo) {
     941             :                 .generic.level = RAW_SFILEINFO_BASIC_INFORMATION,
     942             :         };
     943           0 :         ret = test_delayed_write_vs_setbasic_do(tctx, tree, &setinfo, true);
     944           0 :         if (ret != true) {
     945           0 :                 goto done;
     946             :         }
     947             : 
     948           0 :         torture_comment(tctx, "Test: setting create_time flushes?\n");
     949           0 :         unix_to_nt_time(&setinfo.basic_info.in.create_time, t);
     950           0 :         ret = test_delayed_write_vs_setbasic_do(tctx, tree, &setinfo, true);
     951           0 :         if (ret != true) {
     952           0 :                 goto done;
     953             :         }
     954             : 
     955           0 :         torture_comment(tctx, "Test: setting access_time flushes?\n");
     956           0 :         unix_to_nt_time(&setinfo.basic_info.in.access_time, t);
     957           0 :         ret = test_delayed_write_vs_setbasic_do(tctx, tree, &setinfo, true);
     958           0 :         if (ret != true) {
     959           0 :                 goto done;
     960             :         }
     961             : 
     962           0 :         torture_comment(tctx, "Test: setting change_time flushes?\n");
     963           0 :         unix_to_nt_time(&setinfo.basic_info.in.change_time, t);
     964           0 :         ret = test_delayed_write_vs_setbasic_do(tctx, tree, &setinfo, true);
     965           0 :         if (ret != true) {
     966           0 :                 goto done;
     967             :         }
     968             : 
     969           0 : done:
     970           0 :         smb2_deltree(tree, BASEDIR);
     971           0 :         return ret;
     972             : }
     973             : 
     974           0 : static bool test_delayed_1write(struct torture_context *tctx,
     975             :                                 struct smb2_tree *tree)
     976             : {
     977             :         struct smb2_create cr;
     978           0 :         struct smb2_handle h1 = {{0}};
     979             :         union smb_fileinfo finfo;
     980             :         struct smb2_close c;
     981             :         NTTIME create_time;
     982             :         NTTIME write_time;
     983             :         NTTIME close_time;
     984             :         NTSTATUS status;
     985           0 :         bool ret = true;
     986             : 
     987           0 :         smb2_deltree(tree, BASEDIR);
     988           0 :         status = torture_smb2_testdir(tree, BASEDIR, &h1);
     989           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     990             :                                         "create failed\n");
     991           0 :         status = smb2_util_close(tree, h1);
     992           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     993             :                                         "close failed\n");
     994             : 
     995           0 :         torture_comment(tctx, "Open file-handle 1\n");
     996             : 
     997           0 :         cr = (struct smb2_create) {
     998             :                 .in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED,
     999             :                 .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
    1000             :                 .in.share_access       = NTCREATEX_SHARE_ACCESS_MASK,
    1001             :                 .in.fname              = BASEDIR "\\" FNAME,
    1002             :         };
    1003           0 :         status = smb2_create(tree, tctx, &cr);
    1004           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1005             :                                         "create failed\n");
    1006           0 :         h1 = cr.out.file.handle;
    1007           0 :         create_time = cr.out.create_time;
    1008           0 :         sleep(1);
    1009             : 
    1010           0 :         torture_comment(tctx, "Write to file-handle 1\n");
    1011             : 
    1012           0 :         status = smb2_util_write(tree, h1, "s", 0, 1);
    1013           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1014             :                                         "write failed\n");
    1015           0 :         sleep(3);
    1016             : 
    1017           0 :         torture_comment(tctx, "Check writetime has been updated\n");
    1018             : 
    1019           0 :         finfo = (union smb_fileinfo) {
    1020             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
    1021             :                 .generic.in.file.handle = h1,
    1022             :         };
    1023           0 :         status = smb2_getinfo_file(tree, tree, &finfo);
    1024           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1025             :                                         "getinfo failed\n");
    1026           0 :         write_time = finfo.all_info.out.write_time;
    1027             : 
    1028           0 :         if (!(write_time > create_time)) {
    1029           0 :                 ret = false;
    1030           0 :                 torture_fail_goto(tctx, done,
    1031             :                                   "Write-time not updated (wrong!)\n");
    1032             :         }
    1033             : 
    1034           0 :         torture_comment(tctx, "Close file-handle 1\n");
    1035           0 :         sleep(1);
    1036             : 
    1037           0 :         c = (struct smb2_close) {
    1038             :                 .in.file.handle = h1,
    1039             :                 .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
    1040             :         };
    1041             : 
    1042           0 :         status = smb2_close(tree, &c);
    1043           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1044             :                                         "close failed\n");
    1045           0 :         ZERO_STRUCT(h1);
    1046           0 :         close_time = c.out.write_time;
    1047             : 
    1048           0 :         torture_assert_nttime_equal(tctx, close_time, write_time,
    1049             :                                     "Writetime != close_time (wrong!)\n");
    1050             : 
    1051           0 : done:
    1052           0 :         if (!smb2_util_handle_empty(h1)) {
    1053           0 :                 smb2_util_close(tree, h1);
    1054             :         }
    1055           0 :         smb2_deltree(tree, BASEDIR);
    1056           0 :         return ret;
    1057             : }
    1058             : 
    1059           0 : static bool test_delayed_2write(struct torture_context *tctx,
    1060             :                                 struct smb2_tree *tree)
    1061             : {
    1062             :         struct smb2_create cr;
    1063           0 :         struct smb2_handle h1 = {{0}};
    1064             :         union smb_fileinfo finfo;
    1065             :         struct smb2_close c;
    1066             :         NTTIME create_time;
    1067             :         NTTIME write_time;
    1068             :         NTTIME write_time2;
    1069             :         struct timespec now;
    1070             :         NTTIME send_close_time;
    1071             :         NTTIME close_time;
    1072             :         NTSTATUS status;
    1073           0 :         bool ret = true;
    1074             : 
    1075           0 :         smb2_deltree(tree, BASEDIR);
    1076           0 :         status = torture_smb2_testdir(tree, BASEDIR, &h1);
    1077           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1078             :                                         "create failed\n");
    1079           0 :         status = smb2_util_close(tree, h1);
    1080           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1081             :                                         "close failed\n");
    1082             : 
    1083           0 :         torture_comment(tctx, "Open file\n");
    1084             : 
    1085           0 :         cr = (struct smb2_create) {
    1086             :                 .in.desired_access     = SEC_FLAG_MAXIMUM_ALLOWED,
    1087             :                 .in.create_disposition = NTCREATEX_DISP_OPEN_IF,
    1088             :                 .in.share_access       = NTCREATEX_SHARE_ACCESS_MASK,
    1089             :                 .in.fname              = BASEDIR "\\" FNAME,
    1090             :         };
    1091           0 :         status = smb2_create(tree, tctx, &cr);
    1092           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1093             :                                         "create failed\n");
    1094           0 :         h1 = cr.out.file.handle;
    1095           0 :         create_time = cr.out.create_time;
    1096           0 :         sleep(1);
    1097             : 
    1098           0 :         torture_comment(tctx, "Write to file\n");
    1099             : 
    1100           0 :         status = smb2_util_write(tree, h1, "s", 0, 1);
    1101           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1102             :                                         "write failed\n");
    1103           0 :         sleep(3);
    1104             : 
    1105           0 :         torture_comment(tctx, "Check writetime has been updated\n");
    1106             : 
    1107           0 :         finfo = (union smb_fileinfo) {
    1108             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
    1109             :                 .generic.in.file.handle = h1,
    1110             :         };
    1111           0 :         status = smb2_getinfo_file(tree, tree, &finfo);
    1112           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1113             :                                         "getinfo failed\n");
    1114           0 :         write_time = finfo.all_info.out.write_time;
    1115             : 
    1116           0 :         if (!(write_time > create_time)) {
    1117           0 :                 ret = false;
    1118           0 :                 torture_fail_goto(tctx, done,
    1119             :                                   "Write-time not updated (wrong!)\n");
    1120             :         }
    1121             : 
    1122           0 :         torture_comment(tctx, "Write a second time\n");
    1123             : 
    1124           0 :         status = smb2_util_write(tree, h1, "s", 0, 1);
    1125           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1126             :                                         "write failed\n");
    1127           0 :         sleep(3);
    1128             : 
    1129           0 :         torture_comment(tctx, "Check writetime has NOT been updated\n");
    1130             : 
    1131           0 :         finfo = (union smb_fileinfo) {
    1132             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
    1133             :                 .generic.in.file.handle = h1,
    1134             :         };
    1135           0 :         status = smb2_getinfo_file(tree, tree, &finfo);
    1136           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1137             :                                         "getinfo failed\n");
    1138           0 :         write_time2 = finfo.all_info.out.write_time;
    1139             : 
    1140           0 :         torture_assert_nttime_equal(tctx, write_time2, write_time,
    1141             :                                     "second write updated write-time (wrong!)\n");
    1142             : 
    1143           0 :         torture_comment(tctx, "Close file-handle 1\n");
    1144           0 :         sleep(2);
    1145             : 
    1146           0 :         now = timespec_current();
    1147           0 :         send_close_time = full_timespec_to_nt_time(&now);
    1148             : 
    1149           0 :         c = (struct smb2_close) {
    1150             :                 .in.file.handle = h1,
    1151             :                 .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
    1152             :         };
    1153             : 
    1154           0 :         status = smb2_close(tree, &c);
    1155           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1156             :                                         "close failed\n");
    1157           0 :         ZERO_STRUCT(h1);
    1158           0 :         close_time = c.out.write_time;
    1159             : 
    1160           0 :         if (!(close_time > send_close_time)) {
    1161           0 :                 ret = false;
    1162           0 :                 torture_fail_goto(tctx, done,
    1163             :                                   "Write-time not updated (wrong!)\n");
    1164             :         }
    1165             : 
    1166           0 : done:
    1167           0 :         if (!smb2_util_handle_empty(h1)) {
    1168           0 :                 smb2_util_close(tree, h1);
    1169             :         }
    1170           0 :         smb2_deltree(tree, BASEDIR);
    1171           0 :         return ret;
    1172             : }
    1173             : 
    1174             : /*
    1175             :    basic testing of SMB2 timestamps
    1176             : */
    1177         964 : struct torture_suite *torture_smb2_timestamps_init(TALLOC_CTX *ctx)
    1178             : {
    1179         964 :         struct torture_suite *suite = torture_suite_create(ctx, "timestamps");
    1180             : 
    1181         964 :         torture_suite_add_1smb2_test(suite, "test_close_not_attrib", test_close_no_attrib);
    1182         964 :         torture_suite_add_1smb2_test(suite, "time_t_15032385535", test_time_t_15032385535);
    1183         964 :         torture_suite_add_1smb2_test(suite, "time_t_10000000000", test_time_t_10000000000);
    1184         964 :         torture_suite_add_1smb2_test(suite, "time_t_4294967295", test_time_t_4294967295);
    1185         964 :         torture_suite_add_1smb2_test(suite, "time_t_1", test_time_t_1);
    1186         964 :         torture_suite_add_1smb2_test(suite, "time_t_0", test_time_t_0);
    1187         964 :         torture_suite_add_1smb2_test(suite, "time_t_-1", test_time_t_minus_1);
    1188         964 :         torture_suite_add_1smb2_test(suite, "time_t_-2", test_time_t_minus_2);
    1189         964 :         torture_suite_add_1smb2_test(suite, "time_t_1968", test_time_t_1968);
    1190         964 :         torture_suite_add_1smb2_test(suite, "freeze-thaw", test_freeze_thaw);
    1191             : 
    1192             :         /*
    1193             :          * Testing of delayed write-time udpates
    1194             :          */
    1195         964 :         torture_suite_add_1smb2_test(suite, "delayed-write-vs-seteof", test_delayed_write_vs_seteof);
    1196         964 :         torture_suite_add_1smb2_test(suite, "delayed-write-vs-flush", test_delayed_write_vs_flush);
    1197         964 :         torture_suite_add_1smb2_test(suite, "delayed-write-vs-setbasic", test_delayed_write_vs_setbasic);
    1198         964 :         torture_suite_add_1smb2_test(suite, "delayed-1write", test_delayed_1write);
    1199         964 :         torture_suite_add_1smb2_test(suite, "delayed-2write", test_delayed_2write);
    1200             : 
    1201         964 :         suite->description = talloc_strdup(suite, "SMB2 timestamp tests");
    1202             : 
    1203         964 :         return suite;
    1204             : }
    1205             : 
    1206             : /*
    1207             :  * This test shows that Windows has a timestamp resolution of ~15ms. When so
    1208             :  * when a smaller amount of time than that has passed it's not necessarily
    1209             :  * detectable on a Windows 2019 and newer who implement immediate timestamp
    1210             :  * updates.
    1211             :  *
    1212             :  * Note that this test relies on a low latency SMB connection. Even with a low
    1213             :  * latency connection of eg 1m there's a chance of 1/15 that the first part of
    1214             :  * the test expecting no timestamp change fails as the writetime is updated.
    1215             :  *
    1216             :  * Due to this timing dependency this test is skipped in Samba CI, but it is
    1217             :  * preserved here for future SMB2 timestamps behaviour archealogists.
    1218             :  *
    1219             :  * See also: https://lists.samba.org/archive/cifs-protocol/2019-December/003358.html
    1220             :  */
    1221           0 : static bool test_timestamp_resolution1(struct torture_context *tctx,
    1222             :                                        struct smb2_tree *tree)
    1223             : {
    1224             :         union smb_fileinfo finfo1;
    1225           0 :         const char *fname = BASEDIR "\\" FNAME;
    1226             :         struct smb2_create cr;
    1227           0 :         struct smb2_handle h = {{0}};
    1228             :         struct smb2_close cl;
    1229             :         NTSTATUS status;
    1230           0 :         bool ret = true;
    1231             : 
    1232           0 :         smb2_deltree(tree, BASEDIR);
    1233           0 :         status = torture_smb2_testdir(tree, BASEDIR, &h);
    1234           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1235             :                                         "create failed\n");
    1236           0 :         status = smb2_util_close(tree, h );
    1237           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1238             :                                         "close failed\n");
    1239             : 
    1240           0 :         torture_comment(tctx, "Write without delay, expect no "
    1241             :                         "write-time change\n");
    1242             : 
    1243           0 :         smb2_generic_create(&cr, NULL, false, fname,
    1244             :                             NTCREATEX_DISP_CREATE,
    1245           0 :                             smb2_util_oplock_level(""), 0, 0);
    1246           0 :         status = smb2_create(tree, tree, &cr);
    1247           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1248             :                                         "create failed\n");
    1249           0 :         h = cr.out.file.handle;
    1250             : 
    1251           0 :         finfo1 = (union smb_fileinfo) {
    1252             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
    1253             :                 .generic.in.file.handle = h,
    1254             :         };
    1255           0 :         status = smb2_getinfo_file(tree, tree, &finfo1);
    1256           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1257             :                                         "getinfo failed\n");
    1258             : 
    1259           0 :         status = smb2_util_write(tree, h, "123456789", 0, 9);
    1260           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1261             :                                         "write failed\n");
    1262             : 
    1263           0 :         cl = (struct smb2_close) {
    1264             :                 .in.file.handle = h,
    1265             :                 .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
    1266             :         };
    1267             : 
    1268           0 :         status = smb2_close(tree, &cl);
    1269           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1270             :                                         "close failed\n");
    1271           0 :         ZERO_STRUCT(h);
    1272             : 
    1273           0 :         torture_comment(tctx, "Initial: %s\nClose: %s\n",
    1274             :                         nt_time_string(tctx, finfo1.basic_info.out.write_time),
    1275             :                         nt_time_string(tctx, cl.out.write_time));
    1276             : 
    1277           0 :         torture_assert_u64_equal_goto(tctx,
    1278             :                                       finfo1.basic_info.out.write_time,
    1279             :                                       cl.out.write_time,
    1280             :                                       ret, done,
    1281             :                                       "Write time changed (wrong!)\n");
    1282             : 
    1283           0 :         torture_comment(tctx, "Write with 20 ms delay, expect "
    1284             :                         "write-time change\n");
    1285             : 
    1286           0 :         smb2_generic_create(&cr, NULL, false, fname,
    1287             :                             NTCREATEX_DISP_OPEN,
    1288           0 :                             smb2_util_oplock_level(""), 0, 0);
    1289           0 :         status = smb2_create(tree, tree, &cr);
    1290           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1291             :                                         "create failed\n");
    1292           0 :         h = cr.out.file.handle;
    1293             : 
    1294           0 :         finfo1 = (union smb_fileinfo) {
    1295             :                 .generic.level = RAW_FILEINFO_SMB2_ALL_INFORMATION,
    1296             :                 .generic.in.file.handle = h,
    1297             :         };
    1298           0 :         status = smb2_getinfo_file(tree, tree, &finfo1);
    1299           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1300             :                                         "getinfo failed\n");
    1301             : 
    1302           0 :         smb_msleep(20);
    1303             : 
    1304           0 :         status = smb2_util_write(tree, h, "123456789", 0, 9);
    1305           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1306             :                                         "write failed\n");
    1307             : 
    1308           0 :         cl = (struct smb2_close) {
    1309             :                 .in.file.handle = h,
    1310             :                 .in.flags = SMB2_CLOSE_FLAGS_FULL_INFORMATION,
    1311             :         };
    1312             : 
    1313           0 :         status = smb2_close(tree, &cl);
    1314           0 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
    1315             :                                         "close failed\n");
    1316           0 :         ZERO_STRUCT(h);
    1317             : 
    1318           0 :         torture_comment(tctx, "Initial: %s\nClose: %s\n",
    1319             :                         nt_time_string(tctx, finfo1.basic_info.out.write_time),
    1320             :                         nt_time_string(tctx, cl.out.write_time));
    1321             : 
    1322           0 :         torture_assert_u64_not_equal_goto(
    1323             :                 tctx,
    1324             :                 finfo1.basic_info.out.write_time,
    1325             :                 cl.out.write_time,
    1326             :                 ret, done,
    1327             :                 "Write time did not change (wrong!)\n");
    1328             : 
    1329           0 : done:
    1330           0 :         if (!smb2_util_handle_empty(h)) {
    1331           0 :                 smb2_util_close(tree, h);
    1332             :         }
    1333           0 :         smb2_deltree(tree, BASEDIR);
    1334           0 :         return ret;
    1335             : }
    1336             : 
    1337             : /*
    1338             :    basic testing of SMB2 timestamps
    1339             : */
    1340         964 : struct torture_suite *torture_smb2_timestamp_resolution_init(TALLOC_CTX *ctx)
    1341             : {
    1342         964 :         struct torture_suite *suite = torture_suite_create(ctx, "timestamp_resolution");
    1343             : 
    1344         964 :         torture_suite_add_1smb2_test(suite, "resolution1", test_timestamp_resolution1);
    1345             : 
    1346         964 :         suite->description = talloc_strdup(suite, "SMB2 timestamp tests");
    1347             : 
    1348         964 :         return suite;
    1349             : }

Generated by: LCOV version 1.13