LCOV - code coverage report
Current view: top level - source4/torture/basic - delaywrite.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 20 1587 1.3 %
Date: 2024-06-13 04:01:37 Functions: 1 18 5.6 %

          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           0 : static bool test_delayed_write_update(struct torture_context *tctx, struct smbcli_state *cli)
      37             : {
      38             :         union smb_fileinfo finfo1, finfo2;
      39           0 :         const char *fname = BASEDIR "\\torture_file.txt";
      40             :         NTSTATUS status;
      41           0 :         int fnum1 = -1;
      42           0 :         bool ret = true;
      43             :         ssize_t written;
      44             :         struct timeval start;
      45             :         struct timeval end;
      46           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
      47           0 :         int normal_delay = 2000000;
      48           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
      49           0 :         int msec = 1000 * sec;
      50             : 
      51           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update\n");
      52             : 
      53           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
      54             : 
      55           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
      56           0 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
      57             :                                      "Failed to open %s", fname));
      58             : 
      59           0 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
      60           0 :         finfo1.basic_info.in.file.fnum = fnum1;
      61           0 :         finfo2 = finfo1;
      62             : 
      63           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
      64           0 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
      65             : 
      66           0 :         torture_comment(tctx, "Initial write time %s\n",
      67             :                         nt_time_string(tctx, finfo1.basic_info.out.write_time));
      68             : 
      69           0 :         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
      70           0 :         torture_assert_int_equal(tctx, written, 1,
      71             :                                  "unexpected number of bytes written");
      72             : 
      73           0 :         start = timeval_current();
      74           0 :         end = timeval_add(&start, (120 * sec), 0);
      75           0 :         while (!timeval_expired(&end)) {
      76           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
      77             : 
      78           0 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
      79             : 
      80           0 :                 torture_comment(tctx, "write time %s\n",
      81             :                         nt_time_string(tctx, finfo2.basic_info.out.write_time));
      82             : 
      83           0 :                 if (finfo1.basic_info.out.write_time !=
      84           0 :                     finfo2.basic_info.out.write_time)
      85             :                 {
      86           0 :                         double diff = timeval_elapsed(&start);
      87             : 
      88           0 :                         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           0 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds (correct)\n",
      96             :                                         diff);
      97           0 :                         break;
      98             :                 }
      99           0 :                 fflush(stdout);
     100           0 :                 smb_msleep(1 * msec);
     101             :         }
     102             : 
     103           0 :         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           0 :         if (fnum1 != -1)
     110           0 :                 smbcli_close(cli->tree, fnum1);
     111           0 :         smbcli_unlink(cli->tree, fname);
     112           0 :         smbcli_deltree(cli->tree, BASEDIR);
     113             : 
     114           0 :         return ret;
     115             : }
     116             : 
     117           0 : static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
     118             : {
     119             :         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
     120           0 :         const char *fname = BASEDIR "\\torture_file1.txt";
     121             :         NTSTATUS status;
     122           0 :         int fnum1 = -1;
     123           0 :         bool ret = true;
     124             :         ssize_t written;
     125             :         struct timeval start;
     126             :         struct timeval end;
     127           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     128           0 :         int normal_delay = 2000000;
     129           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
     130           0 :         int msec = 1000 * sec;
     131             :         char buf[2048];
     132             :         bool first;
     133             :         bool updated;
     134             : 
     135           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
     136             : 
     137           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     138             : 
     139           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     140           0 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
     141             :                                      "Failed to open %s", fname));
     142             : 
     143           0 :         memset(buf, 'x', 2048);
     144           0 :         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           0 :         smb_msleep(3 * msec);
     149             : 
     150           0 :         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
     151           0 :         finfo1.all_info.in.file.fnum = fnum1;
     152           0 :         finfo2 = finfo1;
     153           0 :         finfo3 = finfo1;
     154           0 :         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
     155           0 :         pinfo4.all_info.in.file.path = fname;
     156             : 
     157           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     158             : 
     159           0 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     160             : 
     161           0 :         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
     162             :                                  "file size not as expected after write(2048)");
     163             : 
     164           0 :         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           0 :         smb_msleep(3 * msec);
     170             : 
     171             :         /* Do a zero length SMBwrite call to truncate. */
     172           0 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
     173           0 :         torture_assert_int_equal(tctx, written, 0,
     174             :                                  "unexpected number of bytes written");
     175             : 
     176           0 :         start = timeval_current();
     177           0 :         end = timeval_add(&start, (120 * sec), 0);
     178           0 :         first = true;
     179           0 :         updated = false;
     180           0 :         while (!timeval_expired(&end)) {
     181           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     182             : 
     183           0 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     184             : 
     185           0 :                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 1024,
     186             :                                          "file not truncated to expected size "
     187             :                                          "(1024)");
     188             : 
     189           0 :                 torture_comment(tctx, "write time %s\n",
     190             :                         nt_time_string(tctx, finfo2.all_info.out.write_time));
     191             : 
     192           0 :                 if (finfo1.all_info.out.write_time !=
     193           0 :                     finfo2.all_info.out.write_time)
     194             :                 {
     195           0 :                         updated = true;
     196           0 :                         break;
     197             :                 }
     198             : 
     199           0 :                 fflush(stdout);
     200           0 :                 smb_msleep(1 * msec);
     201           0 :                 first = false;
     202             :         }
     203             : 
     204           0 :         torture_assert(tctx, updated,
     205             :                        "Server did not update write time within 120 seconds");
     206             : 
     207           0 :         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           0 :         torture_comment(tctx, "Server updated write time immediately. Good!\n");
     212             : 
     213           0 :         fflush(stdout);
     214           0 :         smb_msleep(2 * msec);
     215             : 
     216             :         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
     217           0 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
     218           0 :         torture_assert_int_equal(tctx, written, 1,
     219             :                                  "unexpected number of bytes written");
     220             : 
     221           0 :         start = timeval_current();
     222           0 :         end = timeval_add(&start, (10*sec), 0);
     223           0 :         while (!timeval_expired(&end)) {
     224           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
     225             : 
     226           0 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     227             : 
     228           0 :                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1024,
     229             :                                          "file not truncated to expected size "
     230             :                                          "(1024)");
     231             : 
     232           0 :                 torture_comment(tctx, "write time %s\n",
     233             :                         nt_time_string(tctx, finfo3.all_info.out.write_time));
     234             : 
     235           0 :                 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           0 :                 fflush(stdout);
     244           0 :                 smb_msleep(1 * msec);
     245             :         }
     246             : 
     247           0 :         torture_comment(tctx, "Server did not update write time within 10 "
     248             :                         "seconds. Good!\n");
     249             : 
     250           0 :         fflush(stdout);
     251           0 :         smb_msleep(2 * msec);
     252             : 
     253             :         /* the close should trigger an write time update */
     254           0 :         smbcli_close(cli->tree, fnum1);
     255           0 :         fnum1 = -1;
     256             : 
     257           0 :         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
     258           0 :         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
     259             : 
     260           0 :         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           0 :         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           0 :         torture_comment(tctx, "Server updated write time on close (correct)\n");
     271             : 
     272           0 :         if (fnum1 != -1)
     273           0 :                 smbcli_close(cli->tree, fnum1);
     274           0 :         smbcli_unlink(cli->tree, fname);
     275           0 :         smbcli_deltree(cli->tree, BASEDIR);
     276             : 
     277           0 :         return ret;
     278             : }
     279             : 
     280             : /* Updating with a SMBwrite of zero length
     281             :  * changes the write time immediately - even on expand. */
     282             : 
     283           0 : static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
     284             : {
     285             :         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
     286           0 :         const char *fname = BASEDIR "\\torture_file1a.txt";
     287             :         NTSTATUS status;
     288           0 :         int fnum1 = -1;
     289           0 :         bool ret = true;
     290             :         ssize_t written;
     291             :         struct timeval start;
     292             :         struct timeval end;
     293           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     294           0 :         int normal_delay = 2000000;
     295           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
     296           0 :         int msec = 1000 * sec;
     297             :         char buf[2048];
     298             :         bool first;
     299             :         bool updated;
     300             : 
     301           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
     302             : 
     303           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     304             : 
     305           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     306           0 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
     307             :                                      "Failed to open %s", fname));
     308             : 
     309           0 :         memset(buf, 'x', 2048);
     310           0 :         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           0 :         smb_msleep(3 * msec);
     315             : 
     316           0 :         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
     317           0 :         finfo1.all_info.in.file.fnum = fnum1;
     318           0 :         finfo2 = finfo1;
     319           0 :         finfo3 = finfo1;
     320           0 :         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
     321           0 :         pinfo4.all_info.in.file.path = fname;
     322             : 
     323           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     324             : 
     325           0 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     326             : 
     327           0 :         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
     328             :                                  "file size not as expected after write(2048)");
     329             : 
     330           0 :         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           0 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
     335             : 
     336           0 :         torture_assert_int_equal(tctx, written, 0,
     337             :                                  "unexpected number of bytes written");
     338             : 
     339           0 :         start = timeval_current();
     340           0 :         end = timeval_add(&start, (120*sec), 0);
     341           0 :         first = true;
     342           0 :         updated = false;
     343           0 :         while (!timeval_expired(&end)) {
     344           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     345             : 
     346           0 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     347             : 
     348           0 :                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
     349             :                                          "file not truncated to expected size "
     350             :                                          "(10240)");
     351             : 
     352           0 :                 torture_comment(tctx, "write time %s\n",
     353             :                         nt_time_string(tctx, finfo2.all_info.out.write_time));
     354             : 
     355           0 :                 if (finfo1.all_info.out.write_time !=
     356           0 :                     finfo2.all_info.out.write_time)
     357             :                 {
     358           0 :                         updated = true;
     359           0 :                         break;
     360             :                 }
     361             : 
     362           0 :                 fflush(stdout);
     363           0 :                 smb_msleep(1 * msec);
     364           0 :                 first = false;
     365             :         }
     366             : 
     367           0 :         torture_assert(tctx, updated,
     368             :                        "Server did not update write time within 120 seconds");
     369             : 
     370           0 :         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           0 :         torture_comment(tctx, "Server updated write time immediately. Good!\n");
     375             : 
     376           0 :         fflush(stdout);
     377           0 :         smb_msleep(2 * msec);
     378             : 
     379             :         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
     380           0 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
     381             : 
     382           0 :         torture_assert_int_equal(tctx, written, 1,
     383             :                                  "unexpected number of bytes written");
     384             : 
     385           0 :         start = timeval_current();
     386           0 :         end = timeval_add(&start, (10*sec), 0);
     387           0 :         while (!timeval_expired(&end)) {
     388           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
     389             : 
     390           0 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     391             : 
     392           0 :                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
     393             :                                          "file not truncated to expected size "
     394             :                                          "(10240)");
     395             : 
     396           0 :                 torture_comment(tctx, "write time %s\n",
     397             :                         nt_time_string(tctx, finfo3.all_info.out.write_time));
     398             : 
     399           0 :                 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           0 :                 fflush(stdout);
     408           0 :                 smb_msleep(1 * msec);
     409             :         }
     410             : 
     411           0 :         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           0 :         smbcli_close(cli->tree, fnum1);
     416           0 :         fnum1 = -1;
     417             : 
     418           0 :         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
     419           0 :         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
     420             : 
     421           0 :         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           0 :         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           0 :         torture_comment(tctx, "Server updated write time on close (correct)\n");
     432             : 
     433           0 :         if (fnum1 != -1)
     434           0 :                 smbcli_close(cli->tree, fnum1);
     435           0 :         smbcli_unlink(cli->tree, fname);
     436           0 :         smbcli_deltree(cli->tree, BASEDIR);
     437             : 
     438           0 :         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           0 : static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
     445             : {
     446             :         union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
     447           0 :         const char *fname = BASEDIR "\\torture_file1b.txt";
     448             :         NTSTATUS status;
     449           0 :         int fnum1 = -1;
     450           0 :         bool ret = true;
     451             :         ssize_t written;
     452             :         struct timeval start;
     453             :         struct timeval end;
     454           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     455           0 :         int normal_delay = 2000000;
     456           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
     457           0 :         int msec = 1000 * sec;
     458             :         char buf[2048];
     459             :         bool first;
     460             :         bool updated;
     461             : 
     462           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
     463             : 
     464           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     465             : 
     466           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     467           0 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
     468             :                                      "Failed to open %s", fname));
     469             : 
     470           0 :         memset(buf, 'x', 2048);
     471           0 :         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           0 :         smb_msleep(3 * msec);
     476             : 
     477           0 :         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
     478           0 :         finfo1.all_info.in.file.fnum = fnum1;
     479           0 :         finfo2 = finfo1;
     480           0 :         finfo3 = finfo1;
     481           0 :         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
     482           0 :         pinfo4.all_info.in.file.path = fname;
     483             : 
     484           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     485             : 
     486           0 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     487             : 
     488           0 :         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
     489             :                                  "file size not as expected after write(2048)");
     490             : 
     491           0 :         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           0 :         status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
     496             : 
     497           0 :         torture_assert_ntstatus_ok(tctx, status, "SET_END_OF_FILE failed");
     498             : 
     499           0 :         start = timeval_current();
     500           0 :         end = timeval_add(&start, (120*sec), 0);
     501           0 :         first = true;
     502           0 :         updated = false;
     503           0 :         while (!timeval_expired(&end)) {
     504           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     505             : 
     506           0 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     507             : 
     508           0 :                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 10240,
     509             :                                          "file not truncated to expected size "
     510             :                                          "(10240)");
     511             : 
     512           0 :                 torture_comment(tctx, "write time %s\n",
     513             :                         nt_time_string(tctx, finfo2.all_info.out.write_time));
     514             : 
     515           0 :                 if (finfo1.all_info.out.write_time !=
     516           0 :                     finfo2.all_info.out.write_time)
     517             :                 {
     518           0 :                         updated = true;
     519           0 :                         break;
     520             :                 }
     521             : 
     522           0 :                 fflush(stdout);
     523           0 :                 smb_msleep(1 * msec);
     524           0 :                 first = false;
     525             :         }
     526             : 
     527           0 :         torture_assert(tctx, updated,
     528             :                        "Server did not update write time within 120 seconds");
     529             : 
     530           0 :         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           0 :         torture_comment(tctx, "Server updated write time immediately. Good!\n");
     535             : 
     536           0 :         fflush(stdout);
     537           0 :         smb_msleep(2 * msec);
     538             : 
     539             :         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
     540           0 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
     541             : 
     542           0 :         torture_assert_int_equal(tctx, written, 1,
     543             :                                  "unexpected number of bytes written");
     544             : 
     545           0 :         start = timeval_current();
     546           0 :         end = timeval_add(&start, (10*sec), 0);
     547           0 :         while (!timeval_expired(&end)) {
     548           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
     549             : 
     550           0 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     551             : 
     552           0 :                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 10240,
     553             :                                          "file not truncated to expected size "
     554             :                                          "(10240)");
     555             : 
     556           0 :                 torture_comment(tctx, "write time %s\n",
     557             :                         nt_time_string(tctx, finfo3.all_info.out.write_time));
     558             : 
     559           0 :                 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           0 :                 fflush(stdout);
     568           0 :                 smb_msleep(1 * msec);
     569             :         }
     570             : 
     571           0 :         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           0 :         smbcli_close(cli->tree, fnum1);
     576           0 :         fnum1 = -1;
     577             : 
     578           0 :         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
     579           0 :         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
     580             : 
     581           0 :         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           0 :         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           0 :         torture_comment(tctx, "Server updated write time on close (correct)\n");
     592             : 
     593           0 :         if (fnum1 != -1)
     594           0 :                 smbcli_close(cli->tree, fnum1);
     595           0 :         smbcli_unlink(cli->tree, fname);
     596           0 :         smbcli_deltree(cli->tree, BASEDIR);
     597             : 
     598           0 :         return ret;
     599             : }
     600             : 
     601             : /* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
     602             : 
     603           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file1c.txt";
     608             :         NTSTATUS status;
     609           0 :         int fnum1 = -1;
     610           0 :         bool ret = true;
     611             :         ssize_t written;
     612             :         struct timeval start;
     613             :         struct timeval end;
     614           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     615           0 :         int normal_delay = 2000000;
     616           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
     617           0 :         int msec = 1000 * sec;
     618             :         char buf[2048];
     619             :         bool first;
     620             :         bool updated;
     621             : 
     622           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
     623             : 
     624           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     625             : 
     626           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     627           0 :         torture_assert_int_not_equal(tctx, fnum1, -1, talloc_asprintf(tctx,
     628             :                                      "Failed to open %s", fname));
     629             : 
     630           0 :         memset(buf, 'x', 2048);
     631           0 :         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           0 :         smb_msleep(3 * msec);
     636             : 
     637           0 :         finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
     638           0 :         finfo1.all_info.in.file.fnum = fnum1;
     639           0 :         finfo2 = finfo1;
     640           0 :         finfo3 = finfo1;
     641           0 :         pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
     642           0 :         pinfo4.all_info.in.file.path = fname;
     643             : 
     644           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     645             : 
     646           0 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     647             : 
     648           0 :         torture_assert_u64_equal(tctx, finfo1.all_info.out.size, 2048,
     649             :                                  "file size not as expected after write(2048)");
     650             : 
     651           0 :         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           0 :         parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
     656           0 :         parms.allocation_info.in.file.fnum = fnum1;
     657           0 :         parms.allocation_info.in.alloc_size = 0;
     658             : 
     659           0 :         status = smb_raw_setfileinfo(cli->tree, &parms);
     660             : 
     661           0 :         torture_assert_ntstatus_ok(tctx, status,
     662             :                                    "RAW_SFILEINFO_ALLOCATION_INFO failed");
     663             : 
     664           0 :         start = timeval_current();
     665           0 :         end = timeval_add(&start, (120*sec), 0);
     666           0 :         first = true;
     667           0 :         updated = false;
     668           0 :         while (!timeval_expired(&end)) {
     669           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     670             : 
     671           0 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     672             : 
     673           0 :                 torture_assert_u64_equal(tctx, finfo2.all_info.out.size, 0,
     674             :                                          "file not truncated to expected size "
     675             :                                          "(0)");
     676             : 
     677           0 :                 torture_comment(tctx, "write time %s\n",
     678             :                         nt_time_string(tctx, finfo2.all_info.out.write_time));
     679             : 
     680           0 :                 if (finfo1.all_info.out.write_time !=
     681           0 :                     finfo2.all_info.out.write_time)
     682             :                 {
     683           0 :                         updated = true;
     684           0 :                         break;
     685             :                 }
     686             : 
     687           0 :                 fflush(stdout);
     688           0 :                 smb_msleep(1 * msec);
     689           0 :                 first = false;
     690             :         }
     691             : 
     692           0 :         torture_assert(tctx, updated,
     693             :                        "Server did not update write time within 120 seconds");
     694             : 
     695           0 :         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           0 :         torture_comment(tctx, "Server updated write time immediately. Good!\n");
     700             : 
     701           0 :         fflush(stdout);
     702           0 :         smb_msleep(2 * msec);
     703             : 
     704             :         /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
     705           0 :         written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
     706           0 :         torture_assert_int_equal(tctx, written, 1,
     707             :                                  "Unexpected number of bytes written");
     708             : 
     709           0 :         start = timeval_current();
     710           0 :         end = timeval_add(&start, (10*sec), 0);
     711           0 :         while (!timeval_expired(&end)) {
     712           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
     713             : 
     714           0 :                 torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     715             : 
     716           0 :                 torture_assert_u64_equal(tctx, finfo3.all_info.out.size, 1,
     717             :                                          "file not expaneded");
     718             : 
     719           0 :                 torture_comment(tctx, "write time %s\n",
     720             :                         nt_time_string(tctx, finfo3.all_info.out.write_time));
     721             : 
     722           0 :                 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           0 :                 fflush(stdout);
     731           0 :                 smb_msleep(1 * msec);
     732             :         }
     733             : 
     734           0 :         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           0 :         smbcli_close(cli->tree, fnum1);
     739           0 :         fnum1 = -1;
     740             : 
     741           0 :         status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
     742           0 :         torture_assert_ntstatus_ok(tctx, status, "pathinfo failed");
     743             : 
     744           0 :         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           0 :         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           0 :         if (fnum1 != -1)
     755           0 :                 smbcli_close(cli->tree, fnum1);
     756           0 :         smbcli_unlink(cli->tree, fname);
     757           0 :         smbcli_deltree(cli->tree, BASEDIR);
     758             : 
     759           0 :         return ret;
     760             : }
     761             : 
     762             : /*
     763             :  * Do as above, but using 2 connections.
     764             :  */
     765             : 
     766           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file.txt";
     771             :         NTSTATUS status;
     772           0 :         int fnum1 = -1;
     773           0 :         int fnum2 = -1;
     774           0 :         bool ret = true;
     775             :         ssize_t written;
     776             :         struct timeval start;
     777             :         struct timeval end;
     778           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
     779           0 :         int normal_delay = 2000000;
     780           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
     781           0 :         int msec = 1000 * sec;
     782             :         union smb_flush flsh;
     783             : 
     784           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
     785             : 
     786           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
     787             : 
     788           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     789           0 :         if (fnum1 == -1) {
     790           0 :                 torture_comment(tctx, "Failed to open %s\n", fname);
     791           0 :                 return false;
     792             :         }
     793             : 
     794           0 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
     795           0 :         finfo1.basic_info.in.file.fnum = fnum1;
     796           0 :         finfo2 = finfo1;
     797             : 
     798           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     799             : 
     800           0 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
     801             :         
     802           0 :         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           0 :         smb_msleep(3 * msec);
     808             : 
     809             :         {
     810             :                 /* Try using setfileinfo instead of write to update write time. */
     811             :                 union smb_setfileinfo sfinfo;
     812           0 :                 time_t t_set = time(NULL);
     813           0 :                 sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
     814           0 :                 sfinfo.basic_info.in.file.fnum = fnum1;
     815           0 :                 sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
     816           0 :                 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           0 :                 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           0 :                 sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
     826           0 :                 sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
     827             : 
     828           0 :                 status = smb_raw_setfileinfo(cli->tree, &sfinfo);
     829             : 
     830           0 :                 torture_assert_ntstatus_ok(tctx, status, "sfileinfo failed");
     831             :         }
     832             : 
     833           0 :         finfo2.basic_info.in.file.path = fname;
     834             :         
     835           0 :         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
     836             : 
     837           0 :         if (!NT_STATUS_IS_OK(status)) {
     838           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     839           0 :                 return false;
     840             :         }
     841           0 :         torture_comment(tctx, "write time %s\n",
     842             :                nt_time_string(tctx, finfo2.basic_info.out.write_time));
     843             : 
     844           0 :         if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
     845           0 :                 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           0 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
     854           0 :         finfo1.basic_info.in.file.fnum = fnum1;
     855           0 :         finfo2 = finfo1;
     856             : 
     857           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
     858             : 
     859           0 :         if (!NT_STATUS_IS_OK(status)) {
     860           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     861           0 :                 return false;
     862             :         }
     863             :         
     864           0 :         torture_comment(tctx, "Modified write time %s\n", 
     865             :                nt_time_string(tctx, finfo1.basic_info.out.write_time));
     866             : 
     867             : 
     868           0 :         torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
     869             : 
     870           0 :         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
     871             : 
     872           0 :         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           0 :         torture_comment(tctx, "Doing flush after write\n");
     882             : 
     883           0 :         flsh.flush.level        = RAW_FLUSH_FLUSH;
     884           0 :         flsh.flush.in.file.fnum = fnum1;
     885           0 :         status = smb_raw_flush(cli->tree, &flsh);
     886           0 :         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           0 :         start = timeval_current();
     894           0 :         end = timeval_add(&start, (15*sec), 0);
     895           0 :         while (!timeval_expired(&end)) {
     896           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     897             : 
     898           0 :                 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           0 :                 torture_comment(tctx, "write time %s\n", 
     904             :                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
     905           0 :                 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           0 :                 fflush(stdout);
     914           0 :                 smb_msleep(1 * msec);
     915             :         }
     916             :         
     917           0 :         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
     918           0 :                 torture_comment(tctx, "Server did not update write time (correct)\n");
     919             :         }
     920             : 
     921           0 :         fflush(stdout);
     922           0 :         smb_msleep(2 * msec);
     923             : 
     924           0 :         fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
     925           0 :         if (fnum2 == -1) {
     926           0 :                 torture_result(tctx, TORTURE_FAIL, "Failed to open %s\n", fname);
     927           0 :                 return false;
     928             :         }
     929             :         
     930           0 :         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           0 :         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
     933             : 
     934           0 :         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           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     941             : 
     942           0 :         if (!NT_STATUS_IS_OK(status)) {
     943           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     944           0 :                 return false;
     945             :         }
     946           0 :         torture_comment(tctx, "write time %s\n", 
     947             :                nt_time_string(tctx, finfo2.basic_info.out.write_time));
     948           0 :         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           0 :         torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
     954           0 :         smbcli_close(cli->tree, fnum1);
     955           0 :         fnum1 = -1;
     956             : 
     957           0 :         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           0 :         written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
     960             : 
     961           0 :         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           0 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
     968           0 :         finfo1.basic_info.in.file.fnum = fnum2;
     969           0 :         finfo2 = finfo1;
     970           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     971             : 
     972           0 :         if (!NT_STATUS_IS_OK(status)) {
     973           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
     974           0 :                 return false;
     975             :         }
     976           0 :         torture_comment(tctx, "write time %s\n", 
     977             :                nt_time_string(tctx, finfo2.basic_info.out.write_time));
     978           0 :         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           0 :         start = timeval_current();
     986           0 :         end = timeval_add(&start, (15*sec), 0);
     987           0 :         while (!timeval_expired(&end)) {
     988           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
     989             : 
     990           0 :                 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           0 :                 torture_comment(tctx, "write time %s\n", 
     996             :                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
     997           0 :                 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           0 :                 fflush(stdout);
    1006           0 :                 smb_msleep(1 * msec);
    1007             :         }
    1008             :         
    1009           0 :         if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    1010           0 :                 torture_comment(tctx, "Server did not update write time (correct)\n");
    1011             :         }
    1012             : 
    1013           0 :         torture_comment(tctx, "Closing second fd to see if write time updated.\n");
    1014             : 
    1015           0 :         smbcli_close(cli->tree, fnum2);
    1016           0 :         fnum2 = -1;
    1017             : 
    1018           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
    1019           0 :         if (fnum1 == -1) {
    1020           0 :                 torture_comment(tctx, "Failed to open %s\n", fname);
    1021           0 :                 return false;
    1022             :         }
    1023             : 
    1024           0 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1025           0 :         finfo1.basic_info.in.file.fnum = fnum1;
    1026           0 :         finfo2 = finfo1;
    1027             : 
    1028           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
    1029             : 
    1030           0 :         if (!NT_STATUS_IS_OK(status)) {
    1031           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
    1032           0 :                 return false;
    1033             :         }
    1034             :         
    1035           0 :         torture_comment(tctx, "Second open initial write time %s\n", 
    1036             :                nt_time_string(tctx, finfo1.basic_info.out.write_time));
    1037             : 
    1038           0 :         smb_msleep(10 * msec);
    1039           0 :         torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
    1040             : 
    1041           0 :         written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
    1042             : 
    1043           0 :         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           0 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1050           0 :         finfo1.basic_info.in.file.fnum = fnum1;
    1051           0 :         finfo2 = finfo1;
    1052           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
    1053             : 
    1054           0 :         if (!NT_STATUS_IS_OK(status)) {
    1055           0 :                 DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
    1056           0 :                 return false;
    1057             :         }
    1058           0 :         torture_comment(tctx, "write time %s\n", 
    1059             :                nt_time_string(tctx, finfo2.basic_info.out.write_time));
    1060           0 :         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           0 :         start = timeval_current();
    1067           0 :         end = timeval_add(&start, (15*sec), 0);
    1068           0 :         while (!timeval_expired(&end)) {
    1069           0 :                 status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
    1070             : 
    1071           0 :                 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           0 :                 torture_comment(tctx, "write time %s\n", 
    1077             :                        nt_time_string(tctx, finfo2.basic_info.out.write_time));
    1078           0 :                 if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
    1079           0 :                         double diff = timeval_elapsed(&start);
    1080           0 :                         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           0 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds"
    1089             :                                         "(correct)\n",
    1090             :                                         diff);
    1091           0 :                         break;
    1092             :                 }
    1093           0 :                 fflush(stdout);
    1094           0 :                 smb_msleep(1*msec);
    1095             :         }
    1096             :         
    1097           0 :         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           0 :         if (fnum1 != -1)
    1108           0 :                 smbcli_close(cli->tree, fnum1);
    1109           0 :         smbcli_unlink(cli->tree, fname);
    1110           0 :         smbcli_deltree(cli->tree, BASEDIR);
    1111             : 
    1112           0 :         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           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file.txt";
    1131             :         NTSTATUS status;
    1132           0 :         int fnum1 = -1;
    1133             :         int fnum2;
    1134           0 :         bool ret = true;
    1135             :         ssize_t written;
    1136           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1137           0 :         int normal_delay = 2000000;
    1138           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1139           0 :         int msec = 1000 * sec;
    1140             : 
    1141           0 :         torture_comment(tctx, "\nRunning test_finfo_after_write\n");
    1142             : 
    1143           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1144             : 
    1145           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1146           0 :         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           0 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1153           0 :         finfo1.basic_info.in.file.fnum = fnum1;
    1154             : 
    1155           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
    1156             : 
    1157           0 :         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           0 :         smb_msleep(1 * msec);
    1164             : 
    1165           0 :         written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1166             : 
    1167           0 :         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           0 :         fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
    1174           0 :         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           0 :         written =  smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
    1182             : 
    1183           0 :         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           0 :         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1191           0 :         finfo2.basic_info.in.file.path = fname;
    1192             : 
    1193           0 :         status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
    1194             : 
    1195           0 :         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           0 :         if (finfo1.basic_info.out.create_time !=
    1203           0 :             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           0 :         if (finfo1.basic_info.out.access_time !=
    1210           0 :             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           0 :         if (finfo1.basic_info.out.write_time !=
    1217           0 :             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           0 :         if (finfo1.basic_info.out.change_time !=
    1227           0 :             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           0 :         smbcli_close(cli2->tree, fnum2);
    1239           0 :         cli2 = NULL;
    1240             : 
    1241             :         /* This call is only for the people looking at ethereal :-) */
    1242           0 :         finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1243           0 :         finfo2.basic_info.in.file.path = fname;
    1244             : 
    1245           0 :         status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
    1246             : 
    1247           0 :         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           0 :  done:
    1254           0 :         if (fnum1 != -1)
    1255           0 :                 smbcli_close(cli->tree, fnum1);
    1256           0 :         smbcli_unlink(cli->tree, fname);
    1257           0 :         smbcli_deltree(cli->tree, BASEDIR);
    1258             : 
    1259           0 :         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           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file3.txt";
    1403           0 :         int fnum1 = -1;
    1404           0 :         bool ret = true;
    1405             :         ssize_t written;
    1406             :         struct timeval start;
    1407             :         struct timeval end;
    1408           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1409           0 :         int normal_delay = 2000000;
    1410           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1411           0 :         int msec = 1000 * sec;
    1412             : 
    1413           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
    1414             : 
    1415           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1416             : 
    1417           0 :         torture_comment(tctx, "Open the file handle\n");
    1418           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1419           0 :         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           0 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1426           0 :         finfo0.basic_info.in.file.fnum = fnum1;
    1427           0 :         finfo1 = finfo0;
    1428           0 :         finfo2 = finfo0;
    1429           0 :         finfo3 = finfo0;
    1430           0 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1431           0 :         pinfo0.basic_info.in.file.path = fname;
    1432           0 :         pinfo1 = pinfo0;
    1433           0 :         pinfo2 = pinfo0;
    1434           0 :         pinfo3 = pinfo0;
    1435           0 :         pinfo4 = pinfo0;
    1436             : 
    1437             :         /* get the initial times */
    1438           0 :         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           0 :         start = timeval_current();
    1446           0 :         end = timeval_add(&start, 7 * sec, 0);
    1447           0 :         while (!timeval_expired(&end)) {
    1448             :                 /* do a write */
    1449           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1450           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1451           0 :                 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           0 :                 GET_INFO_FILE(finfo1);
    1458             : 
    1459           0 :                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
    1460           0 :                         double diff = timeval_elapsed(&start);
    1461           0 :                         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           0 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
    1470             :                                         "(correct)\n",
    1471             :                                         diff);
    1472           0 :                         break;
    1473             :                 }
    1474           0 :                 smb_msleep(0.5 * msec);
    1475             :         }
    1476             : 
    1477           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    1478           0 :         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
    1479             : 
    1480             :         /* sure any further write doesn't update the write time */
    1481           0 :         start = timeval_current();
    1482           0 :         end = timeval_add(&start, 15 * sec, 0);
    1483           0 :         while (!timeval_expired(&end)) {
    1484             :                 /* do a write */
    1485           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1486           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1487           0 :                 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           0 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1494             : 
    1495           0 :                 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           0 :                 smb_msleep(1 * msec);
    1504             :         }
    1505             : 
    1506           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    1507           0 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    1508           0 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    1509           0 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    1510             :         }
    1511             : 
    1512             :         /* sleep */
    1513           0 :         smb_msleep(5 * msec);
    1514             : 
    1515           0 :         GET_INFO_BOTH(finfo3,pinfo3);
    1516           0 :         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           0 :         torture_comment(tctx, "Close the file handle\n");
    1523           0 :         smbcli_close(cli->tree, fnum1);
    1524           0 :         fnum1 = -1;
    1525             : 
    1526           0 :         GET_INFO_PATH(pinfo4);
    1527           0 :         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
    1528             : 
    1529           0 :         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
    1530           0 :                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
    1531             :         }
    1532             : 
    1533           0 :  done:
    1534           0 :         if (fnum1 != -1)
    1535           0 :                 smbcli_close(cli->tree, fnum1);
    1536           0 :         smbcli_unlink(cli->tree, fname);
    1537           0 :         smbcli_deltree(cli->tree, BASEDIR);
    1538             : 
    1539           0 :         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           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file3a.txt";
    1554           0 :         int fnum1 = -1;
    1555           0 :         bool ret = true;
    1556             :         ssize_t written;
    1557             :         int i;
    1558             :         struct timeval start;
    1559             :         struct timeval end;
    1560           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1561           0 :         int normal_delay = 2000000;
    1562           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1563           0 :         int msec = 1000 * sec;
    1564             : 
    1565           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
    1566             : 
    1567           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1568             : 
    1569           0 :         torture_comment(tctx, "Open the file handle\n");
    1570           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1571           0 :         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           0 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1578           0 :         finfo0.basic_info.in.file.fnum = fnum1;
    1579           0 :         finfo1 = finfo0;
    1580           0 :         finfo2 = finfo0;
    1581           0 :         finfo3 = finfo0;
    1582           0 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1583           0 :         pinfo0.basic_info.in.file.path = fname;
    1584           0 :         pinfo1 = pinfo0;
    1585           0 :         pinfo2 = pinfo0;
    1586           0 :         pinfo3 = pinfo0;
    1587           0 :         pinfo4 = pinfo0;
    1588             : 
    1589             :         /* get the initial times */
    1590           0 :         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           0 :         smb_msleep(5 * msec);
    1597             : 
    1598             :         /* get the initial times */
    1599           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    1600           0 :         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           0 :         start = timeval_current();
    1608           0 :         end = timeval_add(&start, 7 * sec, 0);
    1609           0 :         while (!timeval_expired(&end)) {
    1610             :                 /* do a write */
    1611           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1612           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1613           0 :                 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           0 :                 GET_INFO_FILE(finfo1);
    1620             : 
    1621           0 :                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
    1622           0 :                         double diff = timeval_elapsed(&start);
    1623           0 :                         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           0 :                         torture_comment(tctx, "Server updated write_time after %.2f seconds "
    1632             :                                         "(correct)\n",
    1633             :                                         diff);
    1634           0 :                         break;
    1635             :                 }
    1636           0 :                 smb_msleep(0.5 * msec);
    1637             :         }
    1638             : 
    1639           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    1640           0 :         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
    1641             : 
    1642           0 :         smb_msleep(3 * msec);
    1643             : 
    1644             :         /*
    1645             :          * demonstrate that a truncate write always
    1646             :          * updates the write time immediately
    1647             :          */
    1648           0 :         for (i=0; i < 3; i++) {
    1649           0 :                 smb_msleep(2 * msec);
    1650             :                 /* do a write */
    1651           0 :                 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
    1652           0 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
    1653           0 :                 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           0 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1660           0 :                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    1661           0 :                 finfo1 = finfo2;
    1662             :         }
    1663             : 
    1664           0 :         smb_msleep(3 * msec);
    1665             : 
    1666             :         /* sure any further write doesn't update the write time */
    1667           0 :         start = timeval_current();
    1668           0 :         end = timeval_add(&start, 15 * sec, 0);
    1669           0 :         while (!timeval_expired(&end)) {
    1670             :                 /* do a write */
    1671           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1672           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1673           0 :                 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           0 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1680             : 
    1681           0 :                 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           0 :                 smb_msleep(1 * msec);
    1690             :         }
    1691             : 
    1692           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    1693           0 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    1694           0 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    1695           0 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    1696             :         }
    1697             : 
    1698             :         /* sleep */
    1699           0 :         smb_msleep(3 * msec);
    1700             : 
    1701             :         /* get the initial times */
    1702           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    1703           0 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
    1704             : 
    1705             :         /*
    1706             :          * demonstrate that a truncate write always
    1707             :          * updates the write time immediately
    1708             :          */
    1709           0 :         for (i=0; i < 3; i++) {
    1710           0 :                 smb_msleep(2 * msec);
    1711             :                 /* do a write */
    1712           0 :                 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
    1713           0 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
    1714           0 :                 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           0 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1721           0 :                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    1722           0 :                 finfo1 = finfo2;
    1723             :         }
    1724             : 
    1725             :         /* sleep */
    1726           0 :         smb_msleep(3 * msec);
    1727             : 
    1728           0 :         GET_INFO_BOTH(finfo3,pinfo3);
    1729           0 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    1730             : 
    1731             :         /*
    1732             :          * the close doesn't update the write time
    1733             :          */
    1734           0 :         torture_comment(tctx, "Close the file handle\n");
    1735           0 :         smbcli_close(cli->tree, fnum1);
    1736           0 :         fnum1 = -1;
    1737             : 
    1738           0 :         GET_INFO_PATH(pinfo4);
    1739           0 :         COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
    1740             : 
    1741           0 :         if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
    1742           0 :                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
    1743             :         }
    1744             : 
    1745           0 :  done:
    1746           0 :         if (fnum1 != -1)
    1747           0 :                 smbcli_close(cli->tree, fnum1);
    1748           0 :         smbcli_unlink(cli->tree, fname);
    1749           0 :         smbcli_deltree(cli->tree, BASEDIR);
    1750             : 
    1751           0 :         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           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file3b.txt";
    1766           0 :         int fnum1 = -1;
    1767           0 :         bool ret = true;
    1768             :         ssize_t written;
    1769             :         struct timeval start;
    1770             :         struct timeval end;
    1771           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1772           0 :         int normal_delay = 2000000;
    1773           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1774           0 :         int msec = 1000 * sec;
    1775             : 
    1776           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
    1777             : 
    1778           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1779             : 
    1780           0 :         torture_comment(tctx, "Open the file handle\n");
    1781           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1782           0 :         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           0 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1789           0 :         finfo0.basic_info.in.file.fnum = fnum1;
    1790           0 :         finfo1 = finfo0;
    1791           0 :         finfo2 = finfo0;
    1792           0 :         finfo3 = finfo0;
    1793           0 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1794           0 :         pinfo0.basic_info.in.file.path = fname;
    1795           0 :         pinfo1 = pinfo0;
    1796           0 :         pinfo2 = pinfo0;
    1797           0 :         pinfo3 = pinfo0;
    1798           0 :         pinfo4 = pinfo0;
    1799             : 
    1800             :         /* get the initial times */
    1801           0 :         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           0 :         smb_msleep(5 * msec);
    1808             : 
    1809             :         /* get the initial times */
    1810           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    1811           0 :         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           0 :         start = timeval_current();
    1819           0 :         end = timeval_add(&start, 7 * sec, 0);
    1820           0 :         while (!timeval_expired(&end)) {
    1821             :                 /* do a write */
    1822           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1823           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1824           0 :                 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           0 :                 GET_INFO_FILE(finfo1);
    1831             : 
    1832           0 :                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
    1833           0 :                         double diff = timeval_elapsed(&start);
    1834           0 :                         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           0 :                         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           0 :                         break;
    1846             :                 }
    1847           0 :                 smb_msleep(0.5 * msec);
    1848             :         }
    1849             : 
    1850           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    1851           0 :         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
    1852             : 
    1853             :         /* sure any further write doesn't update the write time */
    1854           0 :         start = timeval_current();
    1855           0 :         end = timeval_add(&start, 15 * sec, 0);
    1856           0 :         while (!timeval_expired(&end)) {
    1857             :                 /* do a write */
    1858           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    1859           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    1860           0 :                 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           0 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1867             : 
    1868           0 :                 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           0 :                 smb_msleep(1 * msec);
    1877             :         }
    1878             : 
    1879           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    1880           0 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    1881           0 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    1882           0 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    1883             :         }
    1884             : 
    1885             :         /* sleep */
    1886           0 :         smb_msleep(5 * msec);
    1887             : 
    1888           0 :         GET_INFO_BOTH(finfo3,pinfo3);
    1889           0 :         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           0 :         torture_comment(tctx, "Close the file handle\n");
    1896           0 :         smbcli_close(cli->tree, fnum1);
    1897           0 :         fnum1 = -1;
    1898             : 
    1899           0 :         GET_INFO_PATH(pinfo4);
    1900           0 :         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
    1901             : 
    1902           0 :         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
    1903           0 :                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
    1904             :         }
    1905             : 
    1906           0 :  done:
    1907           0 :         if (fnum1 != -1)
    1908           0 :                 smbcli_close(cli->tree, fnum1);
    1909           0 :         smbcli_unlink(cli->tree, fname);
    1910           0 :         smbcli_deltree(cli->tree, BASEDIR);
    1911             : 
    1912           0 :         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           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file3c.txt";
    1929           0 :         int fnum1 = -1;
    1930           0 :         bool ret = true;
    1931             :         ssize_t written;
    1932             :         int i;
    1933             :         struct timeval start;
    1934             :         struct timeval end;
    1935           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    1936           0 :         int normal_delay = 2000000;
    1937           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    1938           0 :         int msec = 1000 * sec;
    1939             : 
    1940           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
    1941             : 
    1942           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    1943             : 
    1944           0 :         torture_comment(tctx, "Open the file handle\n");
    1945           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    1946           0 :         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           0 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1953           0 :         finfo0.basic_info.in.file.fnum = fnum1;
    1954           0 :         finfo1 = finfo0;
    1955           0 :         finfo2 = finfo0;
    1956           0 :         finfo3 = finfo0;
    1957           0 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    1958           0 :         pinfo0.basic_info.in.file.path = fname;
    1959           0 :         pinfo1 = pinfo0;
    1960           0 :         pinfo2 = pinfo0;
    1961           0 :         pinfo3 = pinfo0;
    1962           0 :         pinfo4 = pinfo0;
    1963             : 
    1964             :         /* get the initial times */
    1965           0 :         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           0 :         smb_msleep(5 * msec);
    1972             : 
    1973             :         /* get the initial times */
    1974           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    1975           0 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    1976             : 
    1977             :         /*
    1978             :          * demonstrate that a truncate write always
    1979             :          * updates the write time immediately
    1980             :          */
    1981           0 :         for (i=0; i < 3; i++) {
    1982           0 :                 smb_msleep(2 * msec);
    1983             :                 /* do a write */
    1984           0 :                 torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
    1985           0 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
    1986           0 :                 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           0 :                 GET_INFO_BOTH(finfo2,pinfo2);
    1993           0 :                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    1994           0 :                 finfo1 = finfo2;
    1995             :         }
    1996             : 
    1997           0 :         start = timeval_current();
    1998           0 :         end = timeval_add(&start, 7 * sec, 0);
    1999           0 :         while (!timeval_expired(&end)) {
    2000             :                 /* do a write */
    2001           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2002           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2003           0 :                 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           0 :                 GET_INFO_FILE(finfo2);
    2010             : 
    2011           0 :                 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           0 :                 smb_msleep(1 * msec);
    2020             :         }
    2021             : 
    2022           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2023           0 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    2024           0 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    2025           0 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2026             :         }
    2027             : 
    2028             :         /* sleep */
    2029           0 :         smb_msleep(5 * msec);
    2030             : 
    2031             :         /* get the initial times */
    2032           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    2033           0 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
    2034             : 
    2035             :         /*
    2036             :          * demonstrate that a truncate write always
    2037             :          * updates the write time immediately
    2038             :          */
    2039           0 :         for (i=0; i < 3; i++) {
    2040           0 :                 smb_msleep(2 * msec);
    2041             :                 /* do a write */
    2042           0 :                 torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
    2043           0 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
    2044           0 :                 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           0 :                 GET_INFO_BOTH(finfo2,pinfo2);
    2051           0 :                 COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    2052           0 :                 finfo1 = finfo2;
    2053             :         }
    2054             : 
    2055             :         /* sleep */
    2056           0 :         smb_msleep(5 * msec);
    2057             : 
    2058           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2059           0 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    2060             : 
    2061             :         /* sure any further write doesn't update the write time */
    2062           0 :         start = timeval_current();
    2063           0 :         end = timeval_add(&start, 15 * sec, 0);
    2064           0 :         while (!timeval_expired(&end)) {
    2065             :                 /* do a write */
    2066           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2067           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2068           0 :                 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           0 :                 GET_INFO_BOTH(finfo2,pinfo2);
    2075             : 
    2076           0 :                 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           0 :                 smb_msleep(1 * msec);
    2085             :         }
    2086             : 
    2087           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2088           0 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    2089           0 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    2090           0 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2091             :         }
    2092             : 
    2093             :         /* sleep */
    2094           0 :         smb_msleep(5 * msec);
    2095             : 
    2096           0 :         GET_INFO_BOTH(finfo3,pinfo3);
    2097           0 :         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           0 :         torture_comment(tctx, "Close the file handle\n");
    2104           0 :         smbcli_close(cli->tree, fnum1);
    2105           0 :         fnum1 = -1;
    2106             : 
    2107           0 :         GET_INFO_PATH(pinfo4);
    2108           0 :         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
    2109             : 
    2110           0 :         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
    2111           0 :                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
    2112             :         }
    2113             : 
    2114           0 :  done:
    2115           0 :         if (fnum1 != -1)
    2116           0 :                 smbcli_close(cli->tree, fnum1);
    2117           0 :         smbcli_unlink(cli->tree, fname);
    2118           0 :         smbcli_deltree(cli->tree, BASEDIR);
    2119             : 
    2120           0 :         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           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file4.txt";
    2136           0 :         int fnum1 = -1;
    2137           0 :         bool ret = true;
    2138             :         ssize_t written;
    2139             :         struct timeval start;
    2140             :         struct timeval end;
    2141           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2142           0 :         int normal_delay = 2000000;
    2143           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2144           0 :         int msec = 1000 * sec;
    2145             : 
    2146           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
    2147             : 
    2148           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2149             : 
    2150           0 :         torture_comment(tctx, "Open the file handle\n");
    2151           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2152           0 :         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           0 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2159           0 :         finfo0.basic_info.in.file.fnum = fnum1;
    2160           0 :         finfo1 = finfo0;
    2161           0 :         finfo2 = finfo0;
    2162           0 :         finfo3 = finfo0;
    2163           0 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2164           0 :         pinfo0.basic_info.in.file.path = fname;
    2165           0 :         pinfo1 = pinfo0;
    2166           0 :         pinfo2 = pinfo0;
    2167           0 :         pinfo3 = pinfo0;
    2168           0 :         pinfo4 = pinfo0;
    2169             : 
    2170             :         /* get the initial times */
    2171           0 :         GET_INFO_BOTH(finfo0,pinfo0);
    2172             : 
    2173             :         /* sleep a bit */
    2174           0 :         smb_msleep(5 * msec);
    2175             : 
    2176             :         /* do a write */
    2177           0 :         torture_comment(tctx, "Do a write on the file handle\n");
    2178           0 :         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2179           0 :         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           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    2186           0 :         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           0 :         start = timeval_current();
    2194           0 :         end = timeval_add(&start, 5 * sec, 0);
    2195           0 :         while (!timeval_expired(&end)) {
    2196             :                 /* get the times after the first write */
    2197           0 :                 GET_INFO_FILE(finfo1);
    2198             : 
    2199           0 :                 if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
    2200           0 :                         double diff = timeval_elapsed(&start);
    2201           0 :                         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           0 :                         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           0 :                         break;
    2213             :                 }
    2214           0 :                 smb_msleep(0.5 * msec);
    2215             :         }
    2216             : 
    2217           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    2218           0 :         COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
    2219             : 
    2220             :         /* sure any further write doesn't update the write time */
    2221           0 :         start = timeval_current();
    2222           0 :         end = timeval_add(&start, 15 * sec, 0);
    2223           0 :         while (!timeval_expired(&end)) {
    2224             :                 /* do a write */
    2225           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2226           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2227           0 :                 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           0 :                 GET_INFO_BOTH(finfo2,pinfo2);
    2234             : 
    2235           0 :                 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           0 :                 smb_msleep(1 * msec);
    2244             :         }
    2245             : 
    2246           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2247           0 :         COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
    2248           0 :         if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
    2249           0 :                 torture_comment(tctx, "Server did not updatewrite_time (correct)\n");
    2250             :         }
    2251             : 
    2252             :         /* sleep */
    2253           0 :         smb_msleep(5 * msec);
    2254             : 
    2255           0 :         GET_INFO_BOTH(finfo3,pinfo3);
    2256           0 :         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           0 :         torture_comment(tctx, "Close the file handle\n");
    2263           0 :         smbcli_close(cli->tree, fnum1);
    2264           0 :         fnum1 = -1;
    2265             : 
    2266           0 :         GET_INFO_PATH(pinfo4);
    2267           0 :         COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
    2268             : 
    2269           0 :         if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
    2270           0 :                 torture_comment(tctx, "Server updated the write_time on close (correct)\n");
    2271             :         }
    2272             : 
    2273           0 :  done:
    2274           0 :         if (fnum1 != -1)
    2275           0 :                 smbcli_close(cli->tree, fnum1);
    2276           0 :         smbcli_unlink(cli->tree, fname);
    2277           0 :         smbcli_deltree(cli->tree, BASEDIR);
    2278             : 
    2279           0 :         return ret;
    2280             : }
    2281             : 
    2282             : /*
    2283             :  * Show writes and closes have no effect on updating times once a SETWRITETIME is done.
    2284             :  */
    2285             : 
    2286           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file5.txt";
    2293           0 :         int fnum1 = -1;
    2294           0 :         bool ret = true;
    2295             :         ssize_t written;
    2296             :         struct timeval start;
    2297             :         struct timeval end;
    2298           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2299           0 :         int normal_delay = 2000000;
    2300           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2301           0 :         int msec = 1000 * sec;
    2302             : 
    2303           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
    2304             : 
    2305           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2306             : 
    2307           0 :         torture_comment(tctx, "Open the file handle\n");
    2308           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2309           0 :         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           0 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2316           0 :         finfo0.basic_info.in.file.fnum = fnum1;
    2317           0 :         finfo1 = finfo0;
    2318           0 :         finfo2 = finfo0;
    2319           0 :         finfo3 = finfo0;
    2320           0 :         finfo4 = finfo0;
    2321           0 :         finfo5 = finfo0;
    2322           0 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2323           0 :         pinfo0.basic_info.in.file.path = fname;
    2324           0 :         pinfo1 = pinfo0;
    2325           0 :         pinfo2 = pinfo0;
    2326           0 :         pinfo3 = pinfo0;
    2327           0 :         pinfo4 = pinfo0;
    2328           0 :         pinfo5 = pinfo0;
    2329           0 :         pinfo6 = pinfo0;
    2330             : 
    2331             :         /* get the initial times */
    2332           0 :         GET_INFO_BOTH(finfo0,pinfo0);
    2333             : 
    2334             :         /* do a write */
    2335           0 :         torture_comment(tctx, "Do a write on the file handle\n");
    2336           0 :         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2337           0 :         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           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    2344           0 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    2345             : 
    2346           0 :         torture_comment(tctx, "Set write time in the future on the file handle\n");
    2347           0 :         SET_INFO_FILE(finfo0, time(NULL) + 86400);
    2348           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2349           0 :         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    2350             : 
    2351           0 :         torture_comment(tctx, "Set write time in the past on the file handle\n");
    2352           0 :         SET_INFO_FILE(finfo0, time(NULL) - 86400);
    2353           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2354           0 :         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
    2355             : 
    2356             :         /* make sure the 2 second delay from the first write are canceled */
    2357           0 :         start = timeval_current();
    2358           0 :         end = timeval_add(&start, 15 * sec, 0);
    2359           0 :         while (!timeval_expired(&end)) {
    2360             : 
    2361             :                 /* get the times after the first write */
    2362           0 :                 GET_INFO_BOTH(finfo3,pinfo3);
    2363             : 
    2364           0 :                 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           0 :                 smb_msleep(1 * msec);
    2373             :         }
    2374             : 
    2375           0 :         GET_INFO_BOTH(finfo3,pinfo3);
    2376           0 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    2377           0 :         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    2378           0 :                 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           0 :         start = timeval_current();
    2383           0 :         end = timeval_add(&start, 15 * sec, 0);
    2384           0 :         while (!timeval_expired(&end)) {
    2385             :                 /* do a write */
    2386           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2387           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2388           0 :                 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           0 :                 GET_INFO_BOTH(finfo4,pinfo4);
    2395             : 
    2396           0 :                 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           0 :                 smb_msleep(1 * msec);
    2405             :         }
    2406             : 
    2407           0 :         GET_INFO_BOTH(finfo4,pinfo4);
    2408           0 :         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
    2409           0 :         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
    2410           0 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2411             :         }
    2412             : 
    2413             :         /* sleep */
    2414           0 :         smb_msleep(5 * msec);
    2415             : 
    2416           0 :         GET_INFO_BOTH(finfo5,pinfo5);
    2417           0 :         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
    2418             : 
    2419             :         /*
    2420             :          * the close doesn't update the write time
    2421             :          */
    2422           0 :         torture_comment(tctx, "Close the file handle\n");
    2423           0 :         smbcli_close(cli->tree, fnum1);
    2424           0 :         fnum1 = -1;
    2425             : 
    2426           0 :         GET_INFO_PATH(pinfo6);
    2427           0 :         COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
    2428             : 
    2429           0 :         if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
    2430           0 :                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
    2431             :         }
    2432             : 
    2433           0 :  done:
    2434           0 :         if (fnum1 != -1)
    2435           0 :                 smbcli_close(cli->tree, fnum1);
    2436           0 :         smbcli_unlink(cli->tree, fname);
    2437           0 :         smbcli_deltree(cli->tree, BASEDIR);
    2438             : 
    2439           0 :         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           0 : 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           0 :         const char *fname = BASEDIR "\\torture_fileb.txt";
    2453           0 :         int fnum1 = -1;
    2454           0 :         bool ret = true;
    2455             :         ssize_t written;
    2456             :         struct timeval start;
    2457             :         struct timeval end;
    2458           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2459           0 :         int normal_delay = 2000000;
    2460           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2461           0 :         int msec = 1000 * sec;
    2462             : 
    2463           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
    2464             : 
    2465           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2466             : 
    2467           0 :         torture_comment(tctx, "Open the file handle\n");
    2468           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2469           0 :         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           0 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2476           0 :         finfo0.basic_info.in.file.fnum = fnum1;
    2477           0 :         finfo1 = finfo0;
    2478           0 :         finfo2 = finfo0;
    2479           0 :         finfo3 = finfo0;
    2480           0 :         finfo4 = finfo0;
    2481           0 :         finfo5 = finfo0;
    2482           0 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2483           0 :         pinfo0.basic_info.in.file.path = fname;
    2484           0 :         pinfo1 = pinfo0;
    2485           0 :         pinfo2 = pinfo0;
    2486           0 :         pinfo3 = pinfo0;
    2487           0 :         pinfo4 = pinfo0;
    2488           0 :         pinfo5 = pinfo0;
    2489           0 :         pinfo6 = pinfo0;
    2490             : 
    2491             :         /* get the initial times */
    2492           0 :         GET_INFO_BOTH(finfo0,pinfo0);
    2493             : 
    2494             :         /* do a write */
    2495           0 :         torture_comment(tctx, "Do a write on the file handle\n");
    2496           0 :         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2497           0 :         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           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    2504           0 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    2505             : 
    2506           0 :         torture_comment(tctx, "Set write time in the future on the file handle\n");
    2507           0 :         SET_INFO_FILE(finfo0, time(NULL) + 86400);
    2508           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2509           0 :         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    2510             : 
    2511           0 :         torture_comment(tctx, "Set write time in the past on the file handle\n");
    2512           0 :         SET_INFO_FILE(finfo0, time(NULL) - 86400);
    2513           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2514           0 :         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
    2515             : 
    2516             :         /* make sure the 2 second delay from the first write are canceled */
    2517           0 :         start = timeval_current();
    2518           0 :         end = timeval_add(&start, 15 * sec, 0);
    2519           0 :         while (!timeval_expired(&end)) {
    2520             : 
    2521             :                 /* get the times after the first write */
    2522           0 :                 GET_INFO_BOTH(finfo3,pinfo3);
    2523             : 
    2524           0 :                 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           0 :                 smb_msleep(1 * msec);
    2533             :         }
    2534             : 
    2535           0 :         GET_INFO_BOTH(finfo3,pinfo3);
    2536           0 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    2537           0 :         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    2538           0 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2539             :         }
    2540             : 
    2541             :         /* Do any further write (truncates) update the write time ? */
    2542           0 :         start = timeval_current();
    2543           0 :         end = timeval_add(&start, 15 * sec, 0);
    2544           0 :         while (!timeval_expired(&end)) {
    2545             :                 /* do a write */
    2546           0 :                 torture_comment(tctx, "Do a truncate write on the file handle\n");
    2547           0 :                 written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
    2548           0 :                 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           0 :                 GET_INFO_BOTH(finfo4,pinfo4);
    2555             : 
    2556           0 :                 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           0 :                 smb_msleep(1 * msec);
    2565             :         }
    2566             : 
    2567           0 :         GET_INFO_BOTH(finfo4,pinfo4);
    2568           0 :         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
    2569           0 :         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
    2570           0 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2571             :         }
    2572             : 
    2573             :         /* sleep */
    2574           0 :         smb_msleep(5 * msec);
    2575             : 
    2576           0 :         GET_INFO_BOTH(finfo5,pinfo5);
    2577           0 :         COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
    2578             : 
    2579             :         /*
    2580             :          * the close doesn't update the write time
    2581             :          */
    2582           0 :         torture_comment(tctx, "Close the file handle\n");
    2583           0 :         smbcli_close(cli->tree, fnum1);
    2584           0 :         fnum1 = -1;
    2585             : 
    2586           0 :         GET_INFO_PATH(pinfo6);
    2587           0 :         COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
    2588             : 
    2589           0 :         if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
    2590           0 :                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
    2591             :         }
    2592             : 
    2593           0 :  done:
    2594           0 :         if (fnum1 != -1)
    2595           0 :                 smbcli_close(cli->tree, fnum1);
    2596           0 :         smbcli_unlink(cli->tree, fname);
    2597           0 :         smbcli_deltree(cli->tree, BASEDIR);
    2598             : 
    2599           0 :         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           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file6.txt";
    2617           0 :         int fnum1 = -1;
    2618           0 :         int fnum2 = -1;
    2619           0 :         bool ret = true;
    2620             :         ssize_t written;
    2621             :         struct timeval start;
    2622             :         struct timeval end;
    2623           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2624           0 :         int normal_delay = 2000000;
    2625           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2626           0 :         int msec = 1000 * sec;
    2627           0 :         bool first = true;
    2628             : 
    2629           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
    2630             : 
    2631           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2632           0 : again:
    2633           0 :         torture_comment(tctx, "Open the file handle\n");
    2634           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2635           0 :         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           0 :         if (fnum2 == -1) {
    2642           0 :                 torture_comment(tctx, "Open the 2nd file handle on 2nd connection\n");
    2643           0 :                 fnum2 = smbcli_open(cli2->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2644           0 :                 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           0 :         finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2652           0 :         finfo0.basic_info.in.file.fnum = fnum1;
    2653           0 :         finfo1 = finfo0;
    2654           0 :         finfo2 = finfo0;
    2655           0 :         finfo3 = finfo0;
    2656           0 :         finfo4 = finfo0;
    2657           0 :         finfo5 = finfo0;
    2658           0 :         pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2659           0 :         pinfo0.basic_info.in.file.path = fname;
    2660           0 :         pinfo1 = pinfo0;
    2661           0 :         pinfo2 = pinfo0;
    2662           0 :         pinfo3 = pinfo0;
    2663           0 :         pinfo4 = pinfo0;
    2664           0 :         pinfo5 = pinfo0;
    2665           0 :         pinfo6 = pinfo0;
    2666           0 :         pinfo7 = pinfo0;
    2667             : 
    2668             :         /* get the initial times */
    2669           0 :         GET_INFO_BOTH(finfo0,pinfo0);
    2670             : 
    2671             :         /* do a write */
    2672           0 :         torture_comment(tctx, "Do a write on the file handle\n");
    2673           0 :         written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2674           0 :         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           0 :         GET_INFO_BOTH(finfo1,pinfo1);
    2681           0 :         COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
    2682             : 
    2683           0 :         torture_comment(tctx, "Set write time in the future on the 2nd file handle\n");
    2684           0 :         SET_INFO_FILE_EX(finfo0, time(NULL) + 86400, cli2->tree, fnum2);
    2685           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2686           0 :         COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
    2687             : 
    2688           0 :         torture_comment(tctx, "Set write time in the past on the 2nd file handle\n");
    2689           0 :         SET_INFO_FILE_EX(finfo0, time(NULL) - 86400, cli2->tree, fnum2);
    2690           0 :         GET_INFO_BOTH(finfo2,pinfo2);
    2691           0 :         COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
    2692             : 
    2693             :         /* make sure the 2 second delay from the first write are canceled */
    2694           0 :         start = timeval_current();
    2695           0 :         end = timeval_add(&start, 10 * sec, 0);
    2696           0 :         while (!timeval_expired(&end)) {
    2697             : 
    2698             :                 /* get the times after the first write */
    2699           0 :                 GET_INFO_BOTH(finfo3,pinfo3);
    2700             : 
    2701           0 :                 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           0 :                 smb_msleep(1 * msec);
    2710             :         }
    2711             : 
    2712           0 :         GET_INFO_BOTH(finfo3,pinfo3);
    2713           0 :         COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
    2714           0 :         if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
    2715           0 :                 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           0 :         start = timeval_current();
    2720           0 :         end = timeval_add(&start, 10 * sec, 0);
    2721           0 :         while (!timeval_expired(&end)) {
    2722             :                 /* do a write */
    2723           0 :                 torture_comment(tctx, "Do a write on the file handle\n");
    2724           0 :                 written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
    2725           0 :                 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           0 :                 GET_INFO_BOTH(finfo4,pinfo4);
    2732             : 
    2733           0 :                 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           0 :                 smb_msleep(1 * msec);
    2742             :         }
    2743             : 
    2744           0 :         GET_INFO_BOTH(finfo4,pinfo4);
    2745           0 :         COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
    2746           0 :         if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
    2747           0 :                 torture_comment(tctx, "Server did not update write_time (correct)\n");
    2748             :         }
    2749             : 
    2750             :         /* sleep */
    2751           0 :         smb_msleep(5 * msec);
    2752             : 
    2753           0 :         GET_INFO_BOTH(finfo5,pinfo5);
    2754           0 :         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           0 :         torture_comment(tctx, "Close the file handle\n");
    2761           0 :         smbcli_close(cli->tree, fnum1);
    2762           0 :         fnum1 = -1;
    2763             : 
    2764           0 :         GET_INFO_PATH(pinfo6);
    2765           0 :         COMPARE_WRITE_TIME_GREATER(pinfo6, pinfo5);
    2766             : 
    2767           0 :         if (pinfo6.basic_info.out.write_time > pinfo5.basic_info.out.write_time) {
    2768           0 :                 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           0 :         finfo5.basic_info.in.file.fnum = fnum2;
    2773           0 :         GET_INFO_FILE2(finfo5);
    2774           0 :         COMPARE_WRITE_TIME_EQUAL(finfo5, pinfo6);
    2775             : 
    2776             :         /* See if we have lost the sticky write time on handle2 */
    2777           0 :         smb_msleep(3 * msec);
    2778           0 :         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           0 :         start = timeval_current();
    2782           0 :         end = timeval_add(&start, 10 * sec, 0);
    2783           0 :         while (!timeval_expired(&end)) {
    2784             :                 /* do a write */
    2785           0 :                 torture_comment(tctx, "Do a write on the second file handle\n");
    2786           0 :                 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
    2787           0 :                 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           0 :                 GET_INFO_FILE2(finfo5);
    2794           0 :                 GET_INFO_PATH(pinfo6);
    2795             : 
    2796           0 :                 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           0 :                 smb_msleep(1 * msec);
    2805             :         }
    2806             : 
    2807             :         /* What about a truncate write ? */
    2808           0 :         start = timeval_current();
    2809           0 :         end = timeval_add(&start, 10 * sec, 0);
    2810           0 :         while (!timeval_expired(&end)) {
    2811             :                 /* do a write */
    2812           0 :                 torture_comment(tctx, "Do a truncate write on the second file handle\n");
    2813           0 :                 written = smbcli_write(cli2->tree, fnum2, 0, "x", 0, 0);
    2814           0 :                 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           0 :                 GET_INFO_FILE2(finfo5);
    2821           0 :                 GET_INFO_PATH(pinfo6);
    2822             : 
    2823           0 :                 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           0 :                 smb_msleep(1 * msec);
    2832             :         }
    2833             : 
    2834             : 
    2835             :         /* keep the 2nd handle open and rerun tests */
    2836           0 :         if (first) {
    2837           0 :                 first = false;
    2838           0 :                 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           0 :         torture_comment(tctx, "Close the 2nd file handle\n");
    2846           0 :         smbcli_close(cli2->tree, fnum2);
    2847           0 :         fnum2 = -1;
    2848             : 
    2849           0 :         GET_INFO_PATH(pinfo7);
    2850           0 :         COMPARE_WRITE_TIME_EQUAL(pinfo7, pinfo6);
    2851             : 
    2852           0 :         if (pinfo7.basic_info.out.write_time == pinfo6.basic_info.out.write_time) {
    2853           0 :                 torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
    2854             :         }
    2855             : 
    2856           0 :  done:
    2857           0 :         if (fnum1 != -1)
    2858           0 :                 smbcli_close(cli->tree, fnum1);
    2859           0 :         if (fnum2 != -1)
    2860           0 :                 smbcli_close(cli2->tree, fnum2);
    2861           0 :         smbcli_unlink(cli->tree, fname);
    2862           0 :         smbcli_deltree(cli->tree, BASEDIR);
    2863             : 
    2864           0 :         return ret;
    2865             : }
    2866             : 
    2867           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file7.txt";
    2872             :         NTSTATUS status;
    2873           0 :         int fnum1 = -1;
    2874           0 :         bool ret = true;
    2875             :         TALLOC_CTX *mem_ctx; 
    2876             : 
    2877           0 :         torture_comment(tctx, "\nRunning test_delayed_write_update7 (timestamp resolution test)\n");
    2878             : 
    2879           0 :         mem_ctx = talloc_init("test_delayed_write_update7");
    2880           0 :         if (!mem_ctx) return false;
    2881             : 
    2882           0 :         ZERO_STRUCT(finfo1);
    2883           0 :         ZERO_STRUCT(finfo2);
    2884           0 :         ZERO_STRUCT(finfo3);
    2885           0 :         ZERO_STRUCT(open_parms);
    2886             : 
    2887           0 :         torture_assert(tctx, torture_setup_dir(cli, BASEDIR), "Failed to setup up test directory: " BASEDIR);
    2888             : 
    2889             :         /* Create the file. */
    2890           0 :         fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    2891           0 :         if (fnum1 == -1) {
    2892           0 :                 torture_result(tctx, TORTURE_FAIL, "Failed to open %s", fname);
    2893           0 :                 return false;
    2894             :         }
    2895             : 
    2896           0 :         finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    2897           0 :         finfo1.basic_info.in.file.fnum = fnum1;
    2898           0 :         finfo2 = finfo1;
    2899           0 :         finfo3 = finfo1;
    2900             : 
    2901             :         /* Get the initial timestamps. */
    2902           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
    2903             : 
    2904           0 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
    2905             :         
    2906             :         /* Set the pending write time to a value with ns. */
    2907           0 :         SET_INFO_FILE_NS(finfo, time(NULL) + 86400, 103, cli->tree, fnum1);
    2908             : 
    2909             :         /* Get the current pending write time by fnum. */
    2910           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
    2911             : 
    2912           0 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
    2913             : 
    2914             :         /* Ensure the time is actually different. */
    2915           0 :         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           0 :         finfo3.basic_info.in.file.path = fname;
    2923           0 :         status = smb_raw_pathinfo(cli->tree, tctx, &finfo3);
    2924             : 
    2925           0 :         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           0 :         smbcli_close(cli->tree, fnum1);
    2935             : 
    2936           0 :         open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
    2937           0 :         open_parms.ntcreatex.in.flags = 0;
    2938           0 :         open_parms.ntcreatex.in.access_mask = SEC_GENERIC_READ;
    2939           0 :         open_parms.ntcreatex.in.file_attr = 0;
    2940           0 :         open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
    2941             :                                         NTCREATEX_SHARE_ACCESS_READ|
    2942             :                                         NTCREATEX_SHARE_ACCESS_WRITE;
    2943           0 :         open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    2944           0 :         open_parms.ntcreatex.in.create_options = 0;
    2945           0 :         open_parms.ntcreatex.in.fname = fname;
    2946             : 
    2947           0 :         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
    2948           0 :         talloc_free(mem_ctx);
    2949             : 
    2950           0 :         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           0 :         fnum1 = open_parms.ntcreatex.out.file.fnum;
    2957             : 
    2958             :         /* Check the returned time matches. */
    2959           0 :         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           0 :  done:
    2966             : 
    2967           0 :         smbcli_close(cli->tree, fnum1);
    2968             : 
    2969           0 :         smbcli_unlink(cli->tree, fname);
    2970           0 :         smbcli_deltree(cli->tree, BASEDIR);
    2971           0 :         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           0 : 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           0 :         const char *fname = BASEDIR "\\torture_file.txt";
    2983             :         NTSTATUS status;
    2984           0 :         int fnum1 = -1;
    2985           0 :         int fnum2 = -1;
    2986           0 :         bool ret = true;
    2987           0 :         double used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
    2988           0 :         int normal_delay = 2000000;
    2989           0 :         double sec = ((double)used_delay) / ((double)normal_delay);
    2990           0 :         int msec = 1000 * sec;
    2991           0 :         TALLOC_CTX *mem_ctx = talloc_init("test_delayed_write_update8");
    2992             : 
    2993           0 :         if (!mem_ctx) return false;
    2994             : 
    2995           0 :         torture_comment(tctx, "\nRunning test directory write update\n");
    2996             : 
    2997           0 :         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           0 :         ZERO_STRUCT(open_parms);
    3001           0 :         open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
    3002           0 :         open_parms.ntcreatex.in.flags = 0;
    3003           0 :         open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ;
    3004           0 :         open_parms.ntcreatex.in.file_attr = 0;
    3005           0 :         open_parms.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_DELETE|
    3006             :                                         NTCREATEX_SHARE_ACCESS_READ|
    3007             :                                         NTCREATEX_SHARE_ACCESS_WRITE;
    3008           0 :         open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
    3009           0 :         open_parms.ntcreatex.in.create_options = NTCREATEX_OPTIONS_DIRECTORY;
    3010           0 :         open_parms.ntcreatex.in.fname = BASEDIR;
    3011             : 
    3012           0 :         status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
    3013           0 :         talloc_free(mem_ctx);
    3014             : 
    3015           0 :         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           0 :         fnum1 = open_parms.ntcreatex.out.file.fnum;
    3023             : 
    3024             :         /* Store the returned write time. */
    3025           0 :         ZERO_STRUCT(dir_info1);
    3026           0 :         dir_info1.basic_info.out.write_time = open_parms.ntcreatex.out.write_time;
    3027             : 
    3028           0 :         torture_comment(tctx, "Initial write time %s\n",
    3029             :                nt_time_string(tctx, dir_info1.basic_info.out.write_time));
    3030             : 
    3031             :         /* sleep */
    3032           0 :         smb_msleep(3 * msec);
    3033             : 
    3034             :         /* Now create a file within the directory. */
    3035           0 :         fnum2 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
    3036           0 :         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           0 :         smbcli_close(cli->tree, fnum2);
    3042             : 
    3043             :         /* Read the directory write time again. */
    3044           0 :         ZERO_STRUCT(dir_info2);
    3045           0 :         dir_info2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
    3046           0 :         dir_info2.basic_info.in.file.fnum = fnum1;
    3047             : 
    3048           0 :         status = smb_raw_fileinfo(cli->tree, tctx, &dir_info2);
    3049             : 
    3050           0 :         torture_assert_ntstatus_ok(tctx, status, "fileinfo failed");
    3051             : 
    3052             :         /* Ensure it's been incremented. */
    3053           0 :         COMPARE_WRITE_TIME_GREATER(dir_info2, dir_info1);
    3054             : 
    3055           0 :         torture_comment(tctx, "Updated write time %s\n",
    3056             :                nt_time_string(tctx, dir_info2.basic_info.out.write_time));
    3057             : 
    3058           0 :  done:
    3059             : 
    3060           0 :         if (fnum1 != -1)
    3061           0 :                 smbcli_close(cli->tree, fnum1);
    3062           0 :         smbcli_unlink(cli->tree, fname);
    3063           0 :         smbcli_deltree(cli->tree, BASEDIR);
    3064             : 
    3065           0 :         return ret;
    3066             : }
    3067             : 
    3068             : /*
    3069             :    testing of delayed update of write_time
    3070             : */
    3071         964 : struct torture_suite *torture_delay_write(TALLOC_CTX *ctx)
    3072             : {
    3073         964 :         struct torture_suite *suite = torture_suite_create(ctx, "delaywrite");
    3074             : 
    3075         964 :         torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
    3076         964 :         torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
    3077         964 :         torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate", test_delayed_write_update1);
    3078         964 :         torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
    3079         964 :         torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
    3080         964 :         torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
    3081         964 :         torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
    3082         964 :         torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
    3083         964 :         torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
    3084         964 :         torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
    3085         964 :         torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
    3086         964 :         torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
    3087         964 :         torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
    3088         964 :         torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
    3089         964 :         torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
    3090         964 :         torture_suite_add_1smb_test(suite, "timestamp resolution test", test_delayed_write_update7);
    3091         964 :         torture_suite_add_1smb_test(suite, "directory timestamp update test", test_directory_update8);
    3092             : 
    3093         964 :         return suite;
    3094             : }

Generated by: LCOV version 1.13