root/source4/torture/basic/delaywrite.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. test_delayed_write_update
  2. test_delayed_write_update1
  3. test_delayed_write_update1a
  4. test_delayed_write_update1b
  5. test_delayed_write_update1c
  6. test_delayed_write_update2
  7. test_finfo_after_write
  8. test_delayed_write_update3
  9. test_delayed_write_update3a
  10. test_delayed_write_update3b
  11. test_delayed_write_update3c
  12. test_delayed_write_update4
  13. test_delayed_write_update5
  14. test_delayed_write_update5b
  15. test_delayed_write_update6
  16. torture_delay_write

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

/* [<][>][^][v][top][bottom][index][help] */