LCOV - code coverage report
Current view: top level - source4/torture/basic - delaywrite.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 1294 1587 81.5 %
Date: 2021-09-23 10:06:22 Functions: 18 18 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    test suite for delayed write update 
       5             : 
       6             :    Copyright (C) Volker Lendecke 2004
       7             :    Copyright (C) Andrew Tridgell 2004
       8             :    Copyright (C) Jeremy Allison 2004
       9             :    
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             :    
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             :    
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "torture/torture.h"
      26             : #include "libcli/raw/libcliraw.h"
      27             : #include "libcli/raw/raw_proto.h"
      28             : #include "system/time.h"
      29             : #include "system/filesys.h"
      30             : #include "libcli/libcli.h"
      31             : #include "torture/util.h"
      32             : #include "torture/basic/proto.h"
      33             : 
      34             : #define BASEDIR "\\delaywrite"
      35             : 
      36           2 : static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
      37             : {
      38             :         union smb_fileinfo finfo1, finfo2;
      39           2 :         const char *fname = BASEDIR "\\torture_file.txt";
      40             :         NTSTATUS status;
      41           2 :         int fnum1 = -1;
      42           2 :         bool ret = true;
      43             :         ssize_t written;
      44             :         struct timeval start;
      45             :         struct timeval end;
      46           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
      47           2 :         int normal_delay = 2000000;
      48           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
      49           2 :         int msec = 1000 * sec;
      50             : 
      51           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update\n");
      52             : 
      53           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
      54             : 
      55           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
      56           2 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
      57             :                                      "Failed to open %s", fname));
      58             : 
      59           2 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
      60           2 :         finfo1.basic_info.in.file.fnum = fnum1;
      61           2 :         finfo2 = finfo1;
      62             : 
      63           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
      64           2 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
      65             : 
      66           2 :         torture_comment(tctx, "Initial write time %s\n",
      67             :                         nt_time_string(tctx, finfo1.basic_info.out.write_time));
      68             : 
      69           2 :         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
      70           2 :         torture_assert_int_equal(tctx, written, 1,
      71             :                                  "unexpected number of bytes written");
      72             : 
      73           2 :         start = timeval_current();
      74           2 :         end = timeval_add(&start, (120 * sec), 0);
      75           8 :         while (!timeval_expired(&end)) {
      76           6 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
      77             : 
      78           6 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
      79             : 
      80           6 :                 torture_comment(tctx, "write time %s\n",
      81             :                         nt_time_string(tctx, finfo2.basic_info.out.write_time));
      82             : 
      83          12 :                 if (finfo1.basic_info.out.write_time !=
      84           6 :                     finfo2.basic_info.out.write_time)
      85             :                 {
      86           2 :                         double diff = timeval_elapsed(&start);
      87             : 
      88           2 :                         torture_assert(tctx,
      89             :                                        diff >= (used_delay / (double)1000000),
      90             :                                        talloc_asprintf(tctx,
      91             :                                         "Server updated write_time after %.2f "
      92             :                                         "seconds (expected >= %.2f)\n",
      93             :                                         diff, used_delay/(double)1000000));
      94             : 
      95           2 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds (correct)\n",
      96             :                                         diff);
      97           2 :                         break;
      98             :                 }
      99           4 :                 fflush(stdout);
     100           4 :                 smb_msleep(1 * msec);
     101             :         }
     102             : 
     103           2 :         torture_assert_u64_not_equal(tctx,
     104             :                                      finfo2.basic_info.out.write_time,
     105             :                                      finfo1.basic_info.out.write_time,
     106             :                                      "Server did not update write time within "
     107             :                                      "120 seconds");
     108             : 
     109           2 :         if (fnum1 != -1)
     110           2 :                 smbcli_close(cli->tree, fnum1);
     111           2 :         smbcli_unlink(cli->tree, fname);
     112           2 :         smbcli_deltree(cli->tree, BASEDIR);
     113             : 
     114           2 :         return ret;
     115             : }
     116             : 
     117           2 : static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
     118             : {
     119             :         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
     120           2 :         const char *fname = BASEDIR "\\torture_file1.txt";
     121             :         NTSTATUS status;
     122           2 :         int fnum1 = -1;
     123           2 :         bool ret = true;
     124             :         ssize_t written;
     125             :         struct timeval start;
     126             :         struct timeval end;
     127           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     128           2 :         int normal_delay = 2000000;
     129           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
     130           2 :         int msec = 1000 * sec;
     131             :         char buf[2048];
     132             :         bool first;
     133             :         bool updated;
     134             : 
     135           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
     136             : 
     137           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     138             : 
     139           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     140           2 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
     141             :                                      "Failed to open %s", fname));
     142             : 
     143           2 :         memset(buf, 'x', 2048);
     144           2 :         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
     145             : 
     146             :         /* 3 second delay to ensure we get past any 2 second time
     147             :            granularity (older systems may have that) */
     148           2 :         smb_msleep(3 * msec);
     149             : 
     150           2 :         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
     151           2 :         finfo1.all_info.in.file.fnum = fnum1;
     152           2 :         finfo2 = finfo1;
     153           2 :         finfo3 = finfo1;
     154           2 :         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
     155           2 :         pinfo4.all_info.in.file.path = fname;
     156             : 
     157           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     158             : 
     159           2 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     160             : 
     161           2 :         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
     162             :                                  "file size not as expected after write(2048)");
     163             : 
     164           2 :         torture_comment(tctx, "Initial write time %s\n",
     165             :                         nt_time_string(tctx, finfo1.all_info.out.write_time));
     166             : 
     167             :         /* 3 second delay to ensure we get past any 2 second time
     168             :            granularity (older systems may have that) */
     169           2 :         smb_msleep(3 * msec);
     170             : 
     171             :         /* Do a zero length SMBwrite call to truncate. */
     172           2 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
     173           2 :         torture_assert_int_equal(tctx, written, 0,
     174             :                                  "unexpected number of bytes written");
     175             : 
     176           2 :         start = timeval_current();
     177           2 :         end = timeval_add(&start, (120 * sec), 0);
     178           2 :         first = true;
     179           2 :         updated = false;
     180           4 :         while (!timeval_expired(&end)) {
     181           2 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     182             : 
     183           2 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     184             : 
     185           2 :                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 1024,
     186             :                                          "file not truncated to expected size "
     187             :                                          "(1024)");
     188             : 
     189           2 :                 torture_comment(tctx, "write time %s\n",
     190             :                         nt_time_string(tctx, finfo2.all_info.out.write_time));
     191             : 
     192           4 :                 if (finfo1.all_info.out.write_time !=
     193           2 :                     finfo2.all_info.out.write_time)
     194             :                 {
     195           2 :                         updated = true;
     196           2 :                         break;
     197             :                 }
     198             : 
     199           0 :                 fflush(stdout);
     200           0 :                 smb_msleep(1 * msec);
     201           0 :                 first = false;
     202             :         }
     203             : 
     204           2 :         torture_assert(tctx, updated,
     205             :                        "Server did not update write time within 120 seconds");
     206             : 
     207           2 :         torture_assert(tctx, first, talloc_asprintf(tctx,
     208             :                        "Server did not update write time immediately but only "
     209             :                        "after %.2f seconds!", timeval_elapsed(&start)));
     210             : 
     211           2 :         torture_comment(tctx, "Server updated write time immediately. Good!\n");
     212             : 
     213           2 :         fflush(stdout);
     214           2 :         smb_msleep(2 * msec);
     215             : 
     216             :         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
     217           2 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
     218           2 :         torture_assert_int_equal(tctx, written, 1,
     219             :                                  "unexpected number of bytes written");
     220             : 
     221           2 :         start = timeval_current();
     222           2 :         end = timeval_add(&start, (10*sec), 0);
     223          20 :         while (!timeval_expired(&end)) {
     224          16 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
     225             : 
     226          16 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     227             : 
     228          16 :                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1024,
     229             :                                          "file not truncated to expected size "
     230             :                                          "(1024)");
     231             : 
     232          16 :                 torture_comment(tctx, "write time %s\n",
     233             :                         nt_time_string(tctx, finfo3.all_info.out.write_time));
     234             : 
     235          16 :                 torture_assert_u64_equal(tctx,
     236             :                                          finfo3.all_info.out.write_time,
     237             :                                          finfo2.all_info.out.write_time,
     238             :                                          talloc_asprintf(tctx,
     239             :                                                 "Server updated write time "
     240             :                                                 "after %.2f seconds (wrong!)",
     241             :                                                 timeval_elapsed(&start)));
     242             : 
     243          16 :                 fflush(stdout);
     244          16 :                 smb_msleep(1 * msec);
     245             :         }
     246             : 
     247           2 :         torture_comment(tctx, "Server did not update write time within 10 "
     248             :                         "seconds. Good!\n");
     249             : 
     250           2 :         fflush(stdout);
     251           2 :         smb_msleep(2 * msec);
     252             : 
     253             :         /* the close should trigger an write time update */
     254           2 :         smbcli_close(cli->tree, fnum1);
     255           2 :         fnum1 = -1;
     256             : 
     257           2 :         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
     258           2 :         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
     259             : 
     260           2 :         torture_assert_u64_not_equal(tctx,
     261             :                                      pinfo4.all_info.out.write_time,
     262             :                                      finfo3.all_info.out.write_time,
     263             :                                      "Server did not update write time on "
     264             :                                      "close (wrong!)");
     265           2 :         torture_assert(tctx,
     266             :                 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
     267             :                 "Server updated write time on close, but to an earlier point "
     268             :                 "in time");
     269             : 
     270           2 :         torture_comment(tctx, "Server updated write time on close (correct)\n");
     271             : 
     272           2 :         if (fnum1 != -1)
     273           0 :                 smbcli_close(cli->tree, fnum1);
     274           2 :         smbcli_unlink(cli->tree, fname);
     275           2 :         smbcli_deltree(cli->tree, BASEDIR);
     276             : 
     277           2 :         return ret;
     278             : }
     279             : 
     280             : /* Updating with a SMBwrite of zero length
     281             :  * changes the write time immediately - even on expand. */
     282             : 
     283           2 : static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
     284             : {
     285             :         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
     286           2 :         const char *fname = BASEDIR "\\torture_file1a.txt";
     287             :         NTSTATUS status;
     288           2 :         int fnum1 = -1;
     289           2 :         bool ret = true;
     290             :         ssize_t written;
     291             :         struct timeval start;
     292             :         struct timeval end;
     293           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     294           2 :         int normal_delay = 2000000;
     295           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
     296           2 :         int msec = 1000 * sec;
     297             :         char buf[2048];
     298             :         bool first;
     299             :         bool updated;
     300             : 
     301           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
     302             : 
     303           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     304             : 
     305           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     306           2 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
     307             :                                      "Failed to open %s", fname));
     308             : 
     309           2 :         memset(buf, 'x', 2048);
     310           2 :         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
     311             : 
     312             :         /* 3 second delay to ensure we get past any 2 second time
     313             :            granularity (older systems may have that) */
     314           2 :         smb_msleep(3 * msec);
     315             : 
     316           2 :         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
     317           2 :         finfo1.all_info.in.file.fnum = fnum1;
     318           2 :         finfo2 = finfo1;
     319           2 :         finfo3 = finfo1;
     320           2 :         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
     321           2 :         pinfo4.all_info.in.file.path = fname;
     322             : 
     323           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     324             : 
     325           2 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     326             : 
     327           2 :         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
     328             :                                  "file size not as expected after write(2048)");
     329             : 
     330           2 :         torture_comment(tctx, "Initial write time %s\n",
     331             :                         nt_time_string(tctx, finfo1.all_info.out.write_time));
     332             : 
     333             :         /* Do a zero length SMBwrite call to truncate. */
     334           2 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
     335             : 
     336           2 :         torture_assert_int_equal(tctx, written, 0,
     337             :                                  "unexpected number of bytes written");
     338             : 
     339           2 :         start = timeval_current();
     340           2 :         end = timeval_add(&start, (120*sec), 0);
     341           2 :         first = true;
     342           2 :         updated = false;
     343           4 :         while (!timeval_expired(&end)) {
     344           2 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     345             : 
     346           2 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     347             : 
     348           2 :                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
     349             :                                          "file not truncated to expected size "
     350             :                                          "(10240)");
     351             : 
     352           2 :                 torture_comment(tctx, "write time %s\n",
     353             :                         nt_time_string(tctx, finfo2.all_info.out.write_time));
     354             : 
     355           4 :                 if (finfo1.all_info.out.write_time !=
     356           2 :                     finfo2.all_info.out.write_time)
     357             :                 {
     358           2 :                         updated = true;
     359           2 :                         break;
     360             :                 }
     361             : 
     362           0 :                 fflush(stdout);
     363           0 :                 smb_msleep(1 * msec);
     364           0 :                 first = false;
     365             :         }
     366             : 
     367           2 :         torture_assert(tctx, updated,
     368             :                        "Server did not update write time within 120 seconds");
     369             : 
     370           2 :         torture_assert(tctx, first, talloc_asprintf(tctx,
     371             :                        "Server did not update write time immediately but only "
     372             :                        "after %.2f seconds!", timeval_elapsed(&start)));
     373             : 
     374           2 :         torture_comment(tctx, "Server updated write time immediately. Good!\n");
     375             : 
     376           2 :         fflush(stdout);
     377           2 :         smb_msleep(2 * msec);
     378             : 
     379             :         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
     380           2 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
     381             : 
     382           2 :         torture_assert_int_equal(tctx, written, 1,
     383             :                                  "unexpected number of bytes written");
     384             : 
     385           2 :         start = timeval_current();
     386           2 :         end = timeval_add(&start, (10*sec), 0);
     387          20 :         while (!timeval_expired(&end)) {
     388          16 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
     389             : 
     390          16 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     391             : 
     392          16 :                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
     393             :                                          "file not truncated to expected size "
     394             :                                          "(10240)");
     395             : 
     396          16 :                 torture_comment(tctx, "write time %s\n",
     397             :                         nt_time_string(tctx, finfo3.all_info.out.write_time));
     398             : 
     399          16 :                 torture_assert_u64_equal(tctx,
     400             :                                          finfo3.all_info.out.write_time,
     401             :                                          finfo2.all_info.out.write_time,
     402             :                                          talloc_asprintf(tctx,
     403             :                                                 "Server updated write time "
     404             :                                                 "after %.2f seconds (wrong!)",
     405             :                                                 timeval_elapsed(&start)));
     406             : 
     407          16 :                 fflush(stdout);
     408          16 :                 smb_msleep(1 * msec);
     409             :         }
     410             : 
     411           2 :         torture_comment(tctx, "Server did not update write time within 10 "
     412             :                         "seconds. Good!\n");
     413             : 
     414             :         /* the close should trigger an write time update */
     415           2 :         smbcli_close(cli->tree, fnum1);
     416           2 :         fnum1 = -1;
     417             : 
     418           2 :         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
     419           2 :         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
     420             : 
     421           2 :         torture_assert_u64_not_equal(tctx,
     422             :                                      pinfo4.all_info.out.write_time,
     423             :                                      finfo3.all_info.out.write_time,
     424             :                                      "Server did not update write time on "
     425             :                                      "close (wrong!)");
     426           2 :         torture_assert(tctx,
     427             :                 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
     428             :                 "Server updated write time on close, but to an earlier point "
     429             :                 "in time");
     430             : 
     431           2 :         torture_comment(tctx, "Server updated write time on close (correct)\n");
     432             : 
     433           2 :         if (fnum1 != -1)
     434           0 :                 smbcli_close(cli->tree, fnum1);
     435           2 :         smbcli_unlink(cli->tree, fname);
     436           2 :         smbcli_deltree(cli->tree, BASEDIR);
     437             : 
     438           2 :         return ret;
     439             : }
     440             : 
     441             : /* Updating with a SET_FILE_END_OF_FILE_INFO
     442             :  * changes the write time immediately - even on expand. */
     443             : 
     444           2 : static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
     445             : {
     446             :         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
     447           2 :         const char *fname = BASEDIR "\\torture_file1b.txt";
     448             :         NTSTATUS status;
     449           2 :         int fnum1 = -1;
     450           2 :         bool ret = true;
     451             :         ssize_t written;
     452             :         struct timeval start;
     453             :         struct timeval end;
     454           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     455           2 :         int normal_delay = 2000000;
     456           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
     457           2 :         int msec = 1000 * sec;
     458             :         char buf[2048];
     459             :         bool first;
     460             :         bool updated;
     461             : 
     462           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
     463             : 
     464           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     465             : 
     466           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     467           2 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
     468             :                                      "Failed to open %s", fname));
     469             : 
     470           2 :         memset(buf, 'x', 2048);
     471           2 :         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
     472             : 
     473             :         /* 3 second delay to ensure we get past any 2 second time
     474             :            granularity (older systems may have that) */
     475           2 :         smb_msleep(3 * msec);
     476             : 
     477           2 :         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
     478           2 :         finfo1.all_info.in.file.fnum = fnum1;
     479           2 :         finfo2 = finfo1;
     480           2 :         finfo3 = finfo1;
     481           2 :         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
     482           2 :         pinfo4.all_info.in.file.path = fname;
     483             : 
     484           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     485             : 
     486           2 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     487             : 
     488           2 :         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
     489             :                                  "file size not as expected after write(2048)");
     490             : 
     491           2 :         torture_comment(tctx, "Initial write time %s\n",
     492             :                 nt_time_string(tctx, finfo1.all_info.out.write_time));
     493             : 
     494             :         /* Do a SET_END_OF_FILE_INFO call to truncate. */
     495           2 :         status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
     496             : 
     497           2 :         torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
     498             : 
     499           2 :         start = timeval_current();
     500           2 :         end = timeval_add(&start, (120*sec), 0);
     501           2 :         first = true;
     502           2 :         updated = false;
     503           4 :         while (!timeval_expired(&end)) {
     504           2 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     505             : 
     506           2 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     507             : 
     508           2 :                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
     509             :                                          "file not truncated to expected size "
     510             :                                          "(10240)");
     511             : 
     512           2 :                 torture_comment(tctx, "write time %s\n",
     513             :                         nt_time_string(tctx, finfo2.all_info.out.write_time));
     514             : 
     515           4 :                 if (finfo1.all_info.out.write_time !=
     516           2 :                     finfo2.all_info.out.write_time)
     517             :                 {
     518           2 :                         updated = true;
     519           2 :                         break;
     520             :                 }
     521             : 
     522           0 :                 fflush(stdout);
     523           0 :                 smb_msleep(1 * msec);
     524           0 :                 first = false;
     525             :         }
     526             : 
     527           2 :         torture_assert(tctx, updated,
     528             :                        "Server did not update write time within 120 seconds");
     529             : 
     530           2 :         torture_assert(tctx, first, talloc_asprintf(tctx,
     531             :                        "Server did not update write time immediately but only "
     532             :                        "after %.2f seconds!", timeval_elapsed(&start)));
     533             : 
     534           2 :         torture_comment(tctx, "Server updated write time immediately. Good!\n");
     535             : 
     536           2 :         fflush(stdout);
     537           2 :         smb_msleep(2 * msec);
     538             : 
     539             :         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
     540           2 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
     541             : 
     542           2 :         torture_assert_int_equal(tctx, written, 1,
     543             :                                  "unexpected number of bytes written");
     544             : 
     545           2 :         start = timeval_current();
     546           2 :         end = timeval_add(&start, (10*sec), 0);
     547          20 :         while (!timeval_expired(&end)) {
     548          16 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
     549             : 
     550          16 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     551             : 
     552          16 :                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
     553             :                                          "file not truncated to expected size "
     554             :                                          "(10240)");
     555             : 
     556          16 :                 torture_comment(tctx, "write time %s\n",
     557             :                         nt_time_string(tctx, finfo3.all_info.out.write_time));
     558             : 
     559          16 :                 torture_assert_u64_equal(tctx,
     560             :                                          finfo3.all_info.out.write_time,
     561             :                                          finfo2.all_info.out.write_time,
     562             :                                          talloc_asprintf(tctx,
     563             :                                                 "Server updated write time "
     564             :                                                 "after %.2f seconds (wrong!)",
     565             :                                                 timeval_elapsed(&start)));
     566             : 
     567          16 :                 fflush(stdout);
     568          16 :                 smb_msleep(1 * msec);
     569             :         }
     570             : 
     571           2 :         torture_comment(tctx, "Server did not update write time within 10 "
     572             :                         "seconds. Good!\n");
     573             : 
     574             :         /* the close should trigger an write time update */
     575           2 :         smbcli_close(cli->tree, fnum1);
     576           2 :         fnum1 = -1;
     577             : 
     578           2 :         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
     579           2 :         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
     580             : 
     581           2 :         torture_assert_u64_not_equal(tctx,
     582             :                                      pinfo4.all_info.out.write_time,
     583             :                                      finfo3.all_info.out.write_time,
     584             :                                      "Server did not update write time on "
     585             :                                      "close (wrong!)");
     586           2 :         torture_assert(tctx,
     587             :                 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
     588             :                 "Server updated write time on close, but to an earlier point "
     589             :                 "in time");
     590             : 
     591           2 :         torture_comment(tctx, "Server updated write time on close (correct)\n");
     592             : 
     593           2 :         if (fnum1 != -1)
     594           0 :                 smbcli_close(cli->tree, fnum1);
     595           2 :         smbcli_unlink(cli->tree, fname);
     596           2 :         smbcli_deltree(cli->tree, BASEDIR);
     597             : 
     598           2 :         return ret;
     599             : }
     600             : 
     601             : /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
     602             : 
     603           2 : static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
     604             : {
     605             :         union smb_setfileinfo parms;
     606             :         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
     607           2 :         const char *fname = BASEDIR "\\torture_file1c.txt";
     608             :         NTSTATUS status;
     609           2 :         int fnum1 = -1;
     610           2 :         bool ret = true;
     611             :         ssize_t written;
     612             :         struct timeval start;
     613             :         struct timeval end;
     614           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     615           2 :         int normal_delay = 2000000;
     616           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
     617           2 :         int msec = 1000 * sec;
     618             :         char buf[2048];
     619             :         bool first;
     620             :         bool updated;
     621             : 
     622           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
     623             : 
     624           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     625             : 
     626           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     627           2 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
     628             :                                      "Failed to open %s", fname));
     629             : 
     630           2 :         memset(buf, 'x', 2048);
     631           2 :         written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
     632             : 
     633             :         /* 3 second delay to ensure we get past any 2 second time
     634             :            granularity (older systems may have that) */
     635           2 :         smb_msleep(3 * msec);
     636             : 
     637           2 :         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
     638           2 :         finfo1.all_info.in.file.fnum = fnum1;
     639           2 :         finfo2 = finfo1;
     640           2 :         finfo3 = finfo1;
     641           2 :         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
     642           2 :         pinfo4.all_info.in.file.path = fname;
     643             : 
     644           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     645             : 
     646           2 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     647             : 
     648           2 :         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
     649             :                                  "file size not as expected after write(2048)");
     650             : 
     651           2 :         torture_comment(tctx, "Initial write time %s\n",
     652             :                 nt_time_string(tctx, finfo1.all_info.out.write_time));
     653             : 
     654             :         /* Do a SET_ALLOCATION_SIZE call to truncate. */
     655           2 :         parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
     656           2 :         parms.allocation_info.in.file.fnum = fnum1;
     657           2 :         parms.allocation_info.in.alloc_size = 0;
     658             : 
     659           2 :         status = smb_raw_setfileinfo(cli->tree, &parms);
     660             : 
     661           2 :         torture_assert_ntstatus_ok(tctx, status,
     662             :                                    "RAW_SFILEINFO_ALLOCATION_INFO failed");
     663             : 
     664           2 :         start = timeval_current();
     665           2 :         end = timeval_add(&start, (120*sec), 0);
     666           2 :         first = true;
     667           2 :         updated = false;
     668           4 :         while (!timeval_expired(&end)) {
     669           2 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     670             : 
     671           2 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     672             : 
     673           2 :                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 0,
     674             :                                          "file not truncated to expected size "
     675             :                                          "(0)");
     676             : 
     677           2 :                 torture_comment(tctx, "write time %s\n",
     678             :                         nt_time_string(tctx, finfo2.all_info.out.write_time));
     679             : 
     680           4 :                 if (finfo1.all_info.out.write_time !=
     681           2 :                     finfo2.all_info.out.write_time)
     682             :                 {
     683           2 :                         updated = true;
     684           2 :                         break;
     685             :                 }
     686             : 
     687           0 :                 fflush(stdout);
     688           0 :                 smb_msleep(1 * msec);
     689           0 :                 first = false;
     690             :         }
     691             : 
     692           2 :         torture_assert(tctx, updated,
     693             :                        "Server did not update write time within 120 seconds");
     694             : 
     695           2 :         torture_assert(tctx, first, talloc_asprintf(tctx,
     696             :                        "Server did not update write time immediately but only "
     697             :                        "after %.2f seconds!", timeval_elapsed(&start)));
     698             : 
     699           2 :         torture_comment(tctx, "Server updated write time immediately. Good!\n");
     700             : 
     701           2 :         fflush(stdout);
     702           2 :         smb_msleep(2 * msec);
     703             : 
     704             :         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
     705           2 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
     706           2 :         torture_assert_int_equal(tctx, written, 1,
     707             :                                  "Unexpected number of bytes written");
     708             : 
     709           2 :         start = timeval_current();
     710           2 :         end = timeval_add(&start, (10*sec), 0);
     711          20 :         while (!timeval_expired(&end)) {
     712          16 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
     713             : 
     714          16 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     715             : 
     716          16 :                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1,
     717             :                                          "file not expaneded");
     718             : 
     719          16 :                 torture_comment(tctx, "write time %s\n",
     720             :                         nt_time_string(tctx, finfo3.all_info.out.write_time));
     721             : 
     722          16 :                 torture_assert_u64_equal(tctx,
     723             :                                          finfo3.all_info.out.write_time,
     724             :                                          finfo2.all_info.out.write_time,
     725             :                                          talloc_asprintf(tctx,
     726             :                                                 "Server updated write time "
     727             :                                                 "after %.2f seconds (wrong!)",
     728             :                                                 timeval_elapsed(&start)));
     729             : 
     730          16 :                 fflush(stdout);
     731          16 :                 smb_msleep(1 * msec);
     732             :         }
     733             : 
     734           2 :         torture_comment(tctx, "Server did not update write time within 10 "
     735             :                         "seconds. Good!\n");
     736             : 
     737             :         /* the close should trigger an write time update */
     738           2 :         smbcli_close(cli->tree, fnum1);
     739           2 :         fnum1 = -1;
     740             : 
     741           2 :         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
     742           2 :         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
     743             : 
     744           2 :         torture_assert_u64_not_equal(tctx,
     745             :                                      pinfo4.all_info.out.write_time,
     746             :                                      finfo3.all_info.out.write_time,
     747             :                                      "Server did not update write time on "
     748             :                                      "close (wrong!)");
     749           2 :         torture_assert(tctx,
     750             :                 pinfo4.all_info.out.write_time > finfo3.all_info.out.write_time,
     751             :                 "Server updated write time on close, but to an earlier point "
     752             :                 "in time");
     753             : 
     754           2 :         if (fnum1 != -1)
     755           0 :                 smbcli_close(cli->tree, fnum1);
     756           2 :         smbcli_unlink(cli->tree, fname);
     757           2 :         smbcli_deltree(cli->tree, BASEDIR);
     758             : 
     759           2 :         return ret;
     760             : }
     761             : 
     762             : /*
     763             :  * Do as above, but using 2 connections.
     764             :  */
     765             : 
     766           2 : static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli, 
     767             :                                                                            struct smbcli_state *cli2)
     768             : {
     769             :         union smb_fileinfo finfo1, finfo2;
     770           2 :         const char *fname = BASEDIR "\\torture_file.txt";
     771             :         NTSTATUS status;
     772           2 :         int fnum1 = -1;
     773           2 :         int fnum2 = -1;
     774           2 :         bool ret = true;
     775             :         ssize_t written;
     776             :         struct timeval start;
     777             :         struct timeval end;
     778           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     779           2 :         int normal_delay = 2000000;
     780           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
     781           2 :         int msec = 1000 * sec;
     782             :         union smb_flush flsh;
     783             : 
     784           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
     785             : 
     786           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     787             : 
     788           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     789           2 :         if (fnum1 == -1) {
     790           0 :                 torture_comment(tctx, "Failed to open %s\n", fname);
     791           0 :                 return false;
     792             :         }
     793             : 
     794           2 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
     795           2 :         finfo1.basic_info.in.file.fnum = fnum1;
     796           2 :         finfo2 = finfo1;
     797             : 
     798           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     799             : 
     800           2 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     801             :         
     802           2 :         torture_comment(tctx, "Initial write time %s\n", 
     803             :                nt_time_string(tctx, finfo1.basic_info.out.write_time));
     804             : 
     805             :         /* 3 second delay to ensure we get past any 2 second time
     806             :            granularity (older systems may have that) */
     807           2 :         smb_msleep(3 * msec);
     808             : 
     809             :         {
     810             :                 /* Try using setfileinfo instead of write to update write time. */
     811             :                 union smb_setfileinfo sfinfo;
     812           2 :                 time_t t_set = time(NULL);
     813           2 :                 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
     814           2 :                 sfinfo.basic_info.in.file.fnum = fnum1;
     815           2 :                 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
     816           2 :                 sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
     817             : 
     818             :                 /* I tried this with both + and - ve to see if it makes a different.
     819             :                    It doesn't - once the filetime is set via setfileinfo it stays that way. */
     820             : #if 1
     821           2 :                 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
     822             : #else
     823             :                 unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
     824             : #endif
     825           2 :                 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
     826           2 :                 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
     827             : 
     828           2 :                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
     829             : 
     830           2 :                 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
     831             :         }
     832             : 
     833           2 :         finfo2.basic_info.in.file.path = fname;
     834             :         
     835           2 :         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
     836             : 
     837           2 :         if (!NT_STATUS_IS_OK(status)) {
     838           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     839           0 :                 return false;
     840             :         }
     841           2 :         torture_comment(tctx, "write time %s\n",
     842             :                nt_time_string(tctx, finfo2.basic_info.out.write_time));
     843             : 
     844           2 :         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
     845           2 :                 torture_comment(tctx, "Server updated write_time (correct)\n");
     846             :         } else {
     847           0 :                 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
     848           0 :                 ret = false;
     849             :         }
     850             : 
     851             :         /* Now try a write to see if the write time gets reset. */
     852             : 
     853           2 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
     854           2 :         finfo1.basic_info.in.file.fnum = fnum1;
     855           2 :         finfo2 = finfo1;
     856             : 
     857           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     858             : 
     859           2 :         if (!NT_STATUS_IS_OK(status)) {
     860           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     861           0 :                 return false;
     862             :         }
     863             :         
     864           2 :         torture_comment(tctx, "Modified write time %s\n", 
     865             :                nt_time_string(tctx, finfo1.basic_info.out.write_time));
     866             : 
     867             : 
     868           2 :         torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
     869             : 
     870           2 :         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
     871             : 
     872           2 :         if (written != 10) {
     873           0 :                 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
     874             :                        (int)written, __location__);
     875           0 :                 return false;
     876             :         }
     877             : 
     878             :         /* Just to prove to tridge that the an smbflush has no effect on
     879             :            the write time :-). The setfileinfo IS STICKY. JRA. */
     880             : 
     881           2 :         torture_comment(tctx, "Doing flush after write\n");
     882             : 
     883           2 :         flsh.flush.level        = RAW_FLUSH_FLUSH;
     884           2 :         flsh.flush.in.file.fnum = fnum1;
     885           2 :         status = smb_raw_flush(cli->tree, &flsh);
     886           2 :         if (!NT_STATUS_IS_OK(status)) {
     887           0 :                 DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
     888           0 :                 return false;
     889             :         }
     890             : 
     891             :         /* Once the time was set using setfileinfo then it stays set - writes
     892             :            don't have any effect. But make sure. */
     893           2 :         start = timeval_current();
     894           2 :         end = timeval_add(&start, (15*sec), 0);
     895          28 :         while (!timeval_expired(&end)) {
     896          24 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     897             : 
     898          24 :                 if (!NT_STATUS_IS_OK(status)) {
     899           0 :                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     900           0 :                         ret = false;
     901           0 :                         break;
     902             :                 }
     903          24 :                 torture_comment(tctx, "write time %s\n", 
     904             :                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
     905          24 :                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
     906           0 :                         double diff = timeval_elapsed(&start);
     907           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
     908             :                                         "(wrong!)\n",
     909             :                                         diff);
     910           0 :                         ret = false;
     911           0 :                         break;
     912             :                 }
     913          24 :                 fflush(stdout);
     914          24 :                 smb_msleep(1 * msec);
     915             :         }
     916             :         
     917           2 :         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
     918           2 :                 torture_comment(tctx, "Server did not update write time (correct)\n");
     919             :         }
     920             : 
     921           2 :         fflush(stdout);
     922           2 :         smb_msleep(2 * msec);
     923             : 
     924           2 :         fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
     925           2 :         if (fnum2 == -1) {
     926           0 :                 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
     927           0 :                 return false;
     928             :         }
     929             :         
     930           2 :         torture_comment(tctx, "Doing a 10 byte write to extend the file via second fd and see if this changes the last write time.\n");
     931             : 
     932           2 :         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
     933             : 
     934           2 :         if (written != 10) {
     935           0 :                 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
     936             :                        (int)written, __location__);
     937           0 :                 return false;
     938             :         }
     939             : 
     940           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     941             : 
     942           2 :         if (!NT_STATUS_IS_OK(status)) {
     943           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     944           0 :                 return false;
     945             :         }
     946           2 :         torture_comment(tctx, "write time %s\n", 
     947             :                nt_time_string(tctx, finfo2.basic_info.out.write_time));
     948           2 :         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
     949           0 :                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
     950           0 :                 ret = false;
     951             :         }
     952             : 
     953           2 :         torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
     954           2 :         smbcli_close(cli->tree, fnum1);
     955           2 :         fnum1 = -1;
     956             : 
     957           2 :         torture_comment(tctx, "Doing a 10 byte write to extend the file via second fd and see if this changes the last write time.\n");
     958             : 
     959           2 :         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
     960             : 
     961           2 :         if (written != 10) {
     962           0 :                 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
     963             :                        (int)written, __location__);
     964           0 :                 return false;
     965             :         }
     966             : 
     967           2 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
     968           2 :         finfo1.basic_info.in.file.fnum = fnum2;
     969           2 :         finfo2 = finfo1;
     970           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     971             : 
     972           2 :         if (!NT_STATUS_IS_OK(status)) {
     973           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     974           0 :                 return false;
     975             :         }
     976           2 :         torture_comment(tctx, "write time %s\n", 
     977             :                nt_time_string(tctx, finfo2.basic_info.out.write_time));
     978           2 :         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
     979           0 :                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
     980           0 :                 ret = false;
     981             :         }
     982             : 
     983             :         /* Once the time was set using setfileinfo then it stays set - writes
     984             :            don't have any effect. But make sure. */
     985           2 :         start = timeval_current();
     986           2 :         end = timeval_add(&start, (15*sec), 0);
     987          28 :         while (!timeval_expired(&end)) {
     988          24 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     989             : 
     990          24 :                 if (!NT_STATUS_IS_OK(status)) {
     991           0 :                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     992           0 :                         ret = false;
     993           0 :                         break;
     994             :                 }
     995          24 :                 torture_comment(tctx, "write time %s\n", 
     996             :                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
     997          24 :                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
     998           0 :                         double diff = timeval_elapsed(&start);
     999           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    1000             :                                         "(wrong!)\n",
    1001             :                                         diff);
    1002           0 :                         ret = false;
    1003           0 :                         break;
    1004             :                 }
    1005          24 :                 fflush(stdout);
    1006          24 :                 smb_msleep(1 * msec);
    1007             :         }
    1008             :         
    1009           2 :         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    1010           2 :                 torture_comment(tctx, "Server did not update write time (correct)\n");
    1011             :         }
    1012             : 
    1013           2 :         torture_comment(tctx, "Closing second fd to see if write time updated.\n");
    1014             : 
    1015           2 :         smbcli_close(cli->tree, fnum2);
    1016           2 :         fnum2 = -1;
    1017             : 
    1018           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
    1019           2 :         if (fnum1 == -1) {
    1020           0 :                 torture_comment(tctx, "Failed to open %s\n", fname);
    1021           0 :                 return false;
    1022             :         }
    1023             : 
    1024           2 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1025           2 :         finfo1.basic_info.in.file.fnum = fnum1;
    1026           2 :         finfo2 = finfo1;
    1027             : 
    1028           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
    1029             : 
    1030           2 :         if (!NT_STATUS_IS_OK(status)) {
    1031           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
    1032           0 :                 return false;
    1033             :         }
    1034             :         
    1035           2 :         torture_comment(tctx, "Second open initial write time %s\n", 
    1036             :                nt_time_string(tctx, finfo1.basic_info.out.write_time));
    1037             : 
    1038           2 :         smb_msleep(10 * msec);
    1039           2 :         torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
    1040             : 
    1041           2 :         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
    1042             : 
    1043           2 :         if (written != 10) {
    1044           0 :                 torture_result(tctx, TORTURE_FAIL, "write failed - wrote %d bytes (%s)\n",
    1045             :                        (int)written, __location__);
    1046           0 :                 return false;
    1047             :         }
    1048             : 
    1049           2 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1050           2 :         finfo1.basic_info.in.file.fnum = fnum1;
    1051           2 :         finfo2 = finfo1;
    1052           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
    1053             : 
    1054           2 :         if (!NT_STATUS_IS_OK(status)) {
    1055           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
    1056           0 :                 return false;
    1057             :         }
    1058           2 :         torture_comment(tctx, "write time %s\n", 
    1059             :                nt_time_string(tctx, finfo2.basic_info.out.write_time));
    1060           2 :         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
    1061           0 :                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time (wrong!)\n");
    1062           0 :                 ret = false;
    1063             :         }
    1064             : 
    1065             :         /* Now the write time should be updated again */
    1066           2 :         start = timeval_current();
    1067           2 :         end = timeval_add(&start, (15*sec), 0);
    1068           8 :         while (!timeval_expired(&end)) {
    1069           6 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
    1070             : 
    1071           6 :                 if (!NT_STATUS_IS_OK(status)) {
    1072           0 :                         DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
    1073           0 :                         ret = false;
    1074           0 :                         break;
    1075             :                 }
    1076           6 :                 torture_comment(tctx, "write time %s\n", 
    1077             :                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
    1078           6 :                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
    1079           2 :                         double diff = timeval_elapsed(&start);
    1080           2 :                         if (diff < (used_delay / (double)1000000)) {
    1081           0 :                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
    1082             :                                                 "(expected > %.2f) (wrong!)\n",
    1083             :                                                 diff, used_delay / (double)1000000);
    1084           0 :                                 ret = false;
    1085           0 :                                 break;
    1086             :                         }
    1087             : 
    1088           2 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds"
    1089             :                                         "(correct)\n",
    1090             :                                         diff);
    1091           2 :                         break;
    1092             :                 }
    1093           4 :                 fflush(stdout);
    1094           4 :                 smb_msleep(1*msec);
    1095             :         }
    1096             :         
    1097           2 :         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    1098           0 :                 torture_result(tctx, TORTURE_FAIL, "Server did not update write time (wrong!)\n");
    1099           0 :                 ret = false;
    1100             :         }
    1101             : 
    1102             : 
    1103             :         /* One more test to do. We should read the filetime via findfirst on the
    1104             :            second connection to ensure it's the same. This is very easy for a Windows
    1105             :            server but a bastard to get right on a POSIX server. JRA. */
    1106             : 
    1107           2 :         if (fnum1 != -1)
    1108           2 :                 smbcli_close(cli->tree, fnum1);
    1109           2 :         smbcli_unlink(cli->tree, fname);
    1110           2 :         smbcli_deltree(cli->tree, BASEDIR);
    1111             : 
    1112           2 :         return ret;
    1113             : }
    1114             : 
    1115             : 
    1116             : /* Windows does obviously not update the stat info during a write call. I
    1117             :  * *think* this is the problem causing a spurious Excel 2003 on XP error
    1118             :  * message when saving a file. Excel does a setfileinfo, writes, and then does
    1119             :  * a getpath(!)info. Or so... For Samba sometimes it displays an error message
    1120             :  * that the file might have been changed in between. What i've been able to
    1121             :  * trace down is that this happens if the getpathinfo after the write shows a
    1122             :  * different last write time than the setfileinfo showed. This is really
    1123             :  * nasty....
    1124             :  */
    1125             : 
    1126           2 : static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli, 
    1127             :                                                                    struct smbcli_state *cli2)
    1128             : {
    1129             :         union smb_fileinfo finfo1, finfo2;
    1130           2 :         const char *fname = BASEDIR "\\torture_file.txt";
    1131             :         NTSTATUS status;
    1132           2 :         int fnum1 = -1;
    1133             :         int fnum2;
    1134           2 :         bool ret = true;
    1135             :         ssize_t written;
    1136           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1137           2 :         int normal_delay = 2000000;
    1138           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1139           2 :         int msec = 1000 * sec;
    1140             : 
    1141           2 :         torture_comment(tctx, "\nRunning test_finfo_after_write\n");
    1142             : 
    1143           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1144             : 
    1145           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1146           2 :         if (fnum1 == -1) {
    1147           0 :                 ret = false;
    1148           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    1149           0 :                 goto done;
    1150             :         }
    1151             : 
    1152           2 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1153           2 :         finfo1.basic_info.in.file.fnum = fnum1;
    1154             : 
    1155           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
    1156             : 
    1157           2 :         if (!NT_STATUS_IS_OK(status)) {
    1158           0 :                 ret = false;
    1159           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
    1160           0 :                 goto done;
    1161             :         }
    1162             : 
    1163           2 :         smb_msleep(1 * msec);
    1164             : 
    1165           2 :         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1166             : 
    1167           2 :         if (written != 1) {
    1168           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    1169           0 :                 ret = false;
    1170           0 :                 goto done;
    1171             :         }
    1172             : 
    1173           2 :         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
    1174           2 :         if (fnum2 == -1) {
    1175           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s", 
    1176             :                        smbcli_errstr(cli2->tree));
    1177           0 :                 ret = false;
    1178           0 :                 goto done;
    1179             :         }
    1180             : 
    1181           2 :         written =  smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
    1182             : 
    1183           2 :         if (written != 1) {
    1184           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", 
    1185             :                        (int)written);
    1186           0 :                 ret = false;
    1187           0 :                 goto done;
    1188             :         }
    1189             : 
    1190           2 :         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1191           2 :         finfo2.basic_info.in.file.path = fname;
    1192             : 
    1193           2 :         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
    1194             : 
    1195           2 :         if (!NT_STATUS_IS_OK(status)) {
    1196           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", 
    1197             :                           nt_errstr(status));
    1198           0 :                 ret = false;
    1199           0 :                 goto done;
    1200             :         }
    1201             : 
    1202           4 :         if (finfo1.basic_info.out.create_time !=
    1203           2 :             finfo2.basic_info.out.create_time) {
    1204           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
    1205           0 :                 ret = false;
    1206           0 :                 goto done;
    1207             :         }
    1208             : 
    1209           4 :         if (finfo1.basic_info.out.access_time !=
    1210           2 :             finfo2.basic_info.out.access_time) {
    1211           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
    1212           0 :                 ret = false;
    1213           0 :                 goto done;
    1214             :         }
    1215             : 
    1216           4 :         if (finfo1.basic_info.out.write_time !=
    1217           2 :             finfo2.basic_info.out.write_time) {
    1218           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
    1219             :                                            "write time conn 1 = %s, conn 2 = %s", 
    1220             :                        nt_time_string(tctx, finfo1.basic_info.out.write_time),
    1221             :                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
    1222           0 :                 ret = false;
    1223           0 :                 goto done;
    1224             :         }
    1225             : 
    1226           4 :         if (finfo1.basic_info.out.change_time !=
    1227           2 :             finfo2.basic_info.out.change_time) {
    1228           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
    1229           0 :                 ret = false;
    1230           0 :                 goto done;
    1231             :         }
    1232             : 
    1233             :         /* One of the two following calls updates the qpathinfo. */
    1234             : 
    1235             :         /* If you had skipped the smbcli_write on fnum2, it would
    1236             :          * *not* have updated the stat on disk */
    1237             : 
    1238           2 :         smbcli_close(cli2->tree, fnum2);
    1239           2 :         cli2 = NULL;
    1240             : 
    1241             :         /* This call is only for the people looking at ethereal :-) */
    1242           2 :         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1243           2 :         finfo2.basic_info.in.file.path = fname;
    1244             : 
    1245           2 :         status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
    1246             : 
    1247           2 :         if (!NT_STATUS_IS_OK(status)) {
    1248           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
    1249           0 :                 ret = false;
    1250           0 :                 goto done;
    1251             :         }
    1252             : 
    1253           4 :  done:
    1254           2 :         if (fnum1 != -1)
    1255           2 :                 smbcli_close(cli->tree, fnum1);
    1256           2 :         smbcli_unlink(cli->tree, fname);
    1257           2 :         smbcli_deltree(cli->tree, BASEDIR);
    1258             : 
    1259           2 :         return ret;
    1260             : }
    1261             : 
    1262             : #define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
    1263             :         uint64_t r = 10*1000*1000; \
    1264             :         NTTIME g = (given).basic_info.out.write_time; \
    1265             :         NTTIME gr = (g / r) * r; \
    1266             :         NTTIME c = (correct).basic_info.out.write_time; \
    1267             :         NTTIME cr = (c / r) * r; \
    1268             :         bool strict = torture_setting_bool(tctx, "strict mode", false); \
    1269             :         bool err = false; \
    1270             :         if (strict && (g cmp c)) { \
    1271             :                 err = true; \
    1272             :         } else if ((g cmp c) && (gr cmp cr)) { \
    1273             :                 /* handle filesystem without high resolution timestamps */ \
    1274             :                 err = true; \
    1275             :         } \
    1276             :         if (err) { \
    1277             :                 torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
    1278             :                                 #given, nt_time_string(tctx, g), (unsigned long long)g, \
    1279             :                                 #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
    1280             :                 ret = false; \
    1281             :                 goto done; \
    1282             :         } \
    1283             : } while (0)
    1284             : #define COMPARE_WRITE_TIME_EQUAL(given,correct) \
    1285             :         COMPARE_WRITE_TIME_CMP(given,correct,!=)
    1286             : #define COMPARE_WRITE_TIME_GREATER(given,correct) \
    1287             :         COMPARE_WRITE_TIME_CMP(given,correct,<=)
    1288             : #define COMPARE_WRITE_TIME_LESS(given,correct) \
    1289             :         COMPARE_WRITE_TIME_CMP(given,correct,>=)
    1290             : 
    1291             : #define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
    1292             :         NTTIME g = (given).basic_info.out.access_time; \
    1293             :         NTTIME c = (correct).basic_info.out.access_time; \
    1294             :         if (g cmp c) { \
    1295             :                 torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
    1296             :                                 #given, nt_time_string(tctx, g), \
    1297             :                                 #cmp, #correct, nt_time_string(tctx, c)); \
    1298             :                 ret = false; \
    1299             :                 goto done; \
    1300             :         } \
    1301             : } while (0)
    1302             : #define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
    1303             :         COMPARE_ACCESS_TIME_CMP(given,correct,!=)
    1304             : 
    1305             : #define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
    1306             :         COMPARE_ACCESS_TIME_EQUAL(given,correct); \
    1307             :         COMPARE_WRITE_TIME_EQUAL(given,correct); \
    1308             : } while (0)
    1309             : 
    1310             : #define GET_INFO_FILE(finfo) do { \
    1311             :         NTSTATUS _status; \
    1312             :         _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
    1313             :         if (!NT_STATUS_IS_OK(_status)) { \
    1314             :                 ret = false; \
    1315             :                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
    1316             :                                nt_errstr(_status)); \
    1317             :                 goto done; \
    1318             :         } \
    1319             :         torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
    1320             :                         nt_time_string(tctx, finfo.basic_info.out.access_time), \
    1321             :                         nt_time_string(tctx, finfo.basic_info.out.write_time)); \
    1322             : } while (0)
    1323             : #define GET_INFO_FILE2(finfo) do { \
    1324             :         NTSTATUS _status; \
    1325             :         _status = smb_raw_fileinfo(cli2->tree, tctx, &finfo); \
    1326             :         if (!NT_STATUS_IS_OK(_status)) { \
    1327             :                 ret = false; \
    1328             :                 torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
    1329             :                                nt_errstr(_status)); \
    1330             :                 goto done; \
    1331             :         } \
    1332             :         torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
    1333             :                         nt_time_string(tctx, finfo.basic_info.out.access_time), \
    1334             :                         nt_time_string(tctx, finfo.basic_info.out.write_time)); \
    1335             : } while (0)
    1336             : #define GET_INFO_PATH(pinfo) do { \
    1337             :         NTSTATUS _status; \
    1338             :         _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
    1339             :         if (!NT_STATUS_IS_OK(_status)) { \
    1340             :                 torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
    1341             :                                nt_errstr(_status)); \
    1342             :                 ret = false; \
    1343             :                 goto done; \
    1344             :         } \
    1345             :         torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
    1346             :                         nt_time_string(tctx, pinfo.basic_info.out.access_time), \
    1347             :                         nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
    1348             : } while (0)
    1349             : #define GET_INFO_BOTH(finfo,pinfo) do { \
    1350             :         GET_INFO_FILE(finfo); \
    1351             :         GET_INFO_PATH(pinfo); \
    1352             :         COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
    1353             : } while (0)
    1354             : 
    1355             : #define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
    1356             :         NTSTATUS _status; \
    1357             :         union smb_setfileinfo sfinfo; \
    1358             :         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
    1359             :         sfinfo.basic_info.in.file.fnum = tfnum; \
    1360             :         sfinfo.basic_info.in.create_time = 0; \
    1361             :         sfinfo.basic_info.in.access_time = 0; \
    1362             :         unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
    1363             :         sfinfo.basic_info.in.change_time = 0; \
    1364             :         sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
    1365             :         _status = smb_raw_setfileinfo(tree, &sfinfo); \
    1366             :         if (!NT_STATUS_IS_OK(_status)) { \
    1367             :                 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
    1368             :                                nt_errstr(_status)); \
    1369             :                 ret = false; \
    1370             :                 goto done; \
    1371             :         } \
    1372             : } while (0)
    1373             : #define SET_INFO_FILE(finfo, wrtime) \
    1374             :         SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
    1375             : 
    1376             : #define SET_INFO_FILE_NS(finfo, wrtime, ns, tree, tfnum) do { \
    1377             :         NTSTATUS _status; \
    1378             :         union smb_setfileinfo sfinfo; \
    1379             :         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
    1380             :         sfinfo.basic_info.in.file.fnum = tfnum; \
    1381             :         sfinfo.basic_info.in.create_time = 0; \
    1382             :         sfinfo.basic_info.in.access_time = 0; \
    1383             :         unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
    1384             :         sfinfo.basic_info.in.write_time += (ns); \
    1385             :         sfinfo.basic_info.in.change_time = 0; \
    1386             :         sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
    1387             :         _status = smb_raw_setfileinfo(tree, &sfinfo); \
    1388             :         if (!NT_STATUS_IS_OK(_status)) { \
    1389             :                 torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
    1390             :                                nt_errstr(_status)); \
    1391             :                 ret = false; \
    1392             :                 goto done; \
    1393             :         } \
    1394             : } while (0)
    1395             : 
    1396           2 : static bool test_delayed_write_update3(struct torture_context *tctx,
    1397             :                                        struct smbcli_state *cli,
    1398             :                                        struct smbcli_state *cli2)
    1399             : {
    1400             :         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
    1401             :         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
    1402           2 :         const char *fname = BASEDIR "\\torture_file3.txt";
    1403           2 :         int fnum1 = -1;
    1404           2 :         bool ret = true;
    1405             :         ssize_t written;
    1406             :         struct timeval start;
    1407             :         struct timeval end;
    1408           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1409           2 :         int normal_delay = 2000000;
    1410           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1411           2 :         int msec = 1000 * sec;
    1412             : 
    1413           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
    1414             : 
    1415           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1416             : 
    1417           2 :         torture_comment(tctx, "Open the file handle\n");
    1418           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1419           2 :         if (fnum1 == -1) {
    1420           0 :                 ret = false;
    1421           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    1422           0 :                 goto done;
    1423             :         }
    1424             : 
    1425           2 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1426           2 :         finfo0.basic_info.in.file.fnum = fnum1;
    1427           2 :         finfo1 = finfo0;
    1428           2 :         finfo2 = finfo0;
    1429           2 :         finfo3 = finfo0;
    1430           2 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1431           2 :         pinfo0.basic_info.in.file.path = fname;
    1432           2 :         pinfo1 = pinfo0;
    1433           2 :         pinfo2 = pinfo0;
    1434           2 :         pinfo3 = pinfo0;
    1435           2 :         pinfo4 = pinfo0;
    1436             : 
    1437             :         /* get the initial times */
    1438           2 :         GET_INFO_BOTH(finfo0,pinfo0);
    1439             : 
    1440             :         /*
    1441             :          * make sure the write time is updated 2 seconds later
    1442             :          * calcuated from the first write
    1443             :          * (but expect up to 5 seconds extra time for a busy server)
    1444             :          */
    1445           2 :         start = timeval_current();
    1446           2 :         end = timeval_add(&start, 7 * sec, 0);
    1447          12 :         while (!timeval_expired(&end)) {
    1448             :                 /* do a write */
    1449          10 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1450          10 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1451          10 :                 if (written != 1) {
    1452           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    1453           0 :                         ret = false;
    1454           0 :                         goto done;
    1455             :                 }
    1456             :                 /* get the times after the write */
    1457          10 :                 GET_INFO_FILE(finfo1);
    1458             : 
    1459          10 :                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
    1460           2 :                         double diff = timeval_elapsed(&start);
    1461           2 :                         if (diff < (used_delay / (double)1000000)) {
    1462           0 :                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    1463             :                                                 "(write time update delay == %.2f) (wrong!)\n",
    1464             :                                                 diff, used_delay / (double)1000000);
    1465           0 :                                 ret = false;
    1466           0 :                                 break;
    1467             :                         }
    1468             : 
    1469           2 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
    1470             :                                         "(correct)\n",
    1471             :                                         diff);
    1472           2 :                         break;
    1473             :                 }
    1474           8 :                 smb_msleep(0.5 * msec);
    1475             :         }
    1476             : 
    1477           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    1478           2 :         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
    1479             : 
    1480             :         /* sure any further write doesn't update the write time */
    1481           2 :         start = timeval_current();
    1482           2 :         end = timeval_add(&start, 15 * sec, 0);
    1483          28 :         while (!timeval_expired(&end)) {
    1484             :                 /* do a write */
    1485          24 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1486          24 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1487          24 :                 if (written != 1) {
    1488           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    1489           0 :                         ret = false;
    1490           0 :                         goto done;
    1491             :                 }
    1492             :                 /* get the times after the write */
    1493          24 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1494             : 
    1495          24 :                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
    1496           0 :                         double diff = timeval_elapsed(&start);
    1497           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    1498             :                                         "(wrong!)\n",
    1499             :                                         diff);
    1500           0 :                         ret = false;
    1501           0 :                         break;
    1502             :                 }
    1503          24 :                 smb_msleep(1 * msec);
    1504             :         }
    1505             : 
    1506           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    1507           2 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    1508           2 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    1509           2 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    1510             :         }
    1511             : 
    1512             :         /* sleep */
    1513           2 :         smb_msleep(5 * msec);
    1514             : 
    1515           2 :         GET_INFO_BOTH(finfo3,pinfo3);
    1516           2 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    1517             : 
    1518             :         /*
    1519             :          * the close updates the write time to the time of the close
    1520             :          * and not to the time of the last write!
    1521             :          */
    1522           2 :         torture_comment(tctx, "Close the file handle\n");
    1523           2 :         smbcli_close(cli->tree, fnum1);
    1524           2 :         fnum1 = -1;
    1525             : 
    1526           2 :         GET_INFO_PATH(pinfo4);
    1527           2 :         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
    1528             : 
    1529           2 :         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
    1530           2 :                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
    1531             :         }
    1532             : 
    1533           2 :  done:
    1534           2 :         if (fnum1 != -1)
    1535           0 :                 smbcli_close(cli->tree, fnum1);
    1536           2 :         smbcli_unlink(cli->tree, fname);
    1537           2 :         smbcli_deltree(cli->tree, BASEDIR);
    1538             : 
    1539           2 :         return ret;
    1540             : }
    1541             : 
    1542             : /*
    1543             :  * Show that a truncate write always updates the write time even
    1544             :  * if an initial write has already updated the write time.
    1545             :  */
    1546             : 
    1547           2 : static bool test_delayed_write_update3a(struct torture_context *tctx,
    1548             :                                         struct smbcli_state *cli,
    1549             :                                         struct smbcli_state *cli2)
    1550             : {
    1551             :         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
    1552             :         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
    1553           2 :         const char *fname = BASEDIR "\\torture_file3a.txt";
    1554           2 :         int fnum1 = -1;
    1555           2 :         bool ret = true;
    1556             :         ssize_t written;
    1557             :         int i;
    1558             :         struct timeval start;
    1559             :         struct timeval end;
    1560           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1561           2 :         int normal_delay = 2000000;
    1562           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1563           2 :         int msec = 1000 * sec;
    1564             : 
    1565           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
    1566             : 
    1567           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1568             : 
    1569           2 :         torture_comment(tctx, "Open the file handle\n");
    1570           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1571           2 :         if (fnum1 == -1) {
    1572           0 :                 ret = false;
    1573           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    1574           0 :                 goto done;
    1575             :         }
    1576             : 
    1577           2 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1578           2 :         finfo0.basic_info.in.file.fnum = fnum1;
    1579           2 :         finfo1 = finfo0;
    1580           2 :         finfo2 = finfo0;
    1581           2 :         finfo3 = finfo0;
    1582           2 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1583           2 :         pinfo0.basic_info.in.file.path = fname;
    1584           2 :         pinfo1 = pinfo0;
    1585           2 :         pinfo2 = pinfo0;
    1586           2 :         pinfo3 = pinfo0;
    1587           2 :         pinfo4 = pinfo0;
    1588             : 
    1589             :         /* get the initial times */
    1590           2 :         GET_INFO_BOTH(finfo0,pinfo0);
    1591             : 
    1592             :         /*
    1593             :          * sleep some time, to demonstrate the handling of write times
    1594             :          * doesn't depend on the time since the open
    1595             :          */
    1596           2 :         smb_msleep(5 * msec);
    1597             : 
    1598             :         /* get the initial times */
    1599           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    1600           2 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    1601             : 
    1602             :         /*
    1603             :          * make sure the write time is updated 2 seconds later
    1604             :          * calcuated from the first write
    1605             :          * (but expect up to 5 seconds extra time for a busy server)
    1606             :          */
    1607           2 :         start = timeval_current();
    1608           2 :         end = timeval_add(&start, 7 * sec, 0);
    1609          12 :         while (!timeval_expired(&end)) {
    1610             :                 /* do a write */
    1611          10 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1612          10 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1613          10 :                 if (written != 1) {
    1614           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    1615           0 :                         ret = false;
    1616           0 :                         goto done;
    1617             :                 }
    1618             :                 /* get the times after the write */
    1619          10 :                 GET_INFO_FILE(finfo1);
    1620             : 
    1621          10 :                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
    1622           2 :                         double diff = timeval_elapsed(&start);
    1623           2 :                         if (diff < (used_delay / (double)1000000)) {
    1624           0 :                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    1625             :                                                 "(1sec == %.2f) (wrong!)\n",
    1626             :                                                 diff, sec);
    1627           0 :                                 ret = false;
    1628           0 :                                 break;
    1629             :                         }
    1630             : 
    1631           2 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
    1632             :                                         "(correct)\n",
    1633             :                                         diff);
    1634           2 :                         break;
    1635             :                 }
    1636           8 :                 smb_msleep(0.5 * msec);
    1637             :         }
    1638             : 
    1639           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    1640           2 :         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
    1641             : 
    1642           2 :         smb_msleep(3 * msec);
    1643             : 
    1644             :         /*
    1645             :          * demonstrate that a truncate write always
    1646             :          * updates the write time immediately
    1647             :          */
    1648           8 :         for (i=0; i < 3; i++) {
    1649           6 :                 smb_msleep(2 * msec);
    1650             :                 /* do a write */
    1651           6 :                 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
    1652           6 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
    1653           6 :                 if (written != 0) {
    1654           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
    1655           0 :                         ret = false;
    1656           0 :                         goto done;
    1657             :                 }
    1658             :                 /* get the times after the write */
    1659           6 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1660           6 :                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    1661           6 :                 finfo1 = finfo2;
    1662             :         }
    1663             : 
    1664           2 :         smb_msleep(3 * msec);
    1665             : 
    1666             :         /* sure any further write doesn't update the write time */
    1667           2 :         start = timeval_current();
    1668           2 :         end = timeval_add(&start, 15 * sec, 0);
    1669          28 :         while (!timeval_expired(&end)) {
    1670             :                 /* do a write */
    1671          24 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1672          24 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1673          24 :                 if (written != 1) {
    1674           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    1675           0 :                         ret = false;
    1676           0 :                         goto done;
    1677             :                 }
    1678             :                 /* get the times after the write */
    1679          24 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1680             : 
    1681          24 :                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
    1682           0 :                         double diff = timeval_elapsed(&start);
    1683           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    1684             :                                         "(wrong!)\n",
    1685             :                                         diff);
    1686           0 :                         ret = false;
    1687           0 :                         break;
    1688             :                 }
    1689          24 :                 smb_msleep(1 * msec);
    1690             :         }
    1691             : 
    1692           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    1693           2 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    1694           2 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    1695           2 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    1696             :         }
    1697             : 
    1698             :         /* sleep */
    1699           2 :         smb_msleep(3 * msec);
    1700             : 
    1701             :         /* get the initial times */
    1702           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    1703           2 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
    1704             : 
    1705             :         /*
    1706             :          * demonstrate that a truncate write always
    1707             :          * updates the write time immediately
    1708             :          */
    1709           8 :         for (i=0; i < 3; i++) {
    1710           6 :                 smb_msleep(2 * msec);
    1711             :                 /* do a write */
    1712           6 :                 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
    1713           6 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
    1714           6 :                 if (written != 0) {
    1715           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
    1716           0 :                         ret = false;
    1717           0 :                         goto done;
    1718             :                 }
    1719             :                 /* get the times after the write */
    1720           6 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1721           6 :                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    1722           6 :                 finfo1 = finfo2;
    1723             :         }
    1724             : 
    1725             :         /* sleep */
    1726           2 :         smb_msleep(3 * msec);
    1727             : 
    1728           2 :         GET_INFO_BOTH(finfo3,pinfo3);
    1729           2 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    1730             : 
    1731             :         /*
    1732             :          * the close doesn't update the write time
    1733             :          */
    1734           2 :         torture_comment(tctx, "Close the file handle\n");
    1735           2 :         smbcli_close(cli->tree, fnum1);
    1736           2 :         fnum1 = -1;
    1737             : 
    1738           2 :         GET_INFO_PATH(pinfo4);
    1739           2 :         COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
    1740             : 
    1741           2 :         if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
    1742           2 :                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
    1743             :         }
    1744             : 
    1745           2 :  done:
    1746           2 :         if (fnum1 != -1)
    1747           0 :                 smbcli_close(cli->tree, fnum1);
    1748           2 :         smbcli_unlink(cli->tree, fname);
    1749           2 :         smbcli_deltree(cli->tree, BASEDIR);
    1750             : 
    1751           2 :         return ret;
    1752             : }
    1753             : 
    1754             : /*
    1755             :  * Show a close after write updates the write timestamp to
    1756             :  * the close time, not the last write time.
    1757             :  */
    1758             : 
    1759           2 : static bool test_delayed_write_update3b(struct torture_context *tctx,
    1760             :                                         struct smbcli_state *cli,
    1761             :                                         struct smbcli_state *cli2)
    1762             : {
    1763             :         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
    1764             :         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
    1765           2 :         const char *fname = BASEDIR "\\torture_file3b.txt";
    1766           2 :         int fnum1 = -1;
    1767           2 :         bool ret = true;
    1768             :         ssize_t written;
    1769             :         struct timeval start;
    1770             :         struct timeval end;
    1771           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1772           2 :         int normal_delay = 2000000;
    1773           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1774           2 :         int msec = 1000 * sec;
    1775             : 
    1776           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
    1777             : 
    1778           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1779             : 
    1780           2 :         torture_comment(tctx, "Open the file handle\n");
    1781           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1782           2 :         if (fnum1 == -1) {
    1783           0 :                 ret = false;
    1784           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    1785           0 :                 goto done;
    1786             :         }
    1787             : 
    1788           2 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1789           2 :         finfo0.basic_info.in.file.fnum = fnum1;
    1790           2 :         finfo1 = finfo0;
    1791           2 :         finfo2 = finfo0;
    1792           2 :         finfo3 = finfo0;
    1793           2 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1794           2 :         pinfo0.basic_info.in.file.path = fname;
    1795           2 :         pinfo1 = pinfo0;
    1796           2 :         pinfo2 = pinfo0;
    1797           2 :         pinfo3 = pinfo0;
    1798           2 :         pinfo4 = pinfo0;
    1799             : 
    1800             :         /* get the initial times */
    1801           2 :         GET_INFO_BOTH(finfo0,pinfo0);
    1802             : 
    1803             :         /*
    1804             :          * sleep some time, to demonstrate the handling of write times
    1805             :          * doesn't depend on the time since the open
    1806             :          */
    1807           2 :         smb_msleep(5 * msec);
    1808             : 
    1809             :         /* get the initial times */
    1810           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    1811           2 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    1812             : 
    1813             :         /*
    1814             :          * make sure the write time is updated 2 seconds later
    1815             :          * calcuated from the first write
    1816             :          * (but expect up to 5 seconds extra time for a busy server)
    1817             :          */
    1818           2 :         start = timeval_current();
    1819           2 :         end = timeval_add(&start, 7 * sec, 0);
    1820          12 :         while (!timeval_expired(&end)) {
    1821             :                 /* do a write */
    1822          10 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1823          10 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1824          10 :                 if (written != 1) {
    1825           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    1826           0 :                         ret = false;
    1827           0 :                         goto done;
    1828             :                 }
    1829             :                 /* get the times after the write */
    1830          10 :                 GET_INFO_FILE(finfo1);
    1831             : 
    1832          10 :                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
    1833           2 :                         double diff = timeval_elapsed(&start);
    1834           2 :                         if (diff < (used_delay / (double)1000000)) {
    1835           0 :                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
    1836             :                                                 "(expected > %.2f) (wrong!)\n",
    1837             :                                                 diff, used_delay / (double)1000000);
    1838           0 :                                 ret = false;
    1839           0 :                                 break;
    1840             :                         }
    1841             : 
    1842           2 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
    1843             :                                         "(write time update delay == %.2f) (correct)\n",
    1844             :                                         diff, used_delay / (double)1000000);
    1845           2 :                         break;
    1846             :                 }
    1847           8 :                 smb_msleep(0.5 * msec);
    1848             :         }
    1849             : 
    1850           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    1851           2 :         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
    1852             : 
    1853             :         /* sure any further write doesn't update the write time */
    1854           2 :         start = timeval_current();
    1855           2 :         end = timeval_add(&start, 15 * sec, 0);
    1856          28 :         while (!timeval_expired(&end)) {
    1857             :                 /* do a write */
    1858          24 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1859          24 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1860          24 :                 if (written != 1) {
    1861           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    1862           0 :                         ret = false;
    1863           0 :                         goto done;
    1864             :                 }
    1865             :                 /* get the times after the write */
    1866          24 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1867             : 
    1868          24 :                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
    1869           0 :                         double diff = timeval_elapsed(&start);
    1870           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    1871             :                                         "(wrong!)\n",
    1872             :                                         diff);
    1873           0 :                         ret = false;
    1874           0 :                         break;
    1875             :                 }
    1876          24 :                 smb_msleep(1 * msec);
    1877             :         }
    1878             : 
    1879           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    1880           2 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    1881           2 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    1882           2 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    1883             :         }
    1884             : 
    1885             :         /* sleep */
    1886           2 :         smb_msleep(5 * msec);
    1887             : 
    1888           2 :         GET_INFO_BOTH(finfo3,pinfo3);
    1889           2 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    1890             : 
    1891             :         /*
    1892             :          * the close updates the write time to the time of the close
    1893             :          * and not to the time of the last write!
    1894             :          */
    1895           2 :         torture_comment(tctx, "Close the file handle\n");
    1896           2 :         smbcli_close(cli->tree, fnum1);
    1897           2 :         fnum1 = -1;
    1898             : 
    1899           2 :         GET_INFO_PATH(pinfo4);
    1900           2 :         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
    1901             : 
    1902           2 :         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
    1903           2 :                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
    1904             :         }
    1905             : 
    1906           2 :  done:
    1907           2 :         if (fnum1 != -1)
    1908           0 :                 smbcli_close(cli->tree, fnum1);
    1909           2 :         smbcli_unlink(cli->tree, fname);
    1910           2 :         smbcli_deltree(cli->tree, BASEDIR);
    1911             : 
    1912           2 :         return ret;
    1913             : }
    1914             : 
    1915             : /*
    1916             :  * Check that a write after a truncate write doesn't update
    1917             :  * the timestamp, but a truncate write after a write does.
    1918             :  * Also prove that a close after a truncate write updates the
    1919             :  * timestamp to current, not the time of last write.
    1920             :  */
    1921             : 
    1922           2 : static bool test_delayed_write_update3c(struct torture_context *tctx,
    1923             :                                         struct smbcli_state *cli,
    1924             :                                         struct smbcli_state *cli2)
    1925             : {
    1926             :         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
    1927             :         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
    1928           2 :         const char *fname = BASEDIR "\\torture_file3c.txt";
    1929           2 :         int fnum1 = -1;
    1930           2 :         bool ret = true;
    1931             :         ssize_t written;
    1932             :         int i;
    1933             :         struct timeval start;
    1934             :         struct timeval end;
    1935           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1936           2 :         int normal_delay = 2000000;
    1937           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1938           2 :         int msec = 1000 * sec;
    1939             : 
    1940           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
    1941             : 
    1942           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1943             : 
    1944           2 :         torture_comment(tctx, "Open the file handle\n");
    1945           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1946           2 :         if (fnum1 == -1) {
    1947           0 :                 ret = false;
    1948           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    1949           0 :                 goto done;
    1950             :         }
    1951             : 
    1952           2 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1953           2 :         finfo0.basic_info.in.file.fnum = fnum1;
    1954           2 :         finfo1 = finfo0;
    1955           2 :         finfo2 = finfo0;
    1956           2 :         finfo3 = finfo0;
    1957           2 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1958           2 :         pinfo0.basic_info.in.file.path = fname;
    1959           2 :         pinfo1 = pinfo0;
    1960           2 :         pinfo2 = pinfo0;
    1961           2 :         pinfo3 = pinfo0;
    1962           2 :         pinfo4 = pinfo0;
    1963             : 
    1964             :         /* get the initial times */
    1965           2 :         GET_INFO_BOTH(finfo0,pinfo0);
    1966             : 
    1967             :         /*
    1968             :          * sleep some time, to demonstrate the handling of write times
    1969             :          * doesn't depend on the time since the open
    1970             :          */
    1971           2 :         smb_msleep(5 * msec);
    1972             : 
    1973             :         /* get the initial times */
    1974           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    1975           2 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    1976             : 
    1977             :         /*
    1978             :          * demonstrate that a truncate write always
    1979             :          * updates the write time immediately
    1980             :          */
    1981           8 :         for (i=0; i < 3; i++) {
    1982           6 :                 smb_msleep(2 * msec);
    1983             :                 /* do a write */
    1984           6 :                 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
    1985           6 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
    1986           6 :                 if (written != 0) {
    1987           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
    1988           0 :                         ret = false;
    1989           0 :                         goto done;
    1990             :                 }
    1991             :                 /* get the times after the write */
    1992           6 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1993           6 :                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    1994           6 :                 finfo1 = finfo2;
    1995             :         }
    1996             : 
    1997           2 :         start = timeval_current();
    1998           2 :         end = timeval_add(&start, 7 * sec, 0);
    1999          12 :         while (!timeval_expired(&end)) {
    2000             :                 /* do a write */
    2001           8 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2002           8 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2003           8 :                 if (written != 1) {
    2004           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2005           0 :                         ret = false;
    2006           0 :                         goto done;
    2007             :                 }
    2008             :                 /* get the times after the write */
    2009           8 :                 GET_INFO_FILE(finfo2);
    2010             : 
    2011           8 :                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
    2012           0 :                         double diff = timeval_elapsed(&start);
    2013           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2014             :                                         "(wrong!)\n",
    2015             :                                         diff);
    2016           0 :                         ret = false;
    2017           0 :                         break;
    2018             :                 }
    2019           8 :                 smb_msleep(1 * msec);
    2020             :         }
    2021             : 
    2022           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    2023           2 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    2024           2 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    2025           2 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2026             :         }
    2027             : 
    2028             :         /* sleep */
    2029           2 :         smb_msleep(5 * msec);
    2030             : 
    2031             :         /* get the initial times */
    2032           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    2033           2 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
    2034             : 
    2035             :         /*
    2036             :          * demonstrate that a truncate write always
    2037             :          * updates the write time immediately
    2038             :          */
    2039           8 :         for (i=0; i < 3; i++) {
    2040           6 :                 smb_msleep(2 * msec);
    2041             :                 /* do a write */
    2042           6 :                 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
    2043           6 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
    2044           6 :                 if (written != 0) {
    2045           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
    2046           0 :                         ret = false;
    2047           0 :                         goto done;
    2048             :                 }
    2049             :                 /* get the times after the write */
    2050           6 :                 GET_INFO_BOTH(finfo2,pinfo2);
    2051           6 :                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    2052           6 :                 finfo1 = finfo2;
    2053             :         }
    2054             : 
    2055             :         /* sleep */
    2056           2 :         smb_msleep(5 * msec);
    2057             : 
    2058           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    2059           2 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    2060             : 
    2061             :         /* sure any further write doesn't update the write time */
    2062           2 :         start = timeval_current();
    2063           2 :         end = timeval_add(&start, 15 * sec, 0);
    2064          28 :         while (!timeval_expired(&end)) {
    2065             :                 /* do a write */
    2066          24 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2067          24 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2068          24 :                 if (written != 1) {
    2069           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2070           0 :                         ret = false;
    2071           0 :                         goto done;
    2072             :                 }
    2073             :                 /* get the times after the write */
    2074          24 :                 GET_INFO_BOTH(finfo2,pinfo2);
    2075             : 
    2076          24 :                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
    2077           0 :                         double diff = timeval_elapsed(&start);
    2078           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2079             :                                         "(wrong!)\n",
    2080             :                                         diff);
    2081           0 :                         ret = false;
    2082           0 :                         break;
    2083             :                 }
    2084          24 :                 smb_msleep(1 * msec);
    2085             :         }
    2086             : 
    2087           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    2088           2 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    2089           2 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    2090           2 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2091             :         }
    2092             : 
    2093             :         /* sleep */
    2094           2 :         smb_msleep(5 * msec);
    2095             : 
    2096           2 :         GET_INFO_BOTH(finfo3,pinfo3);
    2097           2 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    2098             : 
    2099             :         /*
    2100             :          * the close updates the write time to the time of the close
    2101             :          * and not to the time of the last write!
    2102             :          */
    2103           2 :         torture_comment(tctx, "Close the file handle\n");
    2104           2 :         smbcli_close(cli->tree, fnum1);
    2105           2 :         fnum1 = -1;
    2106             : 
    2107           2 :         GET_INFO_PATH(pinfo4);
    2108           2 :         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
    2109             : 
    2110           2 :         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
    2111           2 :                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
    2112             :         }
    2113             : 
    2114           2 :  done:
    2115           2 :         if (fnum1 != -1)
    2116           0 :                 smbcli_close(cli->tree, fnum1);
    2117           2 :         smbcli_unlink(cli->tree, fname);
    2118           2 :         smbcli_deltree(cli->tree, BASEDIR);
    2119             : 
    2120           2 :         return ret;
    2121             : }
    2122             : 
    2123             : /*
    2124             :  * Show only the first write updates the timestamp, and a close
    2125             :  * after writes updates to current (I think this is the same
    2126             :  * as test 3b. JRA).
    2127             :  */
    2128             : 
    2129           2 : static bool test_delayed_write_update4(struct torture_context *tctx,
    2130             :                                        struct smbcli_state *cli,
    2131             :                                        struct smbcli_state *cli2)
    2132             : {
    2133             :         union smb_fileinfo finfo0, finfo1, finfo2, finfo3;
    2134             :         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4;
    2135           2 :         const char *fname = BASEDIR "\\torture_file4.txt";
    2136           2 :         int fnum1 = -1;
    2137           2 :         bool ret = true;
    2138             :         ssize_t written;
    2139             :         struct timeval start;
    2140             :         struct timeval end;
    2141           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2142           2 :         int normal_delay = 2000000;
    2143           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2144           2 :         int msec = 1000 * sec;
    2145             : 
    2146           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
    2147             : 
    2148           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2149             : 
    2150           2 :         torture_comment(tctx, "Open the file handle\n");
    2151           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2152           2 :         if (fnum1 == -1) {
    2153           0 :                 ret = false;
    2154           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    2155           0 :                 goto done;
    2156             :         }
    2157             : 
    2158           2 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2159           2 :         finfo0.basic_info.in.file.fnum = fnum1;
    2160           2 :         finfo1 = finfo0;
    2161           2 :         finfo2 = finfo0;
    2162           2 :         finfo3 = finfo0;
    2163           2 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2164           2 :         pinfo0.basic_info.in.file.path = fname;
    2165           2 :         pinfo1 = pinfo0;
    2166           2 :         pinfo2 = pinfo0;
    2167           2 :         pinfo3 = pinfo0;
    2168           2 :         pinfo4 = pinfo0;
    2169             : 
    2170             :         /* get the initial times */
    2171           2 :         GET_INFO_BOTH(finfo0,pinfo0);
    2172             : 
    2173             :         /* sleep a bit */
    2174           2 :         smb_msleep(5 * msec);
    2175             : 
    2176             :         /* do a write */
    2177           2 :         torture_comment(tctx, "Do a write on the file handle\n");
    2178           2 :         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2179           2 :         if (written != 1) {
    2180           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2181           0 :                 ret = false;
    2182           0 :                 goto done;
    2183             :         }
    2184             : 
    2185           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    2186           2 :         COMPARE_WRITE_TIME_EQUAL(finfo1,finfo0);
    2187             : 
    2188             :         /*
    2189             :          * make sure the write time is updated 2 seconds later
    2190             :          * calcuated from the first write
    2191             :          * (but expect up to 3 seconds extra time for a busy server)
    2192             :          */
    2193           2 :         start = timeval_current();
    2194           2 :         end = timeval_add(&start, 5 * sec, 0);
    2195          12 :         while (!timeval_expired(&end)) {
    2196             :                 /* get the times after the first write */
    2197          10 :                 GET_INFO_FILE(finfo1);
    2198             : 
    2199          10 :                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
    2200           2 :                         double diff = timeval_elapsed(&start);
    2201           2 :                         if (diff < (used_delay / (double)1000000)) {
    2202           0 :                                 torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds"
    2203             :                                                 "(expected > %.2f) (wrong!)\n",
    2204             :                                                 diff, used_delay / (double)1000000);
    2205           0 :                                 ret = false;
    2206           0 :                                 break;
    2207             :                         }
    2208             : 
    2209           2 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
    2210             :                                         "(write time update delay == %.2f) (correct)\n",
    2211             :                                         diff, used_delay / (double)1000000);
    2212           2 :                         break;
    2213             :                 }
    2214           8 :                 smb_msleep(0.5 * msec);
    2215             :         }
    2216             : 
    2217           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    2218           2 :         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
    2219             : 
    2220             :         /* sure any further write doesn't update the write time */
    2221           2 :         start = timeval_current();
    2222           2 :         end = timeval_add(&start, 15 * sec, 0);
    2223          28 :         while (!timeval_expired(&end)) {
    2224             :                 /* do a write */
    2225          24 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2226          24 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2227          24 :                 if (written != 1) {
    2228           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2229           0 :                         ret = false;
    2230           0 :                         goto done;
    2231             :                 }
    2232             :                 /* get the times after the write */
    2233          24 :                 GET_INFO_BOTH(finfo2,pinfo2);
    2234             : 
    2235          24 :                 if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
    2236           0 :                         double diff = timeval_elapsed(&start);
    2237           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2238             :                                         "(wrong!)\n",
    2239             :                                         diff);
    2240           0 :                         ret = false;
    2241           0 :                         break;
    2242             :                 }
    2243          24 :                 smb_msleep(1 * msec);
    2244             :         }
    2245             : 
    2246           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    2247           2 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    2248           2 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    2249           2 :                 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
    2250             :         }
    2251             : 
    2252             :         /* sleep */
    2253           2 :         smb_msleep(5 * msec);
    2254             : 
    2255           2 :         GET_INFO_BOTH(finfo3,pinfo3);
    2256           2 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    2257             : 
    2258             :         /*
    2259             :          * the close updates the write time to the time of the close
    2260             :          * and not to the time of the last write!
    2261             :          */
    2262           2 :         torture_comment(tctx, "Close the file handle\n");
    2263           2 :         smbcli_close(cli->tree, fnum1);
    2264           2 :         fnum1 = -1;
    2265             : 
    2266           2 :         GET_INFO_PATH(pinfo4);
    2267           2 :         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
    2268             : 
    2269           2 :         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
    2270           2 :                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
    2271             :         }
    2272             : 
    2273           2 :  done:
    2274           2 :         if (fnum1 != -1)
    2275           0 :                 smbcli_close(cli->tree, fnum1);
    2276           2 :         smbcli_unlink(cli->tree, fname);
    2277           2 :         smbcli_deltree(cli->tree, BASEDIR);
    2278             : 
    2279           2 :         return ret;
    2280             : }
    2281             : 
    2282             : /*
    2283             :  * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
    2284             :  */
    2285             : 
    2286           2 : static bool test_delayed_write_update5(struct torture_context *tctx,
    2287             :                                        struct smbcli_state *cli,
    2288             :                                        struct smbcli_state *cli2)
    2289             : {
    2290             :         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
    2291             :         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
    2292           2 :         const char *fname = BASEDIR "\\torture_file5.txt";
    2293           2 :         int fnum1 = -1;
    2294           2 :         bool ret = true;
    2295             :         ssize_t written;
    2296             :         struct timeval start;
    2297             :         struct timeval end;
    2298           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2299           2 :         int normal_delay = 2000000;
    2300           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2301           2 :         int msec = 1000 * sec;
    2302             : 
    2303           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
    2304             : 
    2305           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2306             : 
    2307           2 :         torture_comment(tctx, "Open the file handle\n");
    2308           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2309           2 :         if (fnum1 == -1) {
    2310           0 :                 ret = false;
    2311           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    2312           0 :                 goto done;
    2313             :         }
    2314             : 
    2315           2 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2316           2 :         finfo0.basic_info.in.file.fnum = fnum1;
    2317           2 :         finfo1 = finfo0;
    2318           2 :         finfo2 = finfo0;
    2319           2 :         finfo3 = finfo0;
    2320           2 :         finfo4 = finfo0;
    2321           2 :         finfo5 = finfo0;
    2322           2 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2323           2 :         pinfo0.basic_info.in.file.path = fname;
    2324           2 :         pinfo1 = pinfo0;
    2325           2 :         pinfo2 = pinfo0;
    2326           2 :         pinfo3 = pinfo0;
    2327           2 :         pinfo4 = pinfo0;
    2328           2 :         pinfo5 = pinfo0;
    2329           2 :         pinfo6 = pinfo0;
    2330             : 
    2331             :         /* get the initial times */
    2332           2 :         GET_INFO_BOTH(finfo0,pinfo0);
    2333             : 
    2334             :         /* do a write */
    2335           2 :         torture_comment(tctx, "Do a write on the file handle\n");
    2336           2 :         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2337           2 :         if (written != 1) {
    2338           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2339           0 :                 ret = false;
    2340           0 :                 goto done;
    2341             :         }
    2342             : 
    2343           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    2344           2 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    2345             : 
    2346           2 :         torture_comment(tctx, "Set write time in the future on the file handle\n");
    2347           2 :         SET_INFO_FILE(finfo0, time(NULL) + 86400);
    2348           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    2349           2 :         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    2350             : 
    2351           2 :         torture_comment(tctx, "Set write time in the past on the file handle\n");
    2352           2 :         SET_INFO_FILE(finfo0, time(NULL) - 86400);
    2353           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    2354           2 :         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
    2355             : 
    2356             :         /* make sure the 2 second delay from the first write are canceled */
    2357           2 :         start = timeval_current();
    2358           2 :         end = timeval_add(&start, 15 * sec, 0);
    2359          28 :         while (!timeval_expired(&end)) {
    2360             : 
    2361             :                 /* get the times after the first write */
    2362          24 :                 GET_INFO_BOTH(finfo3,pinfo3);
    2363             : 
    2364          24 :                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
    2365           0 :                         double diff = timeval_elapsed(&start);
    2366           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2367             :                                         "(wrong!)\n",
    2368             :                                         diff);
    2369           0 :                         ret = false;
    2370           0 :                         break;
    2371             :                 }
    2372          24 :                 smb_msleep(1 * msec);
    2373             :         }
    2374             : 
    2375           2 :         GET_INFO_BOTH(finfo3,pinfo3);
    2376           2 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    2377           2 :         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    2378           2 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2379             :         }
    2380             : 
    2381             :         /* sure any further write doesn't update the write time */
    2382           2 :         start = timeval_current();
    2383           2 :         end = timeval_add(&start, 15 * sec, 0);
    2384          28 :         while (!timeval_expired(&end)) {
    2385             :                 /* do a write */
    2386          24 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2387          24 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2388          24 :                 if (written != 1) {
    2389           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2390           0 :                         ret = false;
    2391           0 :                         goto done;
    2392             :                 }
    2393             :                 /* get the times after the write */
    2394          24 :                 GET_INFO_BOTH(finfo4,pinfo4);
    2395             : 
    2396          24 :                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
    2397           0 :                         double diff = timeval_elapsed(&start);
    2398           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2399             :                                         "(wrong!)\n",
    2400             :                                         diff);
    2401           0 :                         ret = false;
    2402           0 :                         break;
    2403             :                 }
    2404          24 :                 smb_msleep(1 * msec);
    2405             :         }
    2406             : 
    2407           2 :         GET_INFO_BOTH(finfo4,pinfo4);
    2408           2 :         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
    2409           2 :         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
    2410           2 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2411             :         }
    2412             : 
    2413             :         /* sleep */
    2414           2 :         smb_msleep(5 * msec);
    2415             : 
    2416           2 :         GET_INFO_BOTH(finfo5,pinfo5);
    2417           2 :         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
    2418             : 
    2419             :         /*
    2420             :          * the close doesn't update the write time
    2421             :          */
    2422           2 :         torture_comment(tctx, "Close the file handle\n");
    2423           2 :         smbcli_close(cli->tree, fnum1);
    2424           2 :         fnum1 = -1;
    2425             : 
    2426           2 :         GET_INFO_PATH(pinfo6);
    2427           2 :         COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
    2428             : 
    2429           2 :         if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
    2430           2 :                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
    2431             :         }
    2432             : 
    2433           2 :  done:
    2434           2 :         if (fnum1 != -1)
    2435           0 :                 smbcli_close(cli->tree, fnum1);
    2436           2 :         smbcli_unlink(cli->tree, fname);
    2437           2 :         smbcli_deltree(cli->tree, BASEDIR);
    2438             : 
    2439           2 :         return ret;
    2440             : }
    2441             : 
    2442             : /*
    2443             :  * Show truncate writes and closes have no effect on updating times once a SETWRITETIME is done.
    2444             :  */
    2445             : 
    2446           2 : static bool test_delayed_write_update5b(struct torture_context *tctx,
    2447             :                                         struct smbcli_state *cli,
    2448             :                                         struct smbcli_state *cli2)
    2449             : {
    2450             :         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
    2451             :         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
    2452           2 :         const char *fname = BASEDIR "\\torture_fileb.txt";
    2453           2 :         int fnum1 = -1;
    2454           2 :         bool ret = true;
    2455             :         ssize_t written;
    2456             :         struct timeval start;
    2457             :         struct timeval end;
    2458           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2459           2 :         int normal_delay = 2000000;
    2460           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2461           2 :         int msec = 1000 * sec;
    2462             : 
    2463           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
    2464             : 
    2465           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2466             : 
    2467           2 :         torture_comment(tctx, "Open the file handle\n");
    2468           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2469           2 :         if (fnum1 == -1) {
    2470           0 :                 ret = false;
    2471           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    2472           0 :                 goto done;
    2473             :         }
    2474             : 
    2475           2 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2476           2 :         finfo0.basic_info.in.file.fnum = fnum1;
    2477           2 :         finfo1 = finfo0;
    2478           2 :         finfo2 = finfo0;
    2479           2 :         finfo3 = finfo0;
    2480           2 :         finfo4 = finfo0;
    2481           2 :         finfo5 = finfo0;
    2482           2 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2483           2 :         pinfo0.basic_info.in.file.path = fname;
    2484           2 :         pinfo1 = pinfo0;
    2485           2 :         pinfo2 = pinfo0;
    2486           2 :         pinfo3 = pinfo0;
    2487           2 :         pinfo4 = pinfo0;
    2488           2 :         pinfo5 = pinfo0;
    2489           2 :         pinfo6 = pinfo0;
    2490             : 
    2491             :         /* get the initial times */
    2492           2 :         GET_INFO_BOTH(finfo0,pinfo0);
    2493             : 
    2494             :         /* do a write */
    2495           2 :         torture_comment(tctx, "Do a write on the file handle\n");
    2496           2 :         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2497           2 :         if (written != 1) {
    2498           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2499           0 :                 ret = false;
    2500           0 :                 goto done;
    2501             :         }
    2502             : 
    2503           2 :         GET_INFO_BOTH(finfo1,pinfo1);
    2504           2 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    2505             : 
    2506           2 :         torture_comment(tctx, "Set write time in the future on the file handle\n");
    2507           2 :         SET_INFO_FILE(finfo0, time(NULL) + 86400);
    2508           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    2509           2 :         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    2510             : 
    2511           2 :         torture_comment(tctx, "Set write time in the past on the file handle\n");
    2512           2 :         SET_INFO_FILE(finfo0, time(NULL) - 86400);
    2513           2 :         GET_INFO_BOTH(finfo2,pinfo2);
    2514           2 :         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
    2515             : 
    2516             :         /* make sure the 2 second delay from the first write are canceled */
    2517           2 :         start = timeval_current();
    2518           2 :         end = timeval_add(&start, 15 * sec, 0);
    2519          28 :         while (!timeval_expired(&end)) {
    2520             : 
    2521             :                 /* get the times after the first write */
    2522          24 :                 GET_INFO_BOTH(finfo3,pinfo3);
    2523             : 
    2524          24 :                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
    2525           0 :                         double diff = timeval_elapsed(&start);
    2526           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2527             :                                         "(wrong!)\n",
    2528             :                                         diff);
    2529           0 :                         ret = false;
    2530           0 :                         break;
    2531             :                 }
    2532          24 :                 smb_msleep(1 * msec);
    2533             :         }
    2534             : 
    2535           2 :         GET_INFO_BOTH(finfo3,pinfo3);
    2536           2 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    2537           2 :         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    2538           2 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2539             :         }
    2540             : 
    2541             :         /* Do any further write (truncates) update the write time ? */
    2542           2 :         start = timeval_current();
    2543           2 :         end = timeval_add(&start, 15 * sec, 0);
    2544          28 :         while (!timeval_expired(&end)) {
    2545             :                 /* do a write */
    2546          24 :                 torture_comment(tctx, "Do a truncate write on the file handle\n");
    2547          24 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
    2548          24 :                 if (written != 0) {
    2549           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2550           0 :                         ret = false;
    2551           0 :                         goto done;
    2552             :                 }
    2553             :                 /* get the times after the write */
    2554          24 :                 GET_INFO_BOTH(finfo4,pinfo4);
    2555             : 
    2556          24 :                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
    2557           0 :                         double diff = timeval_elapsed(&start);
    2558           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2559             :                                         "(wrong!)\n",
    2560             :                                         diff);
    2561           0 :                         ret = false;
    2562           0 :                         break;
    2563             :                 }
    2564          24 :                 smb_msleep(1 * msec);
    2565             :         }
    2566             : 
    2567           2 :         GET_INFO_BOTH(finfo4,pinfo4);
    2568           2 :         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
    2569           2 :         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
    2570           2 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2571             :         }
    2572             : 
    2573             :         /* sleep */
    2574           2 :         smb_msleep(5 * msec);
    2575             : 
    2576           2 :         GET_INFO_BOTH(finfo5,pinfo5);
    2577           2 :         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
    2578             : 
    2579             :         /*
    2580             :          * the close doesn't update the write time
    2581             :          */
    2582           2 :         torture_comment(tctx, "Close the file handle\n");
    2583           2 :         smbcli_close(cli->tree, fnum1);
    2584           2 :         fnum1 = -1;
    2585             : 
    2586           2 :         GET_INFO_PATH(pinfo6);
    2587           2 :         COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
    2588             : 
    2589           2 :         if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
    2590           2 :                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
    2591             :         }
    2592             : 
    2593           2 :  done:
    2594           2 :         if (fnum1 != -1)
    2595           0 :                 smbcli_close(cli->tree, fnum1);
    2596           2 :         smbcli_unlink(cli->tree, fname);
    2597           2 :         smbcli_deltree(cli->tree, BASEDIR);
    2598             : 
    2599           2 :         return ret;
    2600             : }
    2601             : 
    2602             : /*
    2603             :  * Open 2 handles on a file. Write one one and then set the
    2604             :  * WRITE TIME explicitly on the other. Ensure the write time
    2605             :  * update is cancelled. Ensure the write time is updated to
    2606             :  * the close time when the non-explicit set handle is closed.
    2607             :  *
    2608             :  */
    2609             : 
    2610           2 : static bool test_delayed_write_update6(struct torture_context *tctx,
    2611             :                                        struct smbcli_state *cli,
    2612             :                                        struct smbcli_state *cli2)
    2613             : {
    2614             :         union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
    2615             :         union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
    2616           2 :         const char *fname = BASEDIR "\\torture_file6.txt";
    2617           2 :         int fnum1 = -1;
    2618           2 :         int fnum2 = -1;
    2619           2 :         bool ret = true;
    2620             :         ssize_t written;
    2621             :         struct timeval start;
    2622             :         struct timeval end;
    2623           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2624           2 :         int normal_delay = 2000000;
    2625           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2626           2 :         int msec = 1000 * sec;
    2627           2 :         bool first = true;
    2628             : 
    2629           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
    2630             : 
    2631           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2632           2 : again:
    2633           4 :         torture_comment(tctx, "Open the file handle\n");
    2634           4 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2635           4 :         if (fnum1 == -1) {
    2636           0 :                 ret = false;
    2637           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    2638           0 :                 goto done;
    2639             :         }
    2640             : 
    2641           4 :         if (fnum2 == -1) {
    2642           2 :                 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
    2643           2 :                 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2644           2 :                 if (fnum2 == -1) {
    2645           0 :                         ret = false;
    2646           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
    2647           0 :                         goto done;
    2648             :                 }
    2649             :         }
    2650             : 
    2651           4 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2652           4 :         finfo0.basic_info.in.file.fnum = fnum1;
    2653           4 :         finfo1 = finfo0;
    2654           4 :         finfo2 = finfo0;
    2655           4 :         finfo3 = finfo0;
    2656           4 :         finfo4 = finfo0;
    2657           4 :         finfo5 = finfo0;
    2658           4 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2659           4 :         pinfo0.basic_info.in.file.path = fname;
    2660           4 :         pinfo1 = pinfo0;
    2661           4 :         pinfo2 = pinfo0;
    2662           4 :         pinfo3 = pinfo0;
    2663           4 :         pinfo4 = pinfo0;
    2664           4 :         pinfo5 = pinfo0;
    2665           4 :         pinfo6 = pinfo0;
    2666           4 :         pinfo7 = pinfo0;
    2667             : 
    2668             :         /* get the initial times */
    2669           4 :         GET_INFO_BOTH(finfo0,pinfo0);
    2670             : 
    2671             :         /* do a write */
    2672           4 :         torture_comment(tctx, "Do a write on the file handle\n");
    2673           4 :         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2674           4 :         if (written != 1) {
    2675           0 :                 torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2676           0 :                 ret = false;
    2677           0 :                 goto done;
    2678             :         }
    2679             : 
    2680           4 :         GET_INFO_BOTH(finfo1,pinfo1);
    2681           4 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    2682             : 
    2683           4 :         torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
    2684           4 :         SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
    2685           4 :         GET_INFO_BOTH(finfo2,pinfo2);
    2686           4 :         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    2687             : 
    2688           4 :         torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
    2689           4 :         SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
    2690           4 :         GET_INFO_BOTH(finfo2,pinfo2);
    2691           4 :         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
    2692             : 
    2693             :         /* make sure the 2 second delay from the first write are canceled */
    2694           4 :         start = timeval_current();
    2695           4 :         end = timeval_add(&start, 10 * sec, 0);
    2696          40 :         while (!timeval_expired(&end)) {
    2697             : 
    2698             :                 /* get the times after the first write */
    2699          32 :                 GET_INFO_BOTH(finfo3,pinfo3);
    2700             : 
    2701          32 :                 if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
    2702           0 :                         double diff = timeval_elapsed(&start);
    2703           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2704             :                                         "(wrong!)\n",
    2705             :                                         diff);
    2706           0 :                         ret = false;
    2707           0 :                         break;
    2708             :                 }
    2709          32 :                 smb_msleep(1 * msec);
    2710             :         }
    2711             : 
    2712           4 :         GET_INFO_BOTH(finfo3,pinfo3);
    2713           4 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    2714           4 :         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    2715           4 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2716             :         }
    2717             : 
    2718             :         /* sure any further write doesn't update the write time */
    2719           4 :         start = timeval_current();
    2720           4 :         end = timeval_add(&start, 10 * sec, 0);
    2721          40 :         while (!timeval_expired(&end)) {
    2722             :                 /* do a write */
    2723          32 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2724          32 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2725          32 :                 if (written != 1) {
    2726           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2727           0 :                         ret = false;
    2728           0 :                         goto done;
    2729             :                 }
    2730             :                 /* get the times after the write */
    2731          32 :                 GET_INFO_BOTH(finfo4,pinfo4);
    2732             : 
    2733          32 :                 if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
    2734           0 :                         double diff = timeval_elapsed(&start);
    2735           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2736             :                                         "(wrong!)\n",
    2737             :                                         diff);
    2738           0 :                         ret = false;
    2739           0 :                         break;
    2740             :                 }
    2741          32 :                 smb_msleep(1 * msec);
    2742             :         }
    2743             : 
    2744           4 :         GET_INFO_BOTH(finfo4,pinfo4);
    2745           4 :         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
    2746           4 :         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
    2747           4 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2748             :         }
    2749             : 
    2750             :         /* sleep */
    2751           4 :         smb_msleep(5 * msec);
    2752             : 
    2753           4 :         GET_INFO_BOTH(finfo5,pinfo5);
    2754           4 :         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
    2755             : 
    2756             :         /*
    2757             :          * the close updates the write time to the time of the close
    2758             :          * as the write time was set on the 2nd handle
    2759             :          */
    2760           4 :         torture_comment(tctx, "Close the file handle\n");
    2761           4 :         smbcli_close(cli->tree, fnum1);
    2762           4 :         fnum1 = -1;
    2763             : 
    2764           4 :         GET_INFO_PATH(pinfo6);
    2765           4 :         COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
    2766             : 
    2767           4 :         if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
    2768           4 :                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
    2769             :         }
    2770             : 
    2771             :         /* See what the second write handle thinks the time is ? */
    2772           4 :         finfo5.basic_info.in.file.fnum = fnum2;
    2773           4 :         GET_INFO_FILE2(finfo5);
    2774           4 :         COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
    2775             : 
    2776             :         /* See if we have lost the sticky write time on handle2 */
    2777           4 :         smb_msleep(3 * msec);
    2778           4 :         torture_comment(tctx, "Have we lost the sticky write time ?\n");
    2779             : 
    2780             :         /* Make sure any further normal write doesn't update the write time */
    2781           4 :         start = timeval_current();
    2782           4 :         end = timeval_add(&start, 10 * sec, 0);
    2783          40 :         while (!timeval_expired(&end)) {
    2784             :                 /* do a write */
    2785          32 :                 torture_comment(tctx, "Do a write on the second file handle\n");
    2786          32 :                 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
    2787          32 :                 if (written != 1) {
    2788           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2789           0 :                         ret = false;
    2790           0 :                         goto done;
    2791             :                 }
    2792             :                 /* get the times after the write */
    2793          32 :                 GET_INFO_FILE2(finfo5);
    2794          32 :                 GET_INFO_PATH(pinfo6);
    2795             : 
    2796          32 :                 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
    2797           0 :                         double diff = timeval_elapsed(&start);
    2798           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2799             :                                         "(wrong!)\n",
    2800             :                                         diff);
    2801           0 :                         ret = false;
    2802           0 :                         break;
    2803             :                 }
    2804          32 :                 smb_msleep(1 * msec);
    2805             :         }
    2806             : 
    2807             :         /* What about a truncate write ? */
    2808           4 :         start = timeval_current();
    2809           4 :         end = timeval_add(&start, 10 * sec, 0);
    2810          40 :         while (!timeval_expired(&end)) {
    2811             :                 /* do a write */
    2812          32 :                 torture_comment(tctx, "Do a truncate write on the second file handle\n");
    2813          32 :                 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
    2814          32 :                 if (written != 0) {
    2815           0 :                         torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
    2816           0 :                         ret = false;
    2817           0 :                         goto done;
    2818             :                 }
    2819             :                 /* get the times after the write */
    2820          32 :                 GET_INFO_FILE2(finfo5);
    2821          32 :                 GET_INFO_PATH(pinfo6);
    2822             : 
    2823          32 :                 if (finfo5.basic_info.out.write_time > pinfo6.basic_info.out.write_time) {
    2824           0 :                         double diff = timeval_elapsed(&start);
    2825           0 :                         torture_result(tctx, TORTURE_FAIL, "Server updated write_time after %.2f seconds "
    2826             :                                         "(wrong!)\n",
    2827             :                                         diff);
    2828           0 :                         ret = false;
    2829           0 :                         break;
    2830             :                 }
    2831          32 :                 smb_msleep(1 * msec);
    2832             :         }
    2833             : 
    2834             : 
    2835             :         /* keep the 2nd handle open and rerun tests */
    2836           4 :         if (first) {
    2837           2 :                 first = false;
    2838           2 :                 goto again;
    2839             :         }
    2840             : 
    2841             :         /*
    2842             :          * closing the 2nd handle will cause no write time update
    2843             :          * as the write time was explicit set on this handle
    2844             :          */
    2845           2 :         torture_comment(tctx, "Close the 2nd file handle\n");
    2846           2 :         smbcli_close(cli2->tree, fnum2);
    2847           2 :         fnum2 = -1;
    2848             : 
    2849           2 :         GET_INFO_PATH(pinfo7);
    2850           2 :         COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
    2851             : 
    2852           2 :         if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
    2853           2 :                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
    2854             :         }
    2855             : 
    2856           2 :  done:
    2857           2 :         if (fnum1 != -1)
    2858           0 :                 smbcli_close(cli->tree, fnum1);
    2859           2 :         if (fnum2 != -1)
    2860           0 :                 smbcli_close(cli2->tree, fnum2);
    2861           2 :         smbcli_unlink(cli->tree, fname);
    2862           2 :         smbcli_deltree(cli->tree, BASEDIR);
    2863             : 
    2864           2 :         return ret;
    2865             : }
    2866             : 
    2867           2 : static bool test_delayed_write_update7(struct torture_context *tctx, struct smbcli_state *cli)
    2868             : {
    2869             :         union smb_open open_parms;
    2870             :         union smb_fileinfo finfo1, finfo2, finfo3;
    2871           2 :         const char *fname = BASEDIR "\\torture_file7.txt";
    2872             :         NTSTATUS status;
    2873           2 :         int fnum1 = -1;
    2874           2 :         bool ret = true;
    2875             :         TALLOC_CTX *mem_ctx; 
    2876             : 
    2877           2 :         torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
    2878             : 
    2879           2 :         mem_ctx = talloc_init("test_delayed_write_update7");
    2880           2 :         if (!mem_ctx) return false;
    2881             : 
    2882           2 :         ZERO_STRUCT(finfo1);
    2883           2 :         ZERO_STRUCT(finfo2);
    2884           2 :         ZERO_STRUCT(finfo3);
    2885           2 :         ZERO_STRUCT(open_parms);
    2886             : 
    2887           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2888             : 
    2889             :         /* Create the file. */
    2890           2 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2891           2 :         if (fnum1 == -1) {
    2892           0 :                 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
    2893           0 :                 return false;
    2894             :         }
    2895             : 
    2896           2 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2897           2 :         finfo1.basic_info.in.file.fnum = fnum1;
    2898           2 :         finfo2 = finfo1;
    2899           2 :         finfo3 = finfo1;
    2900             : 
    2901             :         /* Get the initial timestamps. */
    2902           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
    2903             : 
    2904           2 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
    2905             :         
    2906             :         /* Set the pending write time to a value with ns. */
    2907           2 :         SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
    2908             : 
    2909             :         /* Get the current pending write time by fnum. */
    2910           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
    2911             : 
    2912           2 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
    2913             : 
    2914             :         /* Ensure the time is actually different. */
    2915           2 :         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    2916           0 :                 torture_result(tctx, TORTURE_FAIL,
    2917             :                         "setfileinfo time matches original fileinfo time");
    2918           0 :                 ret = false;
    2919             :         }
    2920             : 
    2921             :         /* Get the current pending write time by path. */
    2922           2 :         finfo3.basic_info.in.file.path = fname;
    2923           2 :         status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
    2924             : 
    2925           2 :         if (finfo2.basic_info.out.write_time != finfo3.basic_info.out.write_time) {
    2926           0 :                 torture_result(tctx, TORTURE_FAIL, 
    2927             :                         "qpathinfo time doesn't match fileinfo time");
    2928           0 :                 ret = false;
    2929             :         }
    2930             : 
    2931             :         /* Now close the file. Re-open and check that the write
    2932             :            time is identical to the one we wrote. */
    2933             : 
    2934           2 :         smbcli_close(cli->tree, fnum1);
    2935             : 
    2936           2 :         open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
    2937           2 :         open_parms.ntcreatex.in.flags = 0;
    2938           2 :         open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
    2939           2 :         open_parms.ntcreatex.in.file_attr = 0;
    2940           2 :         open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
    2941             :                                         NTCREATEX_SHARE_ACCESS_READ|
    2942             :                                         NTCREATEX_SHARE_ACCESS_WRITE;
    2943           2 :         open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    2944           2 :         open_parms.ntcreatex.in.create_options = 0;
    2945           2 :         open_parms.ntcreatex.in.fname = fname;
    2946             : 
    2947           2 :         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
    2948           2 :         talloc_free(mem_ctx);
    2949             : 
    2950           2 :         if (!NT_STATUS_IS_OK(status)) {
    2951           0 :                 torture_result(tctx, TORTURE_FAIL,
    2952             :                         "setfileinfo time matches original fileinfo time");
    2953           0 :                 ret = false;
    2954             :         }
    2955             : 
    2956           2 :         fnum1 = open_parms.ntcreatex.out.file.fnum;
    2957             : 
    2958             :         /* Check the returned time matches. */
    2959           2 :         if (open_parms.ntcreatex.out.write_time != finfo2.basic_info.out.write_time) {
    2960           0 :                 torture_result(tctx, TORTURE_FAIL,
    2961             :                         "final open time does not match set time");
    2962           0 :                 ret = false;
    2963             :         }
    2964             : 
    2965           4 :  done:
    2966             : 
    2967           2 :         smbcli_close(cli->tree, fnum1);
    2968             : 
    2969           2 :         smbcli_unlink(cli->tree, fname);
    2970           2 :         smbcli_deltree(cli->tree, BASEDIR);
    2971           2 :         return ret;
    2972             : }
    2973             : 
    2974             : /*
    2975             :    Test if creating a file in a directory with an open handle updates the
    2976             :    write timestamp (it should).
    2977             : */
    2978           2 : static bool test_directory_update8(struct torture_context *tctx, struct smbcli_state *cli)
    2979             : {
    2980             :         union smb_fileinfo dir_info1, dir_info2;
    2981             :         union smb_open open_parms;
    2982           2 :         const char *fname = BASEDIR "\\torture_file.txt";
    2983             :         NTSTATUS status;
    2984           2 :         int fnum1 = -1;
    2985           2 :         int fnum2 = -1;
    2986           2 :         bool ret = true;
    2987           2 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2988           2 :         int normal_delay = 2000000;
    2989           2 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2990           2 :         int msec = 1000 * sec;
    2991           2 :         TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
    2992             : 
    2993           2 :         if (!mem_ctx) return false;
    2994             : 
    2995           2 :         torture_comment(tctx, "\nRunning test directory write update\n");
    2996             : 
    2997           2 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2998             : 
    2999             :         /* Open a handle on the directory - and leave it open. */
    3000           2 :         ZERO_STRUCT(open_parms);
    3001           2 :         open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
    3002           2 :         open_parms.ntcreatex.in.flags = 0;
    3003           2 :         open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
    3004           2 :         open_parms.ntcreatex.in.file_attr = 0;
    3005           2 :         open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
    3006             :                                         NTCREATEX_SHARE_ACCESS_READ|
    3007             :                                         NTCREATEX_SHARE_ACCESS_WRITE;
    3008           2 :         open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    3009           2 :         open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    3010           2 :         open_parms.ntcreatex.in.fname = BASEDIR;
    3011             : 
    3012           2 :         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
    3013           2 :         talloc_free(mem_ctx);
    3014             : 
    3015           2 :         if (!NT_STATUS_IS_OK(status)) {
    3016           0 :                 torture_result(tctx, TORTURE_FAIL,
    3017             :                         "failed to open directory handle");
    3018           0 :                 ret = false;
    3019           0 :                 goto done;
    3020             :         }
    3021             : 
    3022           2 :         fnum1 = open_parms.ntcreatex.out.file.fnum;
    3023             : 
    3024             :         /* Store the returned write time. */
    3025           2 :         ZERO_STRUCT(dir_info1);
    3026           2 :         dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
    3027             : 
    3028           2 :         torture_comment(tctx, "Initial write time %s\n",
    3029             :                nt_time_string(tctx, dir_info1.basic_info.out.write_time));
    3030             : 
    3031             :         /* sleep */
    3032           2 :         smb_msleep(3 * msec);
    3033             : 
    3034             :         /* Now create a file within the directory. */
    3035           2 :         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    3036           2 :         if (fnum2 == -1) {
    3037           0 :                 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
    3038           0 :                 ret = false;
    3039           0 :                 goto done;
    3040             :         }
    3041           2 :         smbcli_close(cli->tree, fnum2);
    3042             : 
    3043             :         /* Read the directory write time again. */
    3044           2 :         ZERO_STRUCT(dir_info2);
    3045           2 :         dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    3046           2 :         dir_info2.basic_info.in.file.fnum = fnum1;
    3047             : 
    3048           2 :         status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
    3049             : 
    3050           2 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
    3051             : 
    3052             :         /* Ensure it's been incremented. */
    3053           2 :         COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
    3054             : 
    3055           2 :         torture_comment(tctx, "Updated write time %s\n",
    3056             :                nt_time_string(tctx, dir_info2.basic_info.out.write_time));
    3057             : 
    3058           2 :  done:
    3059             : 
    3060           2 :         if (fnum1 != -1)
    3061           2 :                 smbcli_close(cli->tree, fnum1);
    3062           2 :         smbcli_unlink(cli->tree, fname);
    3063           2 :         smbcli_deltree(cli->tree, BASEDIR);
    3064             : 
    3065           2 :         return ret;
    3066             : }
    3067             : 
    3068             : /*
    3069             :    testing of delayed update of write_time
    3070             : */
    3071        2355 : struct torture_suite *torture_delay_write(TALLOC_CTX *ctx)
    3072             : {
    3073        2355 :         struct torture_suite *suite = torture_suite_create(ctx, "delaywrite");
    3074             : 
    3075        2355 :         torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
    3076        2355 :         torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
    3077        2355 :         torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
    3078        2355 :         torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
    3079        2355 :         torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
    3080        2355 :         torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
    3081        2355 :         torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
    3082        2355 :         torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
    3083        2355 :         torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
    3084        2355 :         torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
    3085        2355 :         torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
    3086        2355 :         torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
    3087        2355 :         torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
    3088        2355 :         torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
    3089        2355 :         torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
    3090        2355 :         torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
    3091        2355 :         torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);
    3092             : 
    3093        2355 :         return suite;
    3094             : }

Generated by: LCOV version 1.13