A truncate write must be a smbcli_smbwrite, not a
[metze/samba/wb-ndr.git] / source / torture / basic / delaywrite.c
index e3d63c09ecc74f57a723c37d994579ddbf83c8c5..13319681bd2c5303b6eff2d6b31942b07aa7ad61 100644 (file)
@@ -40,7 +40,14 @@ static bool test_delayed_write_update(struct torture_context *tctx, struct smbcl
        int fnum1 = -1;
        bool ret = true;
        ssize_t written;
-       time_t t;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update\n");
 
        if (!torture_setup_dir(cli, BASEDIR)) {
                return false;
@@ -68,7 +75,7 @@ static bool test_delayed_write_update(struct torture_context *tctx, struct smbcl
 
        /* 3 second delay to ensure we get past any 2 second time
           granularity (older systems may have that) */
-       sleep(3);
+       msleep(3 * msec);
 
        written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
 
@@ -78,9 +85,9 @@ static bool test_delayed_write_update(struct torture_context *tctx, struct smbcl
                return false;
        }
 
-       t = time(NULL);
-
-       while (time(NULL) < t+120) {
+       start = timeval_current();
+       end = timeval_add(&start, (120*sec), 0);
+       while (!timeval_expired(&end)) {
                status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
 
                if (!NT_STATUS_IS_OK(status)) {
@@ -91,20 +98,22 @@ static bool test_delayed_write_update(struct torture_context *tctx, struct smbcl
                torture_comment(tctx, "write time %s\n", 
                       nt_time_string(tctx, finfo2.basic_info.out.write_time));
                if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
-                       int diff = time(NULL) - t;
-                       if (diff < 2) {
-                               torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                                               diff);
+                       double diff = timeval_elapsed(&start);
+                       if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "Server updated write_time after %.2f seconds"
+                                               "(1 sec == %.2f)(wrong!)\n",
+                                               diff, sec);
                                ret = false;
                                break;
                        }
 
-                       torture_comment(tctx, "Server updated write_time after %d seconds (correct)\n",
-                                       diff);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(correct)\n",
+                                       diff, sec);
                        break;
                }
-               sleep(1);
                fflush(stdout);
+               msleep(1 * msec);
        }
        
        if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
@@ -121,22 +130,23 @@ static bool test_delayed_write_update(struct torture_context *tctx, struct smbcl
        return ret;
 }
 
-/* 
- * Do as above, but using 2 connections.
- */
-
-static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli, 
-                                                                          struct smbcli_state *cli2)
+static bool test_delayed_write_update1(struct torture_context *tctx, struct smbcli_state *cli)
 {
-       union smb_fileinfo finfo1, finfo2;
-       const char *fname = BASEDIR "\\torture_file.txt";
+       union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
+       const char *fname = BASEDIR "\\torture_file1.txt";
        NTSTATUS status;
        int fnum1 = -1;
-       int fnum2 = -1;
        bool ret = true;
        ssize_t written;
-       time_t t;
-       union smb_flush flsh;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+       char buf[2048];
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update1\n");
 
        if (!torture_setup_dir(cli, BASEDIR)) {
                return false;
@@ -148,74 +158,19 @@ static bool test_delayed_write_update2(struct torture_context *tctx, struct smbc
                return false;
        }
 
-       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
-       finfo1.basic_info.in.file.fnum = fnum1;
-       finfo2 = finfo1;
-
-       status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
-               return false;
-       }
-       
-       torture_comment(tctx, "Initial write time %s\n", 
-              nt_time_string(tctx, finfo1.basic_info.out.write_time));
+       memset(buf, 'x', 2048);
+       written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
 
        /* 3 second delay to ensure we get past any 2 second time
           granularity (older systems may have that) */
-       sleep(3);
-
-       {
-               /* Try using setfileinfo instead of write to update write time. */
-               union smb_setfileinfo sfinfo;
-               time_t t_set = time(NULL);
-               sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
-               sfinfo.basic_info.in.file.fnum = fnum1;
-               sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
-               sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
-
-               /* I tried this with both + and - ve to see if it makes a different.
-                  It doesn't - once the filetime is set via setfileinfo it stays that way. */
-#if 1
-               unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
-#else
-               unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
-#endif
-               sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
-               sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
-
-               status = smb_raw_setfileinfo(cli->tree, &sfinfo);
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(0, ("sfileinfo failed: %s\n", nt_errstr(status)));
-                       return false;
-               }
-       }
-
-       finfo2.basic_info.in.file.path = fname;
-       
-       status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
-               return false;
-       }
-       torture_comment(tctx, "write time %s\n",
-              nt_time_string(tctx, finfo2.basic_info.out.write_time));
+       msleep(3 * msec);
 
-       if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
-               torture_comment(tctx, "Server updated write_time (correct)\n");
-       } else {
-               torture_comment(tctx, "Server did not update write time (wrong!)\n");
-               ret = false;
-       }
-
-       /* Now try a write to see if the write time gets reset. */
-
-       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
-       finfo1.basic_info.in.file.fnum = fnum1;
+       finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
+       finfo1.all_info.in.file.fnum = fnum1;
        finfo2 = finfo1;
+       finfo3 = finfo1;
+       pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
+       pinfo4.all_info.in.file.path = fname;
 
        status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
 
@@ -223,40 +178,22 @@ static bool test_delayed_write_update2(struct torture_context *tctx, struct smbc
                DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
                return false;
        }
-       
-       torture_comment(tctx, "Modified write time %s\n", 
-              nt_time_string(tctx, finfo1.basic_info.out.write_time));
 
+       torture_comment(tctx, "Initial write time %s\n", 
+              nt_time_string(tctx, finfo1.all_info.out.write_time));
 
-       torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
-
-       written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
+       /* Do a zero length SMBwrite call to truncate. */
+       written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
 
-       if (written != 10) {
-               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
+       if (written != 0) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
                       (int)written, __location__);
                return false;
        }
 
-       /* Just to prove to tridge that the an smbflush has no effect on
-          the write time :-). The setfileinfo IS STICKY. JRA. */
-
-       torture_comment(tctx, "Doing flush after write\n");
-
-       flsh.flush.level        = RAW_FLUSH_FLUSH;
-       flsh.flush.in.file.fnum = fnum1;
-       status = smb_raw_flush(cli->tree, &flsh);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
-               return false;
-       }
-
-       t = time(NULL);
-
-       /* Once the time was set using setfileinfo then it stays set - writes
-          don't have any effect. But make sure. */
-
-       while (time(NULL) < t+15) {
+       start = timeval_current();
+       end = timeval_add(&start, (120*sec), 0);
+       while (!timeval_expired(&end)) {
                status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
 
                if (!NT_STATUS_IS_OK(status)) {
@@ -264,124 +201,157 @@ static bool test_delayed_write_update2(struct torture_context *tctx, struct smbc
                        ret = false;
                        break;
                }
-               torture_comment(tctx, "write time %s\n", 
-                      nt_time_string(tctx, finfo2.basic_info.out.write_time));
-               if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
-                       torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                              (int)(time(NULL) - t));
+
+               if (finfo2.all_info.out.size != 1024) {
+                       DEBUG(0, ("file not truncated, size = %u (should be 1024)\n",
+                               (unsigned int)finfo2.all_info.out.size));
                        ret = false;
                        break;
                }
-               sleep(1);
+
+               torture_comment(tctx, "write time %s\n",
+                      nt_time_string(tctx, finfo2.all_info.out.write_time));
+               if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "After SMBwrite truncate "
+                                       "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(wrong!)\n",
+                                       diff, sec);
+                               ret = false;
+                               break;
+                       }
+
+                       torture_comment(tctx, "After SMBwrite truncate "
+                                       "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(correct)\n",
+                                       diff, sec);
+                       break;
+               }
                fflush(stdout);
-       }
-       
-       if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
-               torture_comment(tctx, "Server did not update write time (correct)\n");
+               msleep(1 * msec);
        }
 
-       fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
-       if (fnum2 == -1) {
-               torture_comment(tctx, "Failed to open %s\n", fname);
-               return false;
+       if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time (wrong!)\n");
+               ret = false;
        }
-       
-       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");
 
-       written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
+       /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
+       written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
 
-       if (written != 10) {
-               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
+       if (written != 1) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
                       (int)written, __location__);
                return false;
        }
 
-       status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+       start = timeval_current();
+       end = timeval_add(&start, (10*sec), 0);
+       while (!timeval_expired(&end)) {
+               status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
 
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
-               return false;
-       }
-       torture_comment(tctx, "write time %s\n", 
-              nt_time_string(tctx, finfo2.basic_info.out.write_time));
-       if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
-               torture_comment(tctx, "Server updated write_time (wrong!)\n");
-               ret = false;
-       }
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+                       ret = false;
+                       break;
+               }
 
-       torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
-       smbcli_close(cli->tree, fnum1);
-       fnum1 = -1;
+               if (finfo3.all_info.out.size != 1024) {
+                       DEBUG(0, ("file not truncated, size = %u (should be 1024)\n",
+                               (unsigned int)finfo3.all_info.out.size));
+                       ret = false;
+                       break;
+               }
 
-       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");
+               torture_comment(tctx, "write time %s\n",
+                      nt_time_string(tctx, finfo3.all_info.out.write_time));
+               if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
 
-       written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
+                       torture_comment(tctx, "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               fflush(stdout);
+               msleep(1 * msec);
+       }
 
-       if (written != 10) {
-               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
-                      (int)written, __location__);
-               return false;
+       if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
+               torture_comment(tctx, "Server updated write time (wrong!)\n");
+               ret = false;
        }
 
-       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
-       finfo1.basic_info.in.file.fnum = fnum2;
-       finfo2 = finfo1;
-       status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+       /* the close should trigger an write time update */
+       smbcli_close(cli->tree, fnum1);
+       fnum1 = -1;
 
+       status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
                return false;
        }
-       torture_comment(tctx, "write time %s\n", 
-              nt_time_string(tctx, finfo2.basic_info.out.write_time));
-       if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
-               torture_comment(tctx, "Server updated write_time (wrong!)\n");
+
+       if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
                ret = false;
+       } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
+               torture_comment(tctx, "Server updated write time on close (correct)\n");
        }
 
-       t = time(NULL);
+       if (fnum1 != -1)
+               smbcli_close(cli->tree, fnum1);
+       smbcli_unlink(cli->tree, fname);
+       smbcli_deltree(cli->tree, BASEDIR);
 
-       /* Once the time was set using setfileinfo then it stays set - writes
-          don't have any effect. But make sure. */
+       return ret;
+}
 
-       while (time(NULL) < t+15) {
-               status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+/* Updating with a SMBwrite of zero length
+ * changes the write time immediately - even on expand. */
 
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
-                       ret = false;
-                       break;
-               }
-               torture_comment(tctx, "write time %s\n", 
-                      nt_time_string(tctx, finfo2.basic_info.out.write_time));
-               if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
-                       torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                              (int)(time(NULL) - t));
-                       ret = false;
-                       break;
-               }
-               sleep(1);
-               fflush(stdout);
-       }
-       
-       if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
-               torture_comment(tctx, "Server did not update write time (correct)\n");
-       }
+static bool test_delayed_write_update1a(struct torture_context *tctx, struct smbcli_state *cli)
+{
+       union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
+       const char *fname = BASEDIR "\\torture_file1a.txt";
+       NTSTATUS status;
+       int fnum1 = -1;
+       bool ret = true;
+       ssize_t written;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+       char buf[2048];
 
-       torture_comment(tctx, "Closing second fd to see if write time updated.\n");
+       torture_comment(tctx, "\nRunning test_delayed_write_update1a\n");
 
-       smbcli_close(cli->tree, fnum2);
-       fnum2 = -1;
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
 
-       fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+       fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum1 == -1) {
                torture_comment(tctx, "Failed to open %s\n", fname);
                return false;
        }
 
-       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
-       finfo1.basic_info.in.file.fnum = fnum1;
+       memset(buf, 'x', 2048);
+       written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
+
+       /* 3 second delay to ensure we get past any 2 second time
+          granularity (older systems may have that) */
+       msleep(3 * msec);
+
+       finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
+       finfo1.all_info.in.file.fnum = fnum1;
        finfo2 = finfo1;
+       finfo3 = finfo1;
+       pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
+       pinfo4.all_info.in.file.path = fname;
 
        status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
 
@@ -389,42 +359,22 @@ static bool test_delayed_write_update2(struct torture_context *tctx, struct smbc
                DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
                return false;
        }
-       
-       torture_comment(tctx, "Second open initial write time %s\n", 
-              nt_time_string(tctx, finfo1.basic_info.out.write_time));
 
-       sleep(10);
-       torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
+       torture_comment(tctx, "Initial write time %s\n", 
+              nt_time_string(tctx, finfo1.all_info.out.write_time));
 
-       written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
+       /* Do a zero length SMBwrite call to truncate. */
+       written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
 
-       if (written != 10) {
-               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
+       if (written != 0) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
                       (int)written, __location__);
                return false;
        }
 
-       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
-       finfo1.basic_info.in.file.fnum = fnum1;
-       finfo2 = finfo1;
-       status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
-               return false;
-       }
-       torture_comment(tctx, "write time %s\n", 
-              nt_time_string(tctx, finfo2.basic_info.out.write_time));
-       if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
-               torture_comment(tctx, "Server updated write_time (wrong!)\n");
-               ret = false;
-       }
-
-       t = time(NULL);
-
-       /* Now the write time should be updated again */
-
-       while (time(NULL) < t+15) {
+       start = timeval_current();
+       end = timeval_add(&start, (120*sec), 0);
+       while (!timeval_expired(&end)) {
                status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
 
                if (!NT_STATUS_IS_OK(status)) {
@@ -432,34 +382,104 @@ static bool test_delayed_write_update2(struct torture_context *tctx, struct smbc
                        ret = false;
                        break;
                }
-               torture_comment(tctx, "write time %s\n", 
-                      nt_time_string(tctx, finfo2.basic_info.out.write_time));
-               if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
-                       int diff = time(NULL) - t;
-                       if (diff < 2) {
-                               torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                                               diff);
+
+               if (finfo2.all_info.out.size != 10240) {
+                       DEBUG(0, ("file not truncated, size = %u (should be 10240)\n",
+                               (unsigned int)finfo2.all_info.out.size));
+                       ret = false;
+                       break;
+               }
+
+               torture_comment(tctx, "write time %s\n",
+                      nt_time_string(tctx, finfo2.all_info.out.write_time));
+               if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "After SMBwrite truncate "
+                                       "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(wrong!)\n",
+                                       diff, sec);
                                ret = false;
                                break;
                        }
 
-                       torture_comment(tctx, "Server updated write_time after %d seconds (correct)\n",
-                                       diff);
+                       torture_comment(tctx, "After SMBwrite truncate "
+                                       "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(correct)\n",
+                                       diff, sec);
                        break;
                }
-               sleep(1);
                fflush(stdout);
+               msleep(1 * msec);
        }
-       
-       if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+
+       if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
                torture_comment(tctx, "Server did not update write time (wrong!)\n");
                ret = false;
        }
 
+       /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
+       written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
 
-       /* One more test to do. We should read the filetime via findfirst on the
-          second connection to ensure it's the same. This is very easy for a Windows
-          server but a bastard to get right on a POSIX server. JRA. */
+       if (written != 1) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
+                      (int)written, __location__);
+               return false;
+       }
+
+       start = timeval_current();
+       end = timeval_add(&start, (10*sec), 0);
+       while (!timeval_expired(&end)) {
+               status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+                       ret = false;
+                       break;
+               }
+
+               if (finfo3.all_info.out.size != 10240) {
+                       DEBUG(0, ("file not truncated, size = %u (should be 10240)\n",
+                               (unsigned int)finfo3.all_info.out.size));
+                       ret = false;
+                       break;
+               }
+
+               torture_comment(tctx, "write time %s\n",
+                      nt_time_string(tctx, finfo3.all_info.out.write_time));
+               if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+
+                       torture_comment(tctx, "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               fflush(stdout);
+               msleep(1 * msec);
+       }
+
+       if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
+               torture_comment(tctx, "Server updated write time (wrong!)\n");
+               ret = false;
+       }
+
+       /* the close should trigger an write time update */
+       smbcli_close(cli->tree, fnum1);
+       fnum1 = -1;
+
+       status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+
+       if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
+               ret = false;
+       } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
+               torture_comment(tctx, "Server updated write time on close (correct)\n");
+       }
 
        if (fnum1 != -1)
                smbcli_close(cli->tree, fnum1);
@@ -469,27 +489,26 @@ static bool test_delayed_write_update2(struct torture_context *tctx, struct smbc
        return ret;
 }
 
+/* Updating with a SET_FILE_END_OF_FILE_INFO
+ * changes the write time immediately - even on expand. */
 
-/* Windows does obviously not update the stat info during a write call. I
- * *think* this is the problem causing a spurious Excel 2003 on XP error
- * message when saving a file. Excel does a setfileinfo, writes, and then does
- * a getpath(!)info. Or so... For Samba sometimes it displays an error message
- * that the file might have been changed in between. What i've been able to
- * trace down is that this happens if the getpathinfo after the write shows a
- * different last write time than the setfileinfo showed. This is really
- * nasty....
- */
-
-static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli, 
-                                                                  struct smbcli_state *cli2)
+static bool test_delayed_write_update1b(struct torture_context *tctx, struct smbcli_state *cli)
 {
-       union smb_fileinfo finfo1, finfo2;
-       const char *fname = BASEDIR "\\torture_file.txt";
+       union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
+       const char *fname = BASEDIR "\\torture_file1b.txt";
        NTSTATUS status;
        int fnum1 = -1;
-       int fnum2;
        bool ret = true;
        ssize_t written;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+       char buf[2048];
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update1b\n");
 
        if (!torture_setup_dir(cli, BASEDIR)) {
                return false;
@@ -497,113 +516,152 @@ static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_s
 
        fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
        if (fnum1 == -1) {
-               ret = false;
-               torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
-               goto done;
+               torture_comment(tctx, "Failed to open %s\n", fname);
+               return false;
        }
 
-       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
-       finfo1.basic_info.in.file.fnum = fnum1;
+       memset(buf, 'x', 2048);
+       written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
+
+       /* 3 second delay to ensure we get past any 2 second time
+          granularity (older systems may have that) */
+       msleep(3 * msec);
+
+       finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
+       finfo1.all_info.in.file.fnum = fnum1;
+       finfo2 = finfo1;
+       finfo3 = finfo1;
+       pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
+       pinfo4.all_info.in.file.path = fname;
 
        status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
 
        if (!NT_STATUS_IS_OK(status)) {
-               ret = false;
-               torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
-               goto done;
+               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               return false;
        }
 
-       msleep(1000);
+       torture_comment(tctx, "Initial write time %s\n",
+              nt_time_string(tctx, finfo1.all_info.out.write_time));
 
-       written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+       /* Do a SET_END_OF_FILE_INFO call to truncate. */
+       status = smbcli_ftruncate(cli->tree, fnum1, (uint64_t)10240);
 
-       if (written != 1) {
-               torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
-               ret = false;
-               goto done;
+       if (!NT_STATUS_IS_OK(status)) {
+               torture_comment(tctx, "SET_END_OF_FILE failed (%s)\n",
+                      nt_errstr(status));
+               return false;
        }
 
-       fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
-       if (fnum2 == -1) {
-               torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s", 
-                      smbcli_errstr(cli2->tree));
-               ret = false;
-               goto done;
-       }
-       
-       written =  smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
-       
-       if (written != 1) {
-               torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", 
-                      (int)written);
-               ret = false;
-               goto done;
-       }
-       
-       finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
-       finfo2.basic_info.in.file.path = fname;
-       
-       status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
-       
-       if (!NT_STATUS_IS_OK(status)) {
-               torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", 
-                         nt_errstr(status));
-               ret = false;
-               goto done;
+       start = timeval_current();
+       end = timeval_add(&start, (120*sec), 0);
+       while (!timeval_expired(&end)) {
+               status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+                       ret = false;
+                       break;
+               }
+
+               if (finfo2.all_info.out.size != 10240) {
+                       DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
+                               (unsigned int)finfo2.all_info.out.size ));
+                       ret = false;
+                       break;
+               }
+
+               torture_comment(tctx, "write time %s\n",
+                      nt_time_string(tctx, finfo2.all_info.out.write_time));
+               if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "After SET_END_OF_FILE truncate "
+                                       "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(wrong!)\n",
+                                       diff, sec);
+                               ret = false;
+                               break;
+                       }
+
+                       torture_comment(tctx, "After SET_END_OF_FILE truncate "
+                                       "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               fflush(stdout);
+               msleep(1 * msec);
        }
-       
-       if (finfo1.basic_info.out.create_time !=
-           finfo2.basic_info.out.create_time) {
-               torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
+
+       if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time (wrong!)\n");
                ret = false;
-               goto done;
        }
-       
-       if (finfo1.basic_info.out.access_time !=
-           finfo2.basic_info.out.access_time) {
-               torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
-               ret = false;
-               goto done;
+
+       /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
+       written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
+
+       if (written != 1) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
+                      (int)written, __location__);
+               return false;
        }
-       
-       if (finfo1.basic_info.out.write_time !=
-           finfo2.basic_info.out.write_time) {
-               torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
-                                          "write time conn 1 = %s, conn 2 = %s", 
-                      nt_time_string(tctx, finfo1.basic_info.out.write_time),
-                      nt_time_string(tctx, finfo2.basic_info.out.write_time));
-               ret = false;
-               goto done;
+
+       start = timeval_current();
+       end = timeval_add(&start, (10*sec), 0);
+       while (!timeval_expired(&end)) {
+               status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+                       ret = false;
+                       break;
+               }
+
+               if (finfo3.all_info.out.size != 10240) {
+                       DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
+                               (unsigned int)finfo3.all_info.out.size ));
+                       ret = false;
+                       break;
+               }
+
+               torture_comment(tctx, "write time %s\n",
+                      nt_time_string(tctx, finfo3.all_info.out.write_time));
+               if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+
+                       torture_comment(tctx, "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               fflush(stdout);
+               msleep(1 * msec);
        }
-       
-       if (finfo1.basic_info.out.change_time !=
-           finfo2.basic_info.out.change_time) {
-               torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
+
+       if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
+               torture_comment(tctx, "Server updated write time (wrong!)\n");
                ret = false;
-               goto done;
        }
-       
-       /* One of the two following calls updates the qpathinfo. */
-       
-       /* If you had skipped the smbcli_write on fnum2, it would
-        * *not* have updated the stat on disk */
-       
-       smbcli_close(cli2->tree, fnum2);
-       cli2 = NULL;
-
-       /* This call is only for the people looking at ethereal :-) */
-       finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
-       finfo2.basic_info.in.file.path = fname;
 
-       status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
+       /* the close should trigger an write time update */
+       smbcli_close(cli->tree, fnum1);
+       fnum1 = -1;
 
+       status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
        if (!NT_STATUS_IS_OK(status)) {
-               torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
+               DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+
+       if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
                ret = false;
-               goto done;
+       } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
+               torture_comment(tctx, "Server updated write time on close (correct)\n");
        }
 
- done:
        if (fnum1 != -1)
                smbcli_close(cli->tree, fnum1);
        smbcli_unlink(cli->tree, fname);
@@ -612,119 +670,1334 @@ static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_s
        return ret;
 }
 
-#define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
-       NTTIME g = (given).basic_info.out.write_time; \
-       NTTIME c = (correct).basic_info.out.write_time; \
-       if (g cmp c) { \
-               torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s %s (%s)%s", \
-                               #given, nt_time_string(tctx, g), \
-                               #cmp, #correct, nt_time_string(tctx, c)); \
-               ret = false; \
-               goto done; \
-       } \
-} while (0)
-#define COMPARE_WRITE_TIME_EQUAL(given,correct) \
-       COMPARE_WRITE_TIME_CMP(given,correct,!=)
-#define COMPARE_WRITE_TIME_GREATER(given,correct) \
-       COMPARE_WRITE_TIME_CMP(given,correct,<=)
-#define COMPARE_WRITE_TIME_LESS(given,correct) \
-       COMPARE_WRITE_TIME_CMP(given,correct,>=)
+/* Updating with a SET_ALLOCATION_INFO (truncate) does so immediately. */
 
-#define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
-       NTTIME g = (given).basic_info.out.access_time; \
-       NTTIME c = (correct).basic_info.out.access_time; \
-       if (g cmp c) { \
-               torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
-                               #given, nt_time_string(tctx, g), \
-                               #cmp, #correct, nt_time_string(tctx, c)); \
-               ret = false; \
-               goto done; \
-       } \
-} while (0)
-#define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
-       COMPARE_ACCESS_TIME_CMP(given,correct,!=)
-#define COMPARE_ACCESS_TIME_GREATER(given,correct) \
-       COMPARE_ACCESS_TIME_CMP(given,correct,<=)
-#define COMPARE_ACCESS_TIME_LESS(given,correct) \
-       COMPARE_ACCESS_TIME_CMP(given,correct,>=)
+static bool test_delayed_write_update1c(struct torture_context *tctx, struct smbcli_state *cli)
+{
+        union smb_setfileinfo parms;
+       union smb_fileinfo finfo1, finfo2, finfo3, pinfo4;
+       const char *fname = BASEDIR "\\torture_file1c.txt";
+       NTSTATUS status;
+       int fnum1 = -1;
+       bool ret = true;
+       ssize_t written;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+       char buf[2048];
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update1c\n");
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
+
+       fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum1 == -1) {
+               torture_comment(tctx, "Failed to open %s\n", fname);
+               return false;
+       }
+
+       memset(buf, 'x', 2048);
+       written =  smbcli_write(cli->tree, fnum1, 0, buf, 0, 2048);
+
+       /* 3 second delay to ensure we get past any 2 second time
+          granularity (older systems may have that) */
+       msleep(3 * msec);
+
+       finfo1.all_info.level = RAW_FILEINFO_ALL_INFO;
+       finfo1.all_info.in.file.fnum = fnum1;
+       finfo2 = finfo1;
+       finfo3 = finfo1;
+       pinfo4.all_info.level = RAW_FILEINFO_ALL_INFO;
+       pinfo4.all_info.in.file.path = fname;
+
+       status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+
+       torture_comment(tctx, "Initial write time %s\n",
+              nt_time_string(tctx, finfo1.all_info.out.write_time));
+
+       /* Do a SET_ALLOCATION_SIZE call to truncate. */
+       parms.allocation_info.level = RAW_SFILEINFO_ALLOCATION_INFO;
+       parms.allocation_info.in.file.fnum = fnum1;
+       parms.allocation_info.in.alloc_size = 0;
+
+        status = smb_raw_setfileinfo(cli->tree, &parms);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               torture_comment(tctx, "RAW_SFILEINFO_ALLOCATION_INFO failed (%s)\n",
+                      nt_errstr(status));
+               return false;
+       }
+
+       start = timeval_current();
+       end = timeval_add(&start, (120*sec), 0);
+       while (!timeval_expired(&end)) {
+               status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+                       ret = false;
+                       break;
+               }
+
+               if (finfo2.all_info.out.size != 0) {
+                       DEBUG(0, ("file not truncated (size = %u, should be 10240)\n",
+                               (unsigned int)finfo2.all_info.out.size ));
+                       ret = false;
+                       break;
+               }
+
+               torture_comment(tctx, "write time %s\n",
+                      nt_time_string(tctx, finfo2.all_info.out.write_time));
+               if (finfo1.all_info.out.write_time != finfo2.all_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       if (diff > (0.25 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
+                                       "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(wrong!)\n",
+                                       diff, sec);
+                               ret = false;
+                               break;
+                       }
+
+                       torture_comment(tctx, "After SET_ALLOCATION_INFO truncate "
+                                       "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               fflush(stdout);
+               msleep(1 * msec);
+       }
+
+       if (finfo1.all_info.out.write_time == finfo2.all_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time (wrong!)\n");
+               ret = false;
+       }
+
+       /* Do a non-zero length SMBwrite and make sure it doesn't update the write time. */
+       written = smbcli_smbwrite(cli->tree, fnum1, "x", 0, 1);
+
+       if (written != 1) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n",
+                      (int)written, __location__);
+               return false;
+       }
+
+       start = timeval_current();
+       end = timeval_add(&start, (10*sec), 0);
+       while (!timeval_expired(&end)) {
+               status = smb_raw_fileinfo(cli->tree, tctx, &finfo3);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+                       ret = false;
+                       break;
+               }
+
+               if (finfo3.all_info.out.size != 1) {
+                       DEBUG(0, ("file not expanded\n"));
+                       ret = false;
+                       break;
+               }
+
+               torture_comment(tctx, "write time %s\n",
+                      nt_time_string(tctx, finfo3.all_info.out.write_time));
+               if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+
+                       torture_comment(tctx, "server updated write_time after %.2f seconds"
+                                       "(1 sec == %.2f)(correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               fflush(stdout);
+               msleep(1 * msec);
+       }
+
+       if (finfo2.all_info.out.write_time != finfo3.all_info.out.write_time) {
+               torture_comment(tctx, "Server updated write time (wrong!)\n");
+               ret = false;
+       }
+
+       /* the close should trigger an write time update */
+       smbcli_close(cli->tree, fnum1);
+       fnum1 = -1;
+
+       status = smb_raw_pathinfo(cli->tree, tctx, &pinfo4);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("pathinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+
+       if (finfo3.all_info.out.write_time == pinfo4.all_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time on close (wrong!)\n");
+               ret = false;
+       } else if (finfo3.all_info.out.write_time < pinfo4.all_info.out.write_time) {
+               torture_comment(tctx, "Server updated write time on close (correct)\n");
+       }
+
+       if (fnum1 != -1)
+               smbcli_close(cli->tree, fnum1);
+       smbcli_unlink(cli->tree, fname);
+       smbcli_deltree(cli->tree, BASEDIR);
+
+       return ret;
+}
+
+/*
+ * Do as above, but using 2 connections.
+ */
+
+static bool test_delayed_write_update2(struct torture_context *tctx, struct smbcli_state *cli, 
+                                                                          struct smbcli_state *cli2)
+{
+       union smb_fileinfo finfo1, finfo2;
+       const char *fname = BASEDIR "\\torture_file.txt";
+       NTSTATUS status;
+       int fnum1 = -1;
+       int fnum2 = -1;
+       bool ret = true;
+       ssize_t written;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+       union smb_flush flsh;
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update2\n");
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
+
+       fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum1 == -1) {
+               torture_comment(tctx, "Failed to open %s\n", fname);
+               return false;
+       }
+
+       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo1.basic_info.in.file.fnum = fnum1;
+       finfo2 = finfo1;
+
+       status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+       
+       torture_comment(tctx, "Initial write time %s\n", 
+              nt_time_string(tctx, finfo1.basic_info.out.write_time));
+
+       /* 3 second delay to ensure we get past any 2 second time
+          granularity (older systems may have that) */
+       msleep(3 * msec);
+
+       {
+               /* Try using setfileinfo instead of write to update write time. */
+               union smb_setfileinfo sfinfo;
+               time_t t_set = time(NULL);
+               sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO;
+               sfinfo.basic_info.in.file.fnum = fnum1;
+               sfinfo.basic_info.in.create_time = finfo1.basic_info.out.create_time;
+               sfinfo.basic_info.in.access_time = finfo1.basic_info.out.access_time;
+
+               /* I tried this with both + and - ve to see if it makes a different.
+                  It doesn't - once the filetime is set via setfileinfo it stays that way. */
+#if 1
+               unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set - 30000);
+#else
+               unix_to_nt_time(&sfinfo.basic_info.in.write_time, t_set + 30000);
+#endif
+               sfinfo.basic_info.in.change_time = finfo1.basic_info.out.change_time;
+               sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib;
+
+               status = smb_raw_setfileinfo(cli->tree, &sfinfo);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("sfileinfo failed: %s\n", nt_errstr(status)));
+                       return false;
+               }
+       }
+
+       finfo2.basic_info.in.file.path = fname;
+       
+       status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+       torture_comment(tctx, "write time %s\n",
+              nt_time_string(tctx, finfo2.basic_info.out.write_time));
+
+       if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+               torture_comment(tctx, "Server updated write_time (correct)\n");
+       } else {
+               torture_comment(tctx, "Server did not update write time (wrong!)\n");
+               ret = false;
+       }
+
+       /* Now try a write to see if the write time gets reset. */
+
+       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo1.basic_info.in.file.fnum = fnum1;
+       finfo2 = finfo1;
+
+       status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+       
+       torture_comment(tctx, "Modified write time %s\n", 
+              nt_time_string(tctx, finfo1.basic_info.out.write_time));
+
+
+       torture_comment(tctx, "Doing a 10 byte write to extend the file and see if this changes the last write time.\n");
+
+       written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 1, 10);
+
+       if (written != 10) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
+                      (int)written, __location__);
+               return false;
+       }
+
+       /* Just to prove to tridge that the an smbflush has no effect on
+          the write time :-). The setfileinfo IS STICKY. JRA. */
+
+       torture_comment(tctx, "Doing flush after write\n");
+
+       flsh.flush.level        = RAW_FLUSH_FLUSH;
+       flsh.flush.in.file.fnum = fnum1;
+       status = smb_raw_flush(cli->tree, &flsh);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("smbflush failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+
+       /* Once the time was set using setfileinfo then it stays set - writes
+          don't have any effect. But make sure. */
+       start = timeval_current();
+       end = timeval_add(&start, (15*sec), 0);
+       while (!timeval_expired(&end)) {
+               status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+                       ret = false;
+                       break;
+               }
+               torture_comment(tctx, "write time %s\n", 
+                      nt_time_string(tctx, finfo2.basic_info.out.write_time));
+               if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds"
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
+                       ret = false;
+                       break;
+               }
+               fflush(stdout);
+               msleep(1 * msec);
+       }
+       
+       if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time (correct)\n");
+       }
+
+       fnum2 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+       if (fnum2 == -1) {
+               torture_comment(tctx, "Failed to open %s\n", fname);
+               return false;
+       }
+       
+       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");
+
+       written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 11, 10);
+
+       if (written != 10) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
+                      (int)written, __location__);
+               return false;
+       }
+
+       status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+       torture_comment(tctx, "write time %s\n", 
+              nt_time_string(tctx, finfo2.basic_info.out.write_time));
+       if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+               torture_comment(tctx, "Server updated write_time (wrong!)\n");
+               ret = false;
+       }
+
+       torture_comment(tctx, "Closing the first fd to see if write time updated.\n");
+       smbcli_close(cli->tree, fnum1);
+       fnum1 = -1;
+
+       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");
+
+       written =  smbcli_write(cli->tree, fnum2, 0, "0123456789", 21, 10);
+
+       if (written != 10) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
+                      (int)written, __location__);
+               return false;
+       }
+
+       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo1.basic_info.in.file.fnum = fnum2;
+       finfo2 = finfo1;
+       status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+       torture_comment(tctx, "write time %s\n", 
+              nt_time_string(tctx, finfo2.basic_info.out.write_time));
+       if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+               torture_comment(tctx, "Server updated write_time (wrong!)\n");
+               ret = false;
+       }
+
+       /* Once the time was set using setfileinfo then it stays set - writes
+          don't have any effect. But make sure. */
+       start = timeval_current();
+       end = timeval_add(&start, (15*sec), 0);
+       while (!timeval_expired(&end)) {
+               status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+                       ret = false;
+                       break;
+               }
+               torture_comment(tctx, "write time %s\n", 
+                      nt_time_string(tctx, finfo2.basic_info.out.write_time));
+               if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
+                       ret = false;
+                       break;
+               }
+               fflush(stdout);
+               msleep(1 * msec);
+       }
+       
+       if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time (correct)\n");
+       }
+
+       torture_comment(tctx, "Closing second fd to see if write time updated.\n");
+
+       smbcli_close(cli->tree, fnum2);
+       fnum2 = -1;
+
+       fnum1 = smbcli_open(cli->tree, fname, O_RDWR, DENY_NONE);
+       if (fnum1 == -1) {
+               torture_comment(tctx, "Failed to open %s\n", fname);
+               return false;
+       }
+
+       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo1.basic_info.in.file.fnum = fnum1;
+       finfo2 = finfo1;
+
+       status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+       
+       torture_comment(tctx, "Second open initial write time %s\n", 
+              nt_time_string(tctx, finfo1.basic_info.out.write_time));
+
+       msleep(10 * msec);
+       torture_comment(tctx, "Doing a 10 byte write to extend the file to see if this changes the last write time.\n");
+
+       written =  smbcli_write(cli->tree, fnum1, 0, "0123456789", 31, 10);
+
+       if (written != 10) {
+               torture_comment(tctx, "write failed - wrote %d bytes (%s)\n", 
+                      (int)written, __location__);
+               return false;
+       }
+
+       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo1.basic_info.in.file.fnum = fnum1;
+       finfo2 = finfo1;
+       status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+               return false;
+       }
+       torture_comment(tctx, "write time %s\n", 
+              nt_time_string(tctx, finfo2.basic_info.out.write_time));
+       if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+               torture_comment(tctx, "Server updated write_time (wrong!)\n");
+               ret = false;
+       }
+
+       /* Now the write time should be updated again */
+       start = timeval_current();
+       end = timeval_add(&start, (15*sec), 0);
+       while (!timeval_expired(&end)) {
+               status = smb_raw_fileinfo(cli->tree, tctx, &finfo2);
+
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("fileinfo failed: %s\n", nt_errstr(status)));
+                       ret = false;
+                       break;
+               }
+               torture_comment(tctx, "write time %s\n", 
+                      nt_time_string(tctx, finfo2.basic_info.out.write_time));
+               if (finfo1.basic_info.out.write_time != finfo2.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "Server updated write_time after %.2f seconds"
+                                               "(1sec == %.2f) (wrong!)\n",
+                                               diff, sec);
+                               ret = false;
+                               break;
+                       }
+
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds"
+                                       "(1sec == %.2f) (correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               fflush(stdout);
+               msleep(1*msec);
+       }
+       
+       if (finfo1.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write time (wrong!)\n");
+               ret = false;
+       }
+
+
+       /* One more test to do. We should read the filetime via findfirst on the
+          second connection to ensure it's the same. This is very easy for a Windows
+          server but a bastard to get right on a POSIX server. JRA. */
+
+       if (fnum1 != -1)
+               smbcli_close(cli->tree, fnum1);
+       smbcli_unlink(cli->tree, fname);
+       smbcli_deltree(cli->tree, BASEDIR);
+
+       return ret;
+}
+
+
+/* Windows does obviously not update the stat info during a write call. I
+ * *think* this is the problem causing a spurious Excel 2003 on XP error
+ * message when saving a file. Excel does a setfileinfo, writes, and then does
+ * a getpath(!)info. Or so... For Samba sometimes it displays an error message
+ * that the file might have been changed in between. What i've been able to
+ * trace down is that this happens if the getpathinfo after the write shows a
+ * different last write time than the setfileinfo showed. This is really
+ * nasty....
+ */
+
+static bool test_finfo_after_write(struct torture_context *tctx, struct smbcli_state *cli, 
+                                                                  struct smbcli_state *cli2)
+{
+       union smb_fileinfo finfo1, finfo2;
+       const char *fname = BASEDIR "\\torture_file.txt";
+       NTSTATUS status;
+       int fnum1 = -1;
+       int fnum2;
+       bool ret = true;
+       ssize_t written;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+
+       torture_comment(tctx, "\nRunning test_finfo_after_write\n");
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
+
+       fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum1 == -1) {
+               ret = false;
+               torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+               goto done;
+       }
+
+       finfo1.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo1.basic_info.in.file.fnum = fnum1;
+
+       status = smb_raw_fileinfo(cli->tree, tctx, &finfo1);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               ret = false;
+               torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
+               goto done;
+       }
+
+       msleep(1 * msec);
+
+       written =  smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+
+       if (written != 1) {
+               torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+               ret = false;
+               goto done;
+       }
+
+       fnum2 = smbcli_open(cli2->tree, fname, O_RDWR, DENY_NONE);
+       if (fnum2 == -1) {
+               torture_result(tctx, TORTURE_FAIL, __location__": failed to open 2nd time - %s", 
+                      smbcli_errstr(cli2->tree));
+               ret = false;
+               goto done;
+       }
+       
+       written =  smbcli_write(cli2->tree, fnum2, 0, "x", 0, 1);
+       
+       if (written != 1) {
+               torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", 
+                      (int)written);
+               ret = false;
+               goto done;
+       }
+       
+       finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo2.basic_info.in.file.path = fname;
+       
+       status = smb_raw_pathinfo(cli2->tree, tctx, &finfo2);
+       
+       if (!NT_STATUS_IS_OK(status)) {
+               torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", 
+                         nt_errstr(status));
+               ret = false;
+               goto done;
+       }
+       
+       if (finfo1.basic_info.out.create_time !=
+           finfo2.basic_info.out.create_time) {
+               torture_result(tctx, TORTURE_FAIL, __location__": create_time changed");
+               ret = false;
+               goto done;
+       }
+       
+       if (finfo1.basic_info.out.access_time !=
+           finfo2.basic_info.out.access_time) {
+               torture_result(tctx, TORTURE_FAIL, __location__": access_time changed");
+               ret = false;
+               goto done;
+       }
+       
+       if (finfo1.basic_info.out.write_time !=
+           finfo2.basic_info.out.write_time) {
+               torture_result(tctx, TORTURE_FAIL, __location__": write_time changed:\n"
+                                          "write time conn 1 = %s, conn 2 = %s", 
+                      nt_time_string(tctx, finfo1.basic_info.out.write_time),
+                      nt_time_string(tctx, finfo2.basic_info.out.write_time));
+               ret = false;
+               goto done;
+       }
+       
+       if (finfo1.basic_info.out.change_time !=
+           finfo2.basic_info.out.change_time) {
+               torture_result(tctx, TORTURE_FAIL, __location__": change_time changed");
+               ret = false;
+               goto done;
+       }
+       
+       /* One of the two following calls updates the qpathinfo. */
+       
+       /* If you had skipped the smbcli_write on fnum2, it would
+        * *not* have updated the stat on disk */
+       
+       smbcli_close(cli2->tree, fnum2);
+       cli2 = NULL;
+
+       /* This call is only for the people looking at ethereal :-) */
+       finfo2.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo2.basic_info.in.file.path = fname;
+
+       status = smb_raw_pathinfo(cli->tree, tctx, &finfo2);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", nt_errstr(status));
+               ret = false;
+               goto done;
+       }
+
+ done:
+       if (fnum1 != -1)
+               smbcli_close(cli->tree, fnum1);
+       smbcli_unlink(cli->tree, fname);
+       smbcli_deltree(cli->tree, BASEDIR);
+
+       return ret;
+}
+
+#define COMPARE_WRITE_TIME_CMP(given, correct, cmp) do { \
+       uint64_t r = 10*1000*1000; \
+       NTTIME g = (given).basic_info.out.write_time; \
+       NTTIME gr = (g / r) * r; \
+       NTTIME c = (correct).basic_info.out.write_time; \
+       NTTIME cr = (c / r) * r; \
+       bool strict = torture_setting_bool(tctx, "strict mode", false); \
+       bool err = false; \
+       if (strict && (g cmp c)) { \
+               err = true; \
+       } else if ((g cmp c) && (gr cmp cr)) { \
+               /* handle filesystem without high resolution timestamps */ \
+               err = true; \
+       } \
+       if (err) { \
+               torture_result(tctx, TORTURE_FAIL, __location__": wrong write_time (%s)%s(%llu) %s (%s)%s(%llu)", \
+                               #given, nt_time_string(tctx, g), (unsigned long long)g, \
+                               #cmp, #correct, nt_time_string(tctx, c), (unsigned long long)c); \
+               ret = false; \
+               goto done; \
+       } \
+} while (0)
+#define COMPARE_WRITE_TIME_EQUAL(given,correct) \
+       COMPARE_WRITE_TIME_CMP(given,correct,!=)
+#define COMPARE_WRITE_TIME_GREATER(given,correct) \
+       COMPARE_WRITE_TIME_CMP(given,correct,<=)
+#define COMPARE_WRITE_TIME_LESS(given,correct) \
+       COMPARE_WRITE_TIME_CMP(given,correct,>=)
+
+#define COMPARE_ACCESS_TIME_CMP(given, correct, cmp) do { \
+       NTTIME g = (given).basic_info.out.access_time; \
+       NTTIME c = (correct).basic_info.out.access_time; \
+       if (g cmp c) { \
+               torture_result(tctx, TORTURE_FAIL, __location__": wrong access_time (%s)%s %s (%s)%s", \
+                               #given, nt_time_string(tctx, g), \
+                               #cmp, #correct, nt_time_string(tctx, c)); \
+               ret = false; \
+               goto done; \
+       } \
+} while (0)
+#define COMPARE_ACCESS_TIME_EQUAL(given,correct) \
+       COMPARE_ACCESS_TIME_CMP(given,correct,!=)
+
+#define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
+       COMPARE_ACCESS_TIME_EQUAL(given,correct); \
+       COMPARE_WRITE_TIME_EQUAL(given,correct); \
+} while (0)
+
+#define GET_INFO_FILE(finfo) do { \
+       NTSTATUS _status; \
+       _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
+       if (!NT_STATUS_IS_OK(_status)) { \
+               ret = false; \
+               torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
+                              nt_errstr(_status)); \
+               goto done; \
+       } \
+       torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
+                       nt_time_string(tctx, finfo.basic_info.out.access_time), \
+                       nt_time_string(tctx, finfo.basic_info.out.write_time)); \
+} while (0)
+#define GET_INFO_PATH(pinfo) do { \
+       NTSTATUS _status; \
+       _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
+       if (!NT_STATUS_IS_OK(_status)) { \
+               torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
+                              nt_errstr(_status)); \
+               ret = false; \
+               goto done; \
+       } \
+       torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
+                       nt_time_string(tctx, pinfo.basic_info.out.access_time), \
+                       nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
+} while (0)
+#define GET_INFO_BOTH(finfo,pinfo) do { \
+       GET_INFO_FILE(finfo); \
+       GET_INFO_PATH(pinfo); \
+       COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
+} while (0)
+
+#define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
+       NTSTATUS _status; \
+       union smb_setfileinfo sfinfo; \
+       sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
+       sfinfo.basic_info.in.file.fnum = tfnum; \
+       sfinfo.basic_info.in.create_time = 0; \
+       sfinfo.basic_info.in.access_time = 0; \
+       unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
+       sfinfo.basic_info.in.change_time = 0; \
+       sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
+       _status = smb_raw_setfileinfo(tree, &sfinfo); \
+       if (!NT_STATUS_IS_OK(_status)) { \
+               torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
+                              nt_errstr(_status)); \
+               ret = false; \
+               goto done; \
+       } \
+} while (0)
+#define SET_INFO_FILE(finfo, wrtime) \
+       SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
+
+static bool test_delayed_write_update3(struct torture_context *tctx,
+                                      struct smbcli_state *cli,
+                                      struct smbcli_state *cli2)
+{
+       union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
+       union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
+       const char *fname = BASEDIR "\\torture_file3.txt";
+       int fnum1 = -1;
+       bool ret = true;
+       ssize_t written;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update3\n");
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
+
+       torture_comment(tctx, "Open the file handle\n");
+       fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum1 == -1) {
+               ret = false;
+               torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+               goto done;
+       }
+
+       finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo0.basic_info.in.file.fnum = fnum1;
+       finfo1 = finfo0;
+       finfo2 = finfo0;
+       finfo3 = finfo0;
+       finfo4 = finfo0;
+       pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       pinfo0.basic_info.in.file.path = fname;
+       pinfo1 = pinfo0;
+       pinfo2 = pinfo0;
+       pinfo3 = pinfo0;
+       pinfo4 = pinfo0;
+       pinfo5 = pinfo0;
+
+       /* get the initial times */
+       GET_INFO_BOTH(finfo0,pinfo0);
+
+       /*
+        * make sure the write time is updated 2 seconds later
+        * calcuated from the first write
+        * (but expect upto 5 seconds extra time for a busy server)
+        */
+       start = timeval_current();
+       end = timeval_add(&start, 7 * sec, 0);
+       while (!timeval_expired(&end)) {
+               /* do a write */
+               torture_comment(tctx, "Do a write on the file handle\n");
+               written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+               if (written != 1) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_FILE(finfo1);
+
+               if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                               "(1sec == %.2f) (wrong!)\n",
+                                               diff, sec);
+                               ret = false;
+                               break;
+                       }
+
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               msleep(0.5 * msec);
+       }
+
+       GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
+
+       /* sure any further write doesn't update the write time */
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
+               /* do a write */
+               torture_comment(tctx, "Do a write on the file handle\n");
+               written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+               if (written != 1) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_BOTH(finfo2,pinfo2);
+
+               if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
+                       ret = false;
+                       break;
+               }
+               msleep(2 * msec);
+       }
+
+       GET_INFO_BOTH(finfo2,pinfo2);
+       COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+       if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write_time (correct)\n");
+       }
+
+       /* sleep */
+       msleep(5 * msec);
+
+       GET_INFO_BOTH(finfo3,pinfo3);
+       COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+
+       /*
+        * the close updates the write time to the time of the close
+        * and not to the time of the last write!
+        */
+       torture_comment(tctx, "Close the file handle\n");
+       smbcli_close(cli->tree, fnum1);
+       fnum1 = -1;
+
+       GET_INFO_PATH(pinfo4);
+       COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
+
+       if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
+               torture_comment(tctx, "Server updated the write_time on close (correct)\n");
+       }
+
+ done:
+       if (fnum1 != -1)
+               smbcli_close(cli->tree, fnum1);
+       smbcli_unlink(cli->tree, fname);
+       smbcli_deltree(cli->tree, BASEDIR);
+
+       return ret;
+}
+
+static bool test_delayed_write_update3a(struct torture_context *tctx,
+                                       struct smbcli_state *cli,
+                                       struct smbcli_state *cli2)
+{
+       union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
+       union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
+       const char *fname = BASEDIR "\\torture_file3a.txt";
+       int fnum1 = -1;
+       bool ret = true;
+       ssize_t written;
+       int i;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update3a\n");
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
+
+       torture_comment(tctx, "Open the file handle\n");
+       fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum1 == -1) {
+               ret = false;
+               torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+               goto done;
+       }
+
+       finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo0.basic_info.in.file.fnum = fnum1;
+       finfo1 = finfo0;
+       finfo2 = finfo0;
+       finfo3 = finfo0;
+       finfo4 = finfo0;
+       pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       pinfo0.basic_info.in.file.path = fname;
+       pinfo1 = pinfo0;
+       pinfo2 = pinfo0;
+       pinfo3 = pinfo0;
+       pinfo4 = pinfo0;
+       pinfo5 = pinfo0;
+
+       /* get the initial times */
+       GET_INFO_BOTH(finfo0,pinfo0);
+
+       /*
+        * sleep some time, to demonstrate the handling of write times
+        * doesn't depend on the time since the open
+        */
+       msleep(5 * msec);
+
+       /* get the initial times */
+       GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+       /*
+        * make sure the write time is updated 2 seconds later
+        * calcuated from the first write
+        * (but expect upto 5 seconds extra time for a busy server)
+        */
+       start = timeval_current();
+       end = timeval_add(&start, 7 * sec, 0);
+       while (!timeval_expired(&end)) {
+               /* do a write */
+               torture_comment(tctx, "Do a write on the file handle\n");
+               written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+               if (written != 1) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_FILE(finfo1);
+
+               if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                               "(1sec == %.2f) (wrong!)\n",
+                                               diff, sec);
+                               ret = false;
+                               break;
+                       }
+
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               msleep(0.5 * msec);
+       }
+
+       GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
+
+       /*
+        * demonstrate that a truncate write always
+        * updates the write time immediately
+        */
+       for (i=0; i < 3; i++) {
+               msleep(1 * msec);
+               /* do a write */
+               torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
+               written = smbcli_smbwrite(cli->tree, fnum1, "x", 10240, 0);
+               if (written != 0) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_BOTH(finfo2,pinfo2);
+               COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+               finfo1 = finfo2;
+       }
+
+       /* sure any further write doesn't update the write time */
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
+               /* do a write */
+               torture_comment(tctx, "Do a write on the file handle\n");
+               written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+               if (written != 1) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_BOTH(finfo2,pinfo2);
+
+               if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
+                       ret = false;
+                       break;
+               }
+               msleep(2 * msec);
+       }
+
+       GET_INFO_BOTH(finfo2,pinfo2);
+       COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+       if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write_time (correct)\n");
+       }
+
+       /* sleep */
+       msleep(5 * msec);
+
+       /* get the initial times */
+       GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
+
+       /*
+        * demonstrate that a truncate write always
+        * updates the write time immediately
+        */
+       for (i=0; i < 3; i++) {
+               msleep(1 * msec);
+               /* do a write */
+               torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
+               written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
+               if (written != 0) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_BOTH(finfo2,pinfo2);
+               COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+               finfo1 = finfo2;
+       }
+
+       /* sleep */
+       msleep(5 * msec);
+
+       GET_INFO_BOTH(finfo3,pinfo3);
+       COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+
+       /*
+        * the close doesn't update the write time
+        */
+       torture_comment(tctx, "Close the file handle\n");
+       smbcli_close(cli->tree, fnum1);
+       fnum1 = -1;
+
+       GET_INFO_PATH(pinfo4);
+       COMPARE_WRITE_TIME_EQUAL(pinfo4, pinfo3);
+
+       if (pinfo4.basic_info.out.write_time == pinfo3.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
+       }
+
+ done:
+       if (fnum1 != -1)
+               smbcli_close(cli->tree, fnum1);
+       smbcli_unlink(cli->tree, fname);
+       smbcli_deltree(cli->tree, BASEDIR);
+
+       return ret;
+}
+
+static bool test_delayed_write_update3b(struct torture_context *tctx,
+                                       struct smbcli_state *cli,
+                                       struct smbcli_state *cli2)
+{
+       union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
+       union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
+       const char *fname = BASEDIR "\\torture_file3b.txt";
+       int fnum1 = -1;
+       bool ret = true;
+       ssize_t written;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update3b\n");
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
+
+       torture_comment(tctx, "Open the file handle\n");
+       fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum1 == -1) {
+               ret = false;
+               torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+               goto done;
+       }
+
+       finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo0.basic_info.in.file.fnum = fnum1;
+       finfo1 = finfo0;
+       finfo2 = finfo0;
+       finfo3 = finfo0;
+       finfo4 = finfo0;
+       pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       pinfo0.basic_info.in.file.path = fname;
+       pinfo1 = pinfo0;
+       pinfo2 = pinfo0;
+       pinfo3 = pinfo0;
+       pinfo4 = pinfo0;
+       pinfo5 = pinfo0;
+
+       /* get the initial times */
+       GET_INFO_BOTH(finfo0,pinfo0);
+
+       /*
+        * sleep some time, to demonstrate the handling of write times
+        * doesn't depend on the time since the open
+        */
+       msleep(5 * msec);
+
+       /* get the initial times */
+       GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+       /*
+        * make sure the write time is updated 2 seconds later
+        * calcuated from the first write
+        * (but expect upto 5 seconds extra time for a busy server)
+        */
+       start = timeval_current();
+       end = timeval_add(&start, 7 * sec, 0);
+       while (!timeval_expired(&end)) {
+               /* do a write */
+               torture_comment(tctx, "Do a write on the file handle\n");
+               written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+               if (written != 1) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_FILE(finfo1);
+
+               if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                               "(1sec == %.2f) (wrong!)\n",
+                                               diff, sec);
+                               ret = false;
+                               break;
+                       }
+
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (correct)\n",
+                                       diff, sec);
+                       break;
+               }
+               msleep(0.5 * msec);
+       }
+
+       GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
+
+       /* sure any further write doesn't update the write time */
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
+               /* do a write */
+               torture_comment(tctx, "Do a write on the file handle\n");
+               written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+               if (written != 1) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_BOTH(finfo2,pinfo2);
+
+               if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
+                       ret = false;
+                       break;
+               }
+               msleep(2 * msec);
+       }
+
+       GET_INFO_BOTH(finfo2,pinfo2);
+       COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+       if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write_time (correct)\n");
+       }
+
+       /* sleep */
+       msleep(5 * msec);
+
+       GET_INFO_BOTH(finfo3,pinfo3);
+       COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+
+       /*
+        * the close updates the write time to the time of the close
+        * and not to the time of the last write!
+        */
+       torture_comment(tctx, "Close the file handle\n");
+       smbcli_close(cli->tree, fnum1);
+       fnum1 = -1;
 
-#define COMPARE_BOTH_TIMES_EQUAL(given,correct) do { \
-       COMPARE_ACCESS_TIME_EQUAL(given,correct); \
-       COMPARE_WRITE_TIME_EQUAL(given,correct); \
-} while (0)
-#define COMPARE_BOTH_TIMES_GEATER(given,correct) do { \
-       COMPARE_ACCESS_TIME_GREATER(given,correct); \
-       COMPARE_WRITE_TIME_GREATER(given,correct); \
-} while (0)
-#define COMPARE_BOTH_TIMES_LESS(given,correct) do { \
-       COMPARE_ACCESS_TIME_LESS(given,correct); \
-       COMPARE_WRITE_TIME_LESS(given,correct); \
-} while (0)
+       GET_INFO_PATH(pinfo4);
+       COMPARE_WRITE_TIME_GREATER(pinfo4, pinfo3);
 
-#define GET_INFO_FILE(finfo) do { \
-       NTSTATUS _status; \
-       _status = smb_raw_fileinfo(cli->tree, tctx, &finfo); \
-       if (!NT_STATUS_IS_OK(_status)) { \
-               ret = false; \
-               torture_result(tctx, TORTURE_FAIL, __location__": fileinfo failed: %s", \
-                              nt_errstr(_status)); \
-               goto done; \
-       } \
-       torture_comment(tctx, "fileinfo: Access(%s) Write(%s)\n", \
-                       nt_time_string(tctx, finfo.basic_info.out.access_time), \
-                       nt_time_string(tctx, finfo.basic_info.out.write_time)); \
-} while (0)
-#define GET_INFO_PATH(pinfo) do { \
-       NTSTATUS _status; \
-       _status = smb_raw_pathinfo(cli2->tree, tctx, &pinfo); \
-       if (!NT_STATUS_IS_OK(_status)) { \
-               torture_result(tctx, TORTURE_FAIL, __location__": pathinfo failed: %s", \
-                              nt_errstr(_status)); \
-               ret = false; \
-               goto done; \
-       } \
-       torture_comment(tctx, "pathinfo: Access(%s) Write(%s)\n", \
-                       nt_time_string(tctx, pinfo.basic_info.out.access_time), \
-                       nt_time_string(tctx, pinfo.basic_info.out.write_time)); \
-} while (0)
-#define GET_INFO_BOTH(finfo,pinfo) do { \
-       GET_INFO_FILE(finfo); \
-       GET_INFO_PATH(pinfo); \
-       COMPARE_BOTH_TIMES_EQUAL(finfo,pinfo); \
-} while (0)
+       if (pinfo4.basic_info.out.write_time > pinfo3.basic_info.out.write_time) {
+               torture_comment(tctx, "Server updated the write_time on close (correct)\n");
+       }
 
-#define SET_INFO_FILE_EX(finfo, wrtime, tree, tfnum) do { \
-       NTSTATUS _status; \
-       union smb_setfileinfo sfinfo; \
-       sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFO; \
-       sfinfo.basic_info.in.file.fnum = tfnum; \
-       sfinfo.basic_info.in.create_time = 0; \
-       sfinfo.basic_info.in.access_time = 0; \
-       unix_to_nt_time(&sfinfo.basic_info.in.write_time, (wrtime)); \
-       sfinfo.basic_info.in.change_time = 0; \
-       sfinfo.basic_info.in.attrib = finfo1.basic_info.out.attrib; \
-       _status = smb_raw_setfileinfo(tree, &sfinfo); \
-       if (!NT_STATUS_IS_OK(_status)) { \
-               torture_result(tctx, TORTURE_FAIL, __location__": setfileinfo failed: %s", \
-                              nt_errstr(_status)); \
-               ret = false; \
-               goto done; \
-       } \
-} while (0)
-#define SET_INFO_FILE(finfo, wrtime) \
-       SET_INFO_FILE_EX(finfo, wrtime, cli->tree, fnum1)
+ done:
+       if (fnum1 != -1)
+               smbcli_close(cli->tree, fnum1);
+       smbcli_unlink(cli->tree, fname);
+       smbcli_deltree(cli->tree, BASEDIR);
 
-static bool test_delayed_write_update3(struct torture_context *tctx,
-                                      struct smbcli_state *cli,
-                                      struct smbcli_state *cli2)
+       return ret;
+}
+
+static bool test_delayed_write_update3c(struct torture_context *tctx,
+                                       struct smbcli_state *cli,
+                                       struct smbcli_state *cli2)
 {
        union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
        union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
-       const char *fname = BASEDIR "\\torture_file.txt";
+       const char *fname = BASEDIR "\\torture_file3c.txt";
        int fnum1 = -1;
        bool ret = true;
        ssize_t written;
-       time_t t;
+       int i;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update3c\n");
 
        if (!torture_setup_dir(cli, BASEDIR)) {
                return false;
@@ -756,12 +2029,38 @@ static bool test_delayed_write_update3(struct torture_context *tctx,
        GET_INFO_BOTH(finfo0,pinfo0);
 
        /*
-        * make sure the write time is updated 2 seconds later
-        * calcuated from the first write
-        * (but expect upto 5 seconds extra time for a busy server)
+        * sleep some time, to demonstrate the handling of write times
+        * doesn't depend on the time since the open
+        */
+       msleep(5 * msec);
+
+       /* get the initial times */
+       GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+       /*
+        * demonstrate that a truncate write always
+        * updates the write time immediately
         */
-       t = time(NULL);
-       while (time(NULL) < t+7) {
+       for (i=0; i < 3; i++) {
+               msleep(1 * msec);
+               /* do a write */
+               torture_comment(tctx, "Do a truncate SMBwrite [%d] on the file handle\n", i);
+               written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
+               if (written != 0) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_BOTH(finfo2,pinfo2);
+               COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+               finfo1 = finfo2;
+       }
+
+       start = timeval_current();
+       end = timeval_add(&start, 7 * sec, 0);
+       while (!timeval_expired(&end)) {
                /* do a write */
                torture_comment(tctx, "Do a write on the file handle\n");
                written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
@@ -771,29 +2070,62 @@ static bool test_delayed_write_update3(struct torture_context *tctx,
                        goto done;
                }
                /* get the times after the write */
-               GET_INFO_FILE(finfo1);
-
-               if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
-                       int diff = time(NULL) - t;
-                       if (diff < 2) {
-                               torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                                               diff);
-                               ret = false;
-                               break;
-                       }
+               GET_INFO_FILE(finfo2);
 
-                       torture_comment(tctx, "Server updated write_time after %d seconds (correct)\n",
-                                       diff);
+               if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
+                       ret = false;
                        break;
                }
-               msleep(500);
+               msleep(2 * msec);
+       }
+
+       GET_INFO_BOTH(finfo2,pinfo2);
+       COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
+       if (finfo2.basic_info.out.write_time == finfo1.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write_time (correct)\n");
        }
 
+       /* sleep */
+       msleep(5 * msec);
+
+       /* get the initial times */
        GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_EQUAL(finfo1, finfo2);
+
+       /*
+        * demonstrate that a truncate write always
+        * updates the write time immediately
+        */
+       for (i=0; i < 3; i++) {
+               msleep(1 * msec);
+               /* do a write */
+               torture_comment(tctx, "Do a truncate write [%d] on the file handle\n", i);
+               written = smbcli_smbwrite(cli->tree, fnum1, "x", 512, 0);
+               if (written != 0) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 0", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_BOTH(finfo2,pinfo2);
+               COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+               finfo1 = finfo2;
+       }
+
+       /* sleep */
+       msleep(5 * msec);
+
+       GET_INFO_BOTH(finfo2,pinfo2);
+       COMPARE_WRITE_TIME_EQUAL(finfo2, finfo1);
 
        /* sure any further write doesn't update the write time */
-       t = time(NULL);
-       while (time(NULL) < t+15) {
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
                /* do a write */
                torture_comment(tctx, "Do a write on the file handle\n");
                written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
@@ -806,12 +2138,14 @@ static bool test_delayed_write_update3(struct torture_context *tctx,
                GET_INFO_BOTH(finfo2,pinfo2);
 
                if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
-                       torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                              (int)(time(NULL) - t));
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
                        ret = false;
                        break;
                }
-               msleep(2000);
+               msleep(2 * msec);
        }
 
        GET_INFO_BOTH(finfo2,pinfo2);
@@ -821,7 +2155,7 @@ static bool test_delayed_write_update3(struct torture_context *tctx,
        }
 
        /* sleep */
-       msleep(5000);
+       msleep(5 * msec);
 
        GET_INFO_BOTH(finfo3,pinfo3);
        COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
@@ -856,11 +2190,18 @@ static bool test_delayed_write_update4(struct torture_context *tctx,
 {
        union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4;
        union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5;
-       const char *fname = BASEDIR "\\torture_file.txt";
+       const char *fname = BASEDIR "\\torture_file4.txt";
        int fnum1 = -1;
        bool ret = true;
        ssize_t written;
-       time_t t;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update4\n");
 
        if (!torture_setup_dir(cli, BASEDIR)) {
                return false;
@@ -892,7 +2233,7 @@ static bool test_delayed_write_update4(struct torture_context *tctx,
        GET_INFO_BOTH(finfo0,pinfo0);
 
        /* sleep a bit */
-       msleep(5000);
+       msleep(5 * msec);
 
        /* do a write */
        torture_comment(tctx, "Do a write on the file handle\n");
@@ -911,32 +2252,37 @@ static bool test_delayed_write_update4(struct torture_context *tctx,
         * calcuated from the first write
         * (but expect upto 3 seconds extra time for a busy server)
         */
-       t = time(NULL);
-       while (time(NULL) < t+5) {
+       start = timeval_current();
+       end = timeval_add(&start, 5 * sec, 0);
+       while (!timeval_expired(&end)) {
                /* get the times after the first write */
                GET_INFO_FILE(finfo1);
 
                if (finfo1.basic_info.out.write_time > finfo0.basic_info.out.write_time) {
-                       int diff = time(NULL) - t;
-                       if (diff < 2) {
-                               torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                                               diff);
+                       double diff = timeval_elapsed(&start);
+                       if (diff < (2 * sec * 0.75)) { /* 0.75 to cope with vmware timing */
+                               torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                               "(1sec == %.2f) (wrong!)\n",
+                                               diff, sec);
                                ret = false;
                                break;
                        }
 
-                       torture_comment(tctx, "Server updated write_time after %d seconds (correct)\n",
-                                       diff);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (correct)\n",
+                                       diff, sec);
                        break;
                }
-               msleep(500);
+               msleep(0.5 * msec);
        }
 
        GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_GREATER(pinfo1, pinfo0);
 
        /* sure any further write doesn't update the write time */
-       t = time(NULL);
-       while (time(NULL) < t+15) {
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
                /* do a write */
                torture_comment(tctx, "Do a write on the file handle\n");
                written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
@@ -949,12 +2295,14 @@ static bool test_delayed_write_update4(struct torture_context *tctx,
                GET_INFO_BOTH(finfo2,pinfo2);
 
                if (finfo2.basic_info.out.write_time > finfo1.basic_info.out.write_time) {
-                       torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                              (int)(time(NULL) - t));
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
                        ret = false;
                        break;
                }
-               msleep(2000);
+               msleep(2 * msec);
        }
 
        GET_INFO_BOTH(finfo2,pinfo2);
@@ -964,7 +2312,7 @@ static bool test_delayed_write_update4(struct torture_context *tctx,
        }
 
        /* sleep */
-       msleep(5000);
+       msleep(5 * msec);
 
        GET_INFO_BOTH(finfo3,pinfo3);
        COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
@@ -999,11 +2347,18 @@ static bool test_delayed_write_update5(struct torture_context *tctx,
 {
        union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
        union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
-       const char *fname = BASEDIR "\\torture_file.txt";
+       const char *fname = BASEDIR "\\torture_file5.txt";
        int fnum1 = -1;
        bool ret = true;
        ssize_t written;
-       time_t t;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update5\n");
 
        if (!torture_setup_dir(cli, BASEDIR)) {
                return false;
@@ -1059,30 +2414,34 @@ static bool test_delayed_write_update5(struct torture_context *tctx,
        COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
 
        /* make sure the 2 second delay from the first write are canceled */
-       t = time(NULL);
-       while (time(NULL) < t+15) {
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
 
                /* get the times after the first write */
                GET_INFO_BOTH(finfo3,pinfo3);
 
                if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
-                       torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                              (int)(time(NULL) - t));
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
                        ret = false;
                        break;
                }
-               msleep(2000);
+               msleep(2 * msec);
        }
 
        GET_INFO_BOTH(finfo3,pinfo3);
        COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
-       if (finfo3.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
+       if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
                torture_comment(tctx, "Server did not update write_time (correct)\n");
        }
 
        /* sure any further write doesn't update the write time */
-       t = time(NULL);
-       while (time(NULL) < t+15) {
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
                /* do a write */
                torture_comment(tctx, "Do a write on the file handle\n");
                written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
@@ -1095,12 +2454,172 @@ static bool test_delayed_write_update5(struct torture_context *tctx,
                GET_INFO_BOTH(finfo4,pinfo4);
 
                if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
-                       torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                              (int)(time(NULL) - t));
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
+                       ret = false;
+                       break;
+               }
+               msleep(2 * msec);
+       }
+
+       GET_INFO_BOTH(finfo4,pinfo4);
+       COMPARE_WRITE_TIME_EQUAL(finfo4, finfo3);
+       if (finfo4.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write_time (correct)\n");
+       }
+
+       /* sleep */
+       msleep(5 * msec);
+
+       GET_INFO_BOTH(finfo5,pinfo5);
+       COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
+
+       /*
+        * the close doesn't update the write time
+        */
+       torture_comment(tctx, "Close the file handle\n");
+       smbcli_close(cli->tree, fnum1);
+       fnum1 = -1;
+
+       GET_INFO_PATH(pinfo6);
+       COMPARE_WRITE_TIME_EQUAL(pinfo6, pinfo5);
+
+       if (pinfo6.basic_info.out.write_time == pinfo5.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update the write_time on close (correct)\n");
+       }
+
+ done:
+       if (fnum1 != -1)
+               smbcli_close(cli->tree, fnum1);
+       smbcli_unlink(cli->tree, fname);
+       smbcli_deltree(cli->tree, BASEDIR);
+
+       return ret;
+}
+
+static bool test_delayed_write_update5b(struct torture_context *tctx,
+                                       struct smbcli_state *cli,
+                                       struct smbcli_state *cli2)
+{
+       union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
+       union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6;
+       const char *fname = BASEDIR "\\torture_fileb.txt";
+       int fnum1 = -1;
+       bool ret = true;
+       ssize_t written;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
+
+       torture_comment(tctx, "\nRunning test_delayed_write_update5b\n");
+
+       if (!torture_setup_dir(cli, BASEDIR)) {
+               return false;
+       }
+
+       torture_comment(tctx, "Open the file handle\n");
+       fnum1 = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT, DENY_NONE);
+       if (fnum1 == -1) {
+               ret = false;
+               torture_result(tctx, TORTURE_FAIL, __location__": unable to open %s", fname);
+               goto done;
+       }
+
+       finfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       finfo0.basic_info.in.file.fnum = fnum1;
+       finfo1 = finfo0;
+       finfo2 = finfo0;
+       finfo3 = finfo0;
+       finfo4 = finfo0;
+       finfo5 = finfo0;
+       pinfo0.basic_info.level = RAW_FILEINFO_BASIC_INFO;
+       pinfo0.basic_info.in.file.path = fname;
+       pinfo1 = pinfo0;
+       pinfo2 = pinfo0;
+       pinfo3 = pinfo0;
+       pinfo4 = pinfo0;
+       pinfo5 = pinfo0;
+       pinfo6 = pinfo0;
+
+       /* get the initial times */
+       GET_INFO_BOTH(finfo0,pinfo0);
+
+       /* do a write */
+       torture_comment(tctx, "Do a write on the file handle\n");
+       written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
+       if (written != 1) {
+               torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+               ret = false;
+               goto done;
+       }
+
+       GET_INFO_BOTH(finfo1,pinfo1);
+       COMPARE_WRITE_TIME_EQUAL(finfo1, finfo0);
+
+       torture_comment(tctx, "Set write time in the future on the file handle\n");
+       SET_INFO_FILE(finfo0, time(NULL) + 86400);
+       GET_INFO_BOTH(finfo2,pinfo2);
+       COMPARE_WRITE_TIME_GREATER(finfo2, finfo1);
+
+       torture_comment(tctx, "Set write time in the past on the file handle\n");
+       SET_INFO_FILE(finfo0, time(NULL) - 86400);
+       GET_INFO_BOTH(finfo2,pinfo2);
+       COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
+
+       /* make sure the 2 second delay from the first write are canceled */
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
+
+               /* get the times after the first write */
+               GET_INFO_BOTH(finfo3,pinfo3);
+
+               if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
+                       ret = false;
+                       break;
+               }
+               msleep(2 * msec);
+       }
+
+       GET_INFO_BOTH(finfo3,pinfo3);
+       COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
+       if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
+               torture_comment(tctx, "Server did not update write_time (correct)\n");
+       }
+
+       /* sure any further write (truncates) update the write time */
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
+               /* do a write */
+               torture_comment(tctx, "Do a truncate write on the file handle\n");
+               written = smbcli_smbwrite(cli->tree, fnum1, "x", 1024, 0);
+               if (written != 0) {
+                       torture_result(tctx, TORTURE_FAIL, __location__": written gave %d - should have been 1", (int)written);
+                       ret = false;
+                       goto done;
+               }
+               /* get the times after the write */
+               GET_INFO_BOTH(finfo4,pinfo4);
+
+               if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
                        ret = false;
                        break;
                }
-               msleep(2000);
+               msleep(2 * msec);
        }
 
        GET_INFO_BOTH(finfo4,pinfo4);
@@ -1110,7 +2629,7 @@ static bool test_delayed_write_update5(struct torture_context *tctx,
        }
 
        /* sleep */
-       msleep(5000);
+       msleep(5 * msec);
 
        GET_INFO_BOTH(finfo5,pinfo5);
        COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
@@ -1144,14 +2663,21 @@ static bool test_delayed_write_update6(struct torture_context *tctx,
 {
        union smb_fileinfo finfo0, finfo1, finfo2, finfo3, finfo4, finfo5;
        union smb_fileinfo pinfo0, pinfo1, pinfo2, pinfo3, pinfo4, pinfo5, pinfo6, pinfo7;
-       const char *fname = BASEDIR "\\torture_file.txt";
+       const char *fname = BASEDIR "\\torture_file6.txt";
        int fnum1 = -1;
        int fnum2 = -1;
        bool ret = true;
        ssize_t written;
-       time_t t;
+       struct timeval start;
+       struct timeval end;
+       int used_delay = torture_setting_int(tctx, "writetimeupdatedelay", 2000000);
+       int normal_delay = 2000000;
+       double sec = ((double)used_delay) / ((double)normal_delay);
+       int msec = 1000 * sec;
        bool first = true;
 
+       torture_comment(tctx, "\nRunning test_delayed_write_update6\n");
+
        if (!torture_setup_dir(cli, BASEDIR)) {
                return false;
        }
@@ -1217,30 +2743,34 @@ again:
        COMPARE_WRITE_TIME_LESS(finfo2, finfo1);
 
        /* make sure the 2 second delay from the first write are canceled */
-       t = time(NULL);
-       while (time(NULL) < t+15) {
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
 
                /* get the times after the first write */
                GET_INFO_BOTH(finfo3,pinfo3);
 
                if (finfo3.basic_info.out.write_time > finfo2.basic_info.out.write_time) {
-                       torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                              (int)(time(NULL) - t));
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
                        ret = false;
                        break;
                }
-               msleep(2000);
+               msleep(2 * msec);
        }
 
        GET_INFO_BOTH(finfo3,pinfo3);
        COMPARE_WRITE_TIME_EQUAL(finfo3, finfo2);
-       if (finfo3.basic_info.out.write_time == finfo3.basic_info.out.write_time) {
+       if (finfo3.basic_info.out.write_time == finfo2.basic_info.out.write_time) {
                torture_comment(tctx, "Server did not update write_time (correct)\n");
        }
 
        /* sure any further write doesn't update the write time */
-       t = time(NULL);
-       while (time(NULL) < t+15) {
+       start = timeval_current();
+       end = timeval_add(&start, 15 * sec, 0);
+       while (!timeval_expired(&end)) {
                /* do a write */
                torture_comment(tctx, "Do a write on the file handle\n");
                written = smbcli_write(cli->tree, fnum1, 0, "x", 0, 1);
@@ -1253,12 +2783,14 @@ again:
                GET_INFO_BOTH(finfo4,pinfo4);
 
                if (finfo4.basic_info.out.write_time > finfo3.basic_info.out.write_time) {
-                       torture_comment(tctx, "Server updated write_time after %d seconds (wrong!)\n",
-                              (int)(time(NULL) - t));
+                       double diff = timeval_elapsed(&start);
+                       torture_comment(tctx, "Server updated write_time after %.2f seconds "
+                                       "(1sec == %.2f) (wrong!)\n",
+                                       diff, sec);
                        ret = false;
                        break;
                }
-               msleep(2000);
+               msleep(2 * msec);
        }
 
        GET_INFO_BOTH(finfo4,pinfo4);
@@ -1268,7 +2800,7 @@ again:
        }
 
        /* sleep */
-       msleep(5000);
+       msleep(5 * msec);
 
        GET_INFO_BOTH(finfo5,pinfo5);
        COMPARE_WRITE_TIME_EQUAL(finfo5, finfo4);
@@ -1330,10 +2862,18 @@ struct torture_suite *torture_delay_write(void)
 
        torture_suite_add_2smb_test(suite, "finfo update on close", test_finfo_after_write);
        torture_suite_add_1smb_test(suite, "delayed update of write time", test_delayed_write_update);
+       torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate ", test_delayed_write_update1);
+       torture_suite_add_1smb_test(suite, "update of write time and SMBwrite truncate expand", test_delayed_write_update1a);
+       torture_suite_add_1smb_test(suite, "update of write time using SET_END_OF_FILE", test_delayed_write_update1b);
+       torture_suite_add_1smb_test(suite, "update of write time using SET_ALLOCATION_SIZE", test_delayed_write_update1c);
        torture_suite_add_2smb_test(suite, "delayed update of write time using 2 connections", test_delayed_write_update2);
        torture_suite_add_2smb_test(suite, "delayed update of write time 3", test_delayed_write_update3);
+       torture_suite_add_2smb_test(suite, "delayed update of write time 3a", test_delayed_write_update3a);
+       torture_suite_add_2smb_test(suite, "delayed update of write time 3b", test_delayed_write_update3b);
+       torture_suite_add_2smb_test(suite, "delayed update of write time 3c", test_delayed_write_update3c);
        torture_suite_add_2smb_test(suite, "delayed update of write time 4", test_delayed_write_update4);
        torture_suite_add_2smb_test(suite, "delayed update of write time 5", test_delayed_write_update5);
+       torture_suite_add_2smb_test(suite, "delayed update of write time 5b", test_delayed_write_update5b);
        torture_suite_add_2smb_test(suite, "delayed update of write time 6", test_delayed_write_update6);
 
        return suite;